فهرست منبع

Merge branch 'master' of http://git.fwt.com/Hotline/hotline

TANG JIANG 2 سال پیش
والد
کامیت
b34dc889a5

+ 2 - 0
src/Hotline.Api/Controllers/OrderController.cs

@@ -125,6 +125,8 @@ public class OrderController : BaseController
             .Includes(d => d.OrderComplain)
             .Includes(d => d.OrderReport)
             .FirstAsync(d => d.Id == id);
+        if (order == null)
+            return null;
         if (!string.IsNullOrEmpty(order?.WorkflowId))
         {
             order.Workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withSupplements: true, withAssigns: true, cancellationToken: HttpContext.RequestAborted);

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

@@ -50,6 +50,7 @@ namespace Hotline.Application.Mappers
             config.ForType<WorkflowStep, WorkflowTrace>()
                 .Ignore(d => d.Id)
                 .Ignore(d=>d.ParentId)
+                .Ignore(d=>d.Status)
                 .Map(d => d.StepId, s => s.Id);
 
             config.ForType<WorkflowSupplement, WorkflowSupplementDto>()

+ 9 - 74
src/Hotline.Share/Dtos/FlowEngine/StepBasicDto.cs

@@ -4,8 +4,6 @@ namespace Hotline.Share.Dtos.FlowEngine
 {
     public class StepBasicDto
     {
-        public string WorkflowId { get; set; }
-
         public string Name { get; set; }
 
         /// <summary>
@@ -20,6 +18,11 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// </summary>
         public EHandlerType HandlerType { get; set; }
 
+        /// <summary>
+        /// 只允许该角色下本部门人办理,否则该角色下所有人均可办理(办理者类型为角色时此字段有值)
+        /// </summary>
+        public bool? OnlySelfOrg { get; set; }
+
         /// <summary>
         /// 办理者分类(或是直接保存办理者)
         /// <example>
@@ -33,82 +36,14 @@ 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其中一个, 如果不是会签则只有一个)
+        /// 发起会签节点code(不支持发起会签节点无此字段)
         /// </summary>
-        public string? NextMainHandler { get; set; }
+        public string? CountersignStartCode { get; set; }
 
         /// <summary>
-        /// 下一节点code
+        /// 会签汇总节点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
+        public string? CountersignEndCode { get; set; }
     }
 }

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

@@ -8,6 +8,8 @@ namespace Hotline.Share.Dtos.FlowEngine
     {
         public string Id { get; set; }
 
+        public string DefinitionId { get; set; }
+
         public string Title { get; set; }
 
         /// <summary>
@@ -21,7 +23,7 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// 到期时间
         /// </summary>
         public DateTime ExpiredTime { get; set; }
-        
+
         public DateTime? CompleteTime { get; set; }
 
         /// <summary>
@@ -33,7 +35,7 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// 到达当前节点时间(stepBox创建时间)
         /// </summary>
         public DateTime? CurrentStepTime { get; set; }
-        
+
         public EWorkflowStatus Status { get; set; }
         public string StatusText => Status.ToString();
 
@@ -72,23 +74,14 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// <summary>
         /// 主节点,依据流转进度动态生成
         /// </summary>
-        public List<StepBoxDto> StepBoxes { get; set; }
-        
+        public List<WorkflowStepDto> StepBoxes { get; set; }
+
         public List<WorkflowTraceDto> Traces { get; set; }
 
         public List<WorkflowSupplementDto> Supplements { get; set; }
 
     }
 
-    public class StepBoxDto
-    {
-        public DateTime? StartTime { get; set; }
-
-        public DateTime? EndTime { get; set; }
-
-        public List<StepBasicDto> Steps { get; set; }
-    }
-
     public class WorkflowSupplementDto
     {
         /// <summary>

+ 119 - 0
src/Hotline.Share/Dtos/FlowEngine/WorkflowStepDto.cs

@@ -0,0 +1,119 @@
+using Hotline.Share.Enums.FlowEngine;
+
+namespace Hotline.Share.Dtos.FlowEngine;
+
+public class WorkflowStepDto
+{
+    public string Id { get; set; }
+
+    public DateTime CreationTime { get; set; }
+
+    public string WorkflowId { get; set; }
+
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 模板内唯一
+    /// </summary>
+    public string Code { get; set; }
+
+    public EStepType StepType { get; init; }
+
+    /// <summary>
+    /// 办理者类型
+    /// </summary>
+    public EHandlerType HandlerType { get; set; }
+
+    /// <summary>
+    /// 办理者分类(或是直接保存办理者)
+    /// <example>
+    /// 根据类型可能为:roles, orgLevels, orgTypes, orgCodes, userIds
+    /// </example>
+    /// </summary>
+    public List<IdName> HandlerClassifies { get; set; } = new();
+
+    /// <summary>
+    /// 会签模式
+    /// </summary>
+    public ECountersignMode CountersignMode { get; set; }
+
+    public EWorkflowStepStatus Status { 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
+
+    public List<WorkflowStepDto> Steps { get; set; }
+}

+ 2 - 6
src/Hotline.Share/Dtos/FlowEngine/WorkflowTraceDto.cs

@@ -4,14 +4,10 @@ using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.FlowEngine;
 
-public class WorkflowTraceDto : StepBasicDto
+public class WorkflowTraceDto : WorkflowStepDto
 {
     public string StepId { get; set; }
-
-    //public NextWorkflowDto NextWorkflowDto { get; set; }
-
-    //public bool IsBackward { get; set; }
-
+    
     /// <summary>
     /// 流转记录状态
     /// </summary>

+ 1 - 1
src/Hotline.Share/Enums/FlowEngine/EWorkflowStepStatus.cs

@@ -11,7 +11,7 @@ public enum EWorkflowStepStatus
     Created = 0,
 
     /// <summary>
-    /// 已指派(待受理)
+    /// 已指派(待受理/接办
     /// </summary>
     [Description("已指派")]
     Assigned = 1,

+ 35 - 35
src/Hotline/FlowEngine/Definitions/Step.cs

@@ -1,48 +1,48 @@
-using Hotline.FlowEngine.Workflows;
+//using Hotline.FlowEngine.Workflows;
 
-namespace Hotline.FlowEngine.Definitions;
+//namespace Hotline.FlowEngine.Definitions;
 
-public class Step : StepBasic
-{
-    public string Id { get; set; }
+//public class Step : StepBasic
+//{
+//    public string Id { get; set; }
 
-    public List<NextStep> NextSteps { get; set; }
+//    public List<NextStep> NextSteps { get; set; }
 
-    /// <summary>
-    /// 被指派处理对象(依据不同指派方式可能为:depCode或userId)
-    /// </summary>
-    public string HandlerId { get; set; }
+//    /// <summary>
+//    /// 被指派处理对象(依据不同指派方式可能为:depCode或userId)
+//    /// </summary>
+//    public string HandlerId { get; set; }
 
-    public DateTime? StartTime { get; set; } = DateTime.Now;
+//    public DateTime? StartTime { get; set; } = DateTime.Now;
 
-    public DateTime? EndTime { get; set; }
+//    public DateTime? EndTime { get; set; }
 
-    #region 审批参数
+//    #region 审批参数
 
-    /// <summary>
-    /// (下一节点处理人)根据审批者类型不同,此字段为不同内容
-    /// <example>
-    /// 部门等级/分类为:depCodes, 角色为:userIds
-    /// </example>
-    /// </summary>
-    public List<string> Handlers { get; set; }
+//    /// <summary>
+//    /// (下一节点处理人)根据审批者类型不同,此字段为不同内容
+//    /// <example>
+//    /// 部门等级/分类为:depCodes, 角色为:userIds
+//    /// </example>
+//    /// </summary>
+//    public List<string> Handlers { get; set; }
 
-    /// <summary>
-    /// 下一节点code
-    /// </summary>
-    public string NextStepCode { get; set; }
+//    /// <summary>
+//    /// 下一节点code
+//    /// </summary>
+//    public string NextStepCode { get; set; }
 
-    /// <summary>
-    /// 是否短信通知
-    /// </summary>
-    public bool AcceptSms { get; set; }
+//    /// <summary>
+//    /// 是否短信通知
+//    /// </summary>
+//    public bool AcceptSms { get; set; }
 
-    /// <summary>
-    /// 办理意见
-    /// </summary>
-    public string Opinion { get; set; }
+//    /// <summary>
+//    /// 办理意见
+//    /// </summary>
+//    public string Opinion { get; set; }
 
-    #endregion
+//    #endregion
 
-    public string PreviousId { get; set; }
-}
+//    public string PreviousId { get; set; }
+//}

+ 9 - 0
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -117,6 +117,15 @@ public class StepBasicEntity : CreationEntity
     [SugarColumn(IsNullable = true)]
     public string? AcceptUserName { get; set; }
 
+    /// <summary>
+    /// 接办人部门code
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public string? AcceptOrgCode { get; set; }
+
+    [SugarColumn(IsNullable = true)]
+    public string? AcceptOrgName { get; set; }
+
     /// <summary>
     /// 接办时间
     /// </summary>

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

@@ -148,19 +148,6 @@ public class Workflow : CreationEntity
     /// <summary>
     /// 检查会签是否结束
     /// </summary>
-    public void CompleteCountersign()
-    {
-        if (IsInCountersign())
-        {
-            var countersignStepBox = StepBoxes.First(d => d.Code == CurrentCountersignStepCode);
-            var isCountersignOver = countersignStepBox.Steps.All(d =>
-                d.Status is EWorkflowStepStatus.Completed &&
-                (!d.HasStartCountersign || d.IsCountersignComplete.GetValueOrDefault()));
-            if (isCountersignOver) //会签结束
-                CurrentCountersignStepCode = null;
-        }
-    }
-
     public bool CheckIfCountersignOver()
     {
         var countersignStepBox = StepBoxes.First(d => d.Code == CurrentCountersignStepCode);

+ 47 - 0
src/Hotline/FlowEngine/Workflows/WorkflowCountersign.cs

@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SqlSugar;
+using XF.Domain.Repository;
+
+namespace Hotline.FlowEngine.Workflows
+{
+    public class WorkflowCountersign : CreationEntity
+    {
+        public string WorkflowId { get; set; }
+
+        /// <summary>
+        /// 发起会签节点code
+        /// </summary>
+        public string StartStepCode { get; set; }
+
+        /// <summary>
+        /// 会签汇总节点code
+        /// </summary>
+        public string EndStepCode { get; set; }
+
+        /// <summary>
+        /// 会签结束时间
+        /// </summary>
+        public DateTime? CompleteTime { get; set; }
+
+        /// <summary>
+        /// 会签嵌套会签场景记录上级会签Id
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string? ParentId { get; set; }
+
+        /// <summary>
+        /// 该会签参与成员数量
+        /// </summary>
+        public int Members { get; set; }
+
+        /// <summary>
+        /// 会签是否完成(如有嵌套会签,下级所有会签都完成才可判定当前会签为完成)
+        /// </summary>
+        public bool IsCompleted() => CompleteTime.HasValue;
+    }
+
+}

+ 32 - 27
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -6,6 +6,7 @@ using Hotline.Share.Enums.FlowEngine;
 using Hotline.Users;
 using MapsterMapper;
 using MediatR;
+using Microsoft.Extensions.Logging;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
@@ -25,6 +26,7 @@ namespace Hotline.FlowEngine.Workflows
         private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
         private readonly IMediator _mediator;
+        private readonly ILogger<WorkflowDomainService> _logger;
 
         public WorkflowDomainService(
             IWorkflowRepository workflowRepository,
@@ -34,7 +36,8 @@ namespace Hotline.FlowEngine.Workflows
             IWorkflowAssignRepository workflowAssignRepository,
             ISessionContext sessionContext,
             IMapper mapper,
-            IMediator mediator)
+            IMediator mediator,
+            ILogger<WorkflowDomainService> logger)
         {
             _workflowRepository = workflowRepository;
             _workflowStepRepository = workflowStepRepository;
@@ -45,6 +48,7 @@ namespace Hotline.FlowEngine.Workflows
             _sessionContext = sessionContext;
             _mapper = mapper;
             _mediator = mediator;
+            _logger = logger;
         }
 
         public async Task<Workflow> CreateWorkflowAsync(Definition definition, string title, CancellationToken cancellationToken)
@@ -137,6 +141,7 @@ namespace Hotline.FlowEngine.Workflows
             {
                 var traces = await _workflowTraceRepository.Queryable()
                     .Where(d => d.WorkflowId == workflow.Id)
+                    .OrderBy(d => d.CreationTime)
                     .ToTreeAsync(d => d.Traces, d => d.ParentId, null);
                 workflow.Traces = traces;
             }
@@ -150,7 +155,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         public async Task AcceptAsync(Workflow workflow, string userId, string userName, string orgCode, string orgName, CancellationToken cancellationToken)
         {
-            if(!workflow.CanHandle(_sessionContext.RequiredUserId,_sessionContext.RequiredOrgCode)) return;
+            if (!workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode)) return;
             //工单完成以后查看的场景
             if (workflow.Status is not EWorkflowStatus.Runnable) return;
 
@@ -176,7 +181,7 @@ namespace Hotline.FlowEngine.Workflows
                 currentStepBox.Status = EWorkflowStepStatus.Accepted;
                 changedSteps.Add(currentStepBox);
             }
-            currentStep.Accept(userId, userName);
+            currentStep.Accept(userId, userName, _sessionContext.RequiredOrgCode, _sessionContext.OrgName);
 
             //接办时非会签并且有多个接办部门时需更新接办部门
             if (!workflow.IsInCountersign())
@@ -265,7 +270,7 @@ namespace Hotline.FlowEngine.Workflows
             }
 
             //检查是否流转到流程终点
-            if (nextStepBoxDefine.StepType is EStepType.End)
+            if (nextStepBoxDefine.StepType is EStepType.End && !workflow.IsInCountersign())
             {
                 workflow.Complete();
                 await _workflowRepository.UpdateAsync(workflow, cancellationToken);
@@ -357,26 +362,6 @@ namespace Hotline.FlowEngine.Workflows
             _mediator.Publish(new NextStepNotify(workflow, dto, isStartCountersign, isCountersignOver, flowAssignMode));
         }
 
-        /// <summary>
-        /// 更新下级汇总节点可办理状态
-        /// </summary>
-        /// <param name="nextStepBox"></param>
-        /// <param name="currentStep"></param>
-        /// <param name="cancellationToken"></param>
-        /// <returns></returns>
-        private async Task UpdateNextCountersignEndAssignedAsync(WorkflowStep nextStepBox, WorkflowStep currentStep, CancellationToken cancellationToken)
-        {
-            var countersignId = string.IsNullOrEmpty(currentStep.TopCountersignId)
-                ? currentStep.PrevCountersignId
-                : currentStep.TopCountersignId;
-
-            var nextStep = nextStepBox.Steps.First(d => d.PrevCountersignId == countersignId);
-            nextStep.SetAssigned();
-
-            await _workflowStepRepository.UpdateAsync(nextStep, cancellationToken);
-        }
-
-
         /// <summary>
         /// 退回(返回前一节点)
         /// </summary>
@@ -531,6 +516,25 @@ namespace Hotline.FlowEngine.Workflows
 
         #region private
 
+        /// <summary>
+        /// 更新下级汇总节点可办理状态
+        /// </summary>
+        /// <param name="nextStepBox"></param>
+        /// <param name="currentStep"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        private async Task UpdateNextCountersignEndAssignedAsync(WorkflowStep nextStepBox, WorkflowStep currentStep, CancellationToken cancellationToken)
+        {
+            var countersignId = string.IsNullOrEmpty(currentStep.TopCountersignId)
+                ? currentStep.PrevCountersignId
+                : currentStep.TopCountersignId;
+
+            var nextStep = nextStepBox.Steps.First(d => d.PrevCountersignId == countersignId);
+            nextStep.SetAssigned();
+
+            await _workflowStepRepository.UpdateAsync(nextStep, cancellationToken);
+        }
+
         /// <summary>
         /// 在stepCode对应的stepBox中找到开启会签流程的节点
         /// </summary>
@@ -595,8 +599,8 @@ namespace Hotline.FlowEngine.Workflows
             var trace = await GetWorkflowTraceAsync(workflow.Id, step.Id, cancellationToken);
             _mapper.Map(dto, trace);
             _mapper.Map(step, trace);
-            trace.ExpiredTime = workflow.ExpiredTime;
-            trace.TimeLimit = workflow.TimeLimit;
+            //trace.ExpiredTime = workflow.ExpiredTime;
+            //trace.TimeLimit = workflow.TimeLimit;
             await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
         }
 
@@ -709,7 +713,8 @@ namespace Hotline.FlowEngine.Workflows
             {
                 if (prevStep is null)
                 {
-                    //创建流程或特殊处理场景
+
+                    //开始流程或向后跳转场景
                     await CreateSubStepsAsync(stepBoxDefine, dto, stepBox, string.Empty, EWorkflowStepStatus.Assigned,
                         null, null, cancellationToken);
                 }

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

@@ -97,11 +97,13 @@ public class WorkflowStep : StepBasicEntity
     /// </summary>
     /// <param name="userId"></param>
     /// <param name="userName"></param>
-    public void Accept(string userId, string userName)
+    public void Accept(string userId, string userName, string orgCode, string orgName)
     {
         AcceptUserId = userId;
         AcceptUserName = userName;
         AcceptTime = DateTime.Now;
+        AcceptOrgCode = orgCode;
+        AcceptOrgName = orgName;
         Status = EWorkflowStepStatus.Accepted;
     }