Procházet zdrojové kódy

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

dss před 2 roky
rodič
revize
1ead588021

+ 12 - 7
src/Hotline.Api/Controllers/PbxController.cs

@@ -6,6 +6,7 @@ using Hotline.CallCenter.Devices;
 using Hotline.CallCenter.Ivrs;
 using Hotline.CallCenter.Manage;
 using Hotline.CallCenter.Tels;
+using Hotline.FlowEngine.Definitions;
 using Hotline.Permissions;
 using Hotline.Repository.SqlSugar.CallCenter;
 using Hotline.Settings;
@@ -47,6 +48,7 @@ namespace Hotline.Api.Controllers
         private readonly ITrunkIvrManagerRepository _trunkIvrManagerRepository;
         private readonly IIvrCategoryRepository _ivrCategoryRepository;
         private readonly IWorkflowApplication _workflowApplication;
+        private readonly IDefinitionDomainService _definitionDomainService;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
         public PbxController(
@@ -65,6 +67,7 @@ namespace Hotline.Api.Controllers
             ITrunkIvrManagerRepository trunkIvrManagerRepository,
             IIvrCategoryRepository ivrCategoryRepository,
             IWorkflowApplication workflowApplication,
+            IDefinitionDomainService definitionDomainService,
             ISystemSettingCacheManager systemSettingCacheManager)
         {
             _telRepository = telRepository;
@@ -82,6 +85,7 @@ namespace Hotline.Api.Controllers
             _trunkIvrManagerRepository = trunkIvrManagerRepository;
             _ivrCategoryRepository = ivrCategoryRepository;
             _workflowApplication = workflowApplication;
+            _definitionDomainService = definitionDomainService;
             _systemSettingCacheManager = systemSettingCacheManager;
         }
 
@@ -246,15 +250,16 @@ namespace Hotline.Api.Controllers
             }
             else
             {
-                telRest.WorkflowId = await _workflowApplication.StartWorkflowAsync(dto, HttpContext.RequestAborted);
+                var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
+                var definition = await _definitionDomainService.GetLastVersionDefinitionByModuleCodeAsync(
+                    WorkflowModuleConsts.TelRestApply, HttpContext.RequestAborted);
+                if (definition is null)
+                    throw UserFriendlyException.SameMessage("未配置流程模板");
+                startWorkflowDto.DefinitionCode = definition.Code;
+                startWorkflowDto.Title = dto.Reason;
+                telRest.WorkflowId = await _workflowApplication.StartWorkflowAsync(startWorkflowDto, HttpContext.RequestAborted);
             }
             await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
-
-            //string id = await _telDomainService.RestAsync(work, dto.Reason, isApply, HttpContext.RequestAborted);
-
-            //var startworkflow = _mapper.Map<StartWorkflowDto>(dto);
-            //if (isApply)
-            //    await _workflowApplication.StartWorkflowAsync(dto, HttpContext.RequestAborted);
         }
 
         /// <summary>

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

@@ -10,7 +10,6 @@ using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Requests;
 using Hotline.Users;
 using MapsterMapper;
-using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
 using XF.Domain.Authentications;
@@ -244,6 +243,15 @@ public class WorkflowController : BaseController
         return await _workflowApplication.GetNextStepOptionsAsync(workflow, HttpContext.RequestAborted);
     }
 
+    /// <summary>
+    /// 办理节点
+    /// </summary>
+    [HttpPost("next")]
+    public async Task NextAsync([FromBody]NextWorkflowDto dto)
+    {
+        await _workflowApplication.NextAsync(dto, HttpContext.RequestAborted);
+    }
+
     /// <summary>
     /// 跳转至任意节点
     /// </summary>

+ 6 - 6
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -88,7 +88,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var nextStepBoxDefine = _workflowDomainService.GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
         var isOutOfCallCenter =
             await CheckIfFlowOutOfCallCenterAsync(nextStepBoxDefine, dto.NextMainHandler, cancellationToken);
-        var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.Handlers.Count);
+        var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
         await _workflowDomainService.NextAsync(workflow, dto, nextStepBoxDefine, isOutOfCallCenter, isStartCountersign, cancellationToken);
 
         //更新接办部门(详情页面展示)
@@ -221,12 +221,12 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             switch (nextStepBoxDefine.HandlerType)
             {
                 case EHandlerType.Role:
-                    if (dto.Handlers.Any())
+                    if (dto.NextHandlers.Any())
                     {
                         //选了handler,handler为userId 
                         var users1 = await _userRepository.Queryable()
                             .Includes(d => d.Organization)
-                            .Where(d => dto.Handlers.Select(d => d.Id).Contains(d.Id))
+                            .Where(d => dto.NextHandlers.Select(d => d.Id).Contains(d.Id))
                             .ToListAsync();
                         assigns = users1.Select(d => WorkflowAssign.Create(workflow.Id, d.OrgCode, d.Organization.OrgName))
                             .ToList();
@@ -245,7 +245,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                         {
                             var accounts = await _accountRepository.Queryable()
                                 .Includes(d => d.User, d => d.Organization)
-                                .Where(d => dto.Handlers.Select(d => d.Id).Contains(d.Name))
+                                .Where(d => dto.NextHandlers.Select(d => d.Id).Contains(d.Name))
                                 .ToListAsync();
                             assigns = accounts.Select(d => d.User.Organization).Select(d =>
                                 WorkflowAssign.Create(workflow.Id, d.OrgCode, d.OrgName)).ToList();
@@ -257,14 +257,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 case EHandlerType.OrgLevel:
                 case EHandlerType.OrgType:
                 case EHandlerType.AssignOrg:
-                    assigns = dto.Handlers.Select(d => WorkflowAssign.Create(workflow.Id, d.Id, d.Name)).ToList();
+                    assigns = dto.NextHandlers.Select(d => WorkflowAssign.Create(workflow.Id, d.Id, d.Name)).ToList();
                     break;
 
                 case EHandlerType.AssignUser:
                     //指定人所属部门
                     var users = await _userRepository.Queryable()
                         .Includes(d => d.Organization)
-                        .Where(d => dto.Handlers.Select(d => d.Id).Contains(d.Id))
+                        .Where(d => dto.NextHandlers.Select(d => d.Id).Contains(d.Id))
                         .ToListAsync();
                     assigns = users.Select(d => WorkflowAssign.Create(workflow.Id, d.OrgCode, d.Organization.OrgName))
                         .ToList();

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

@@ -32,7 +32,7 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
         var workflow = notification.Workflow;
         var data = notification.Dto;
         var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
-            data.Handlers.Select(d => d.Id).ToList(), cancellationToken);
+            data.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
 
         switch (workflow.ModuleCode)
         {

+ 1 - 1
src/Hotline.Application/Handlers/FlowEngine/StartWorkflowHandler.cs

@@ -38,7 +38,7 @@ namespace Hotline.Application.Handlers.FlowEngine
             var workflow = notification.Workflow;
             var data = notification.Dto;
             var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
-                data.Handlers.Select(d => d.Id).ToList(), cancellationToken);
+                data.NextHandlers.Select(d => d.Id).ToList(), cancellationToken);
 
             switch (workflow.ModuleCode)
             {

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

@@ -1,5 +1,6 @@
 using Hotline.CallCenter.BlackLists;
 using Hotline.FlowEngine.Definitions;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Identity.Roles;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.FlowEngine;
@@ -39,7 +40,8 @@ namespace Hotline.Application.Mappers
             config.NewConfig<UpdateDefinitionDto, Definition>()
                 .Ignore(d => d.Id);
 
-
+            config.NewConfig<WorkflowStep, WorkflowStep>()
+                .Ignore(d => d.Id);
 
             #endregion
         }

+ 1 - 1
src/Hotline.Share/Dtos/CallCenter/TelRestDto.cs

@@ -2,7 +2,7 @@
 
 namespace Hotline.Share.Dtos.CallCenter
 {
-    public class StartRestDto: StartWorkflowDto
+    public class StartRestDto : BasicWorkflowDto
     {
         /// <summary>
         /// 小休原因

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs

@@ -16,7 +16,7 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// 部门等级/分类为:depCodes, 角色为:userIds
     /// </example>
     /// </summary>
-    public List<IdName> Handlers { get; set; }
+    public List<IdName> NextHandlers { get; set; }
 
     /// <summary>
     /// 是否短信通知

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/EndWorkflowDto.cs

@@ -10,5 +10,5 @@ public class EndWorkflowDto
     /// <summary>
     /// 附件
     /// </summary>
-    public List<string> Additions { get; set; }
+    public List<string> Additions { get; set; } = new();
 }

+ 2 - 0
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -70,6 +70,8 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? EmployeeStaffNo { get; set; }
 
+        public string WorkflowId { get; set; }
+
         /// <summary>
         /// 超期时间描述(需求:超期3天、0.5天后超期)
         /// </summary>

+ 0 - 50
src/Hotline.Share/Dtos/Workflow/WorkflowDefinitionDto.cs

@@ -1,50 +0,0 @@
-namespace Hotline.Share.Dtos.Workflow;
-
-public class WorkflowDefinitionDto
-{
-    public bool IsPreDefinition { get; set; }
-
-    /// <summary>
-    /// 模板编码
-    /// </summary>
-    public string Id { get; set; }
-
-    public int Version { get; set; }
-
-    public string Description { get; set; }
-
-    //public string DataType { get; set; }
-
-    //public WorkflowErrorHandling DefaultErrorBehavior { get; set; }
-
-    public TimeSpan? DefaultErrorRetryInterval { get; set; }
-
-    //public List<Step> Steps { get; set; } = new List<Step>();
-
-    /// <summary>
-    /// 业务模块
-    /// </summary>
-    public string Module { get; set; }
-
-    /// <summary>
-    /// 业务模块编码
-    /// </summary>
-    public string ModuleCode { get; set; }
-
-    /// <summary>
-    /// 模板名称
-    /// </summary>
-    public string Name { get; set; }
-
-    /// <summary>
-    /// 启用/禁用
-    /// </summary>
-    public bool Enable { get; set; }
-
-    public DateTime CreationTime { get; set; }
-
-    /// <summary>
-    /// 最近更新时间
-    /// </summary>
-    public DateTime LastModificationTime { get; }
-}

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

@@ -47,12 +47,13 @@ public class StepBasicEntity : CreationEntity
     /// </example>
     /// </summary>
     [SugarColumn(ColumnDataType = "varchar(2000)", IsJson = true)]
-    public List<IdName> NextHandlers { get; set; }
+    public List<IdName> NextHandlers { get; set; } = new();
 
     /// <summary>
     /// 下一节点主办,(NextHandlers其中一个, 如果不是会签则只有一个)
     /// </summary>
-    public string NextMainHandler { get; set; }
+    [SugarColumn(IsNullable = true)]
+    public string? NextMainHandler { get; set; }
 
     /// <summary>
     /// 下一节点code
@@ -74,7 +75,7 @@ public class StepBasicEntity : CreationEntity
     /// 附件
     /// </summary>
     [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
-    public List<string> Additions { get; set; }
+    public List<string> Additions { get; set; } = new();
 
     #endregion
 

+ 6 - 3
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -21,6 +21,7 @@ public class Workflow : CreationEntity
     [SugarColumn(IsNullable = true)]
     public string? ModuleCode { get; set; }
 
+    [SugarColumn(Length = 2000)]
     public string Title { get; set; }
 
     /// <summary>
@@ -35,16 +36,18 @@ public class Workflow : CreationEntity
     /// <summary>
     /// 当前节点名称(会签状态此字段保存最外层会签办理节点名称)
     /// </summary>
-    public string CurrentStepName { get; set; }
+    [SugarColumn(IsNullable = true)]
+    public string? CurrentStepName { get; set; }
 
     /// <summary>
     /// 到达当前节点时间(stepBox创建时间)
     /// </summary>
-    public DateTime CurrentStepTime { get; set; }
+    public DateTime? CurrentStepTime { get; set; }
 
     /// <summary>
     /// 当前会签办理节点code,嵌套会签为最外层会签办理节点code(不处于会签状态则无值)
     /// </summary>
+    [SugarColumn(IsNullable = true)]
     public string? CurrentCountersignStepCode { get; set; }
 
     /// <summary>
@@ -97,7 +100,7 @@ public class Workflow : CreationEntity
     [SugarColumn(IsIgnore = true)]
     public List<WorkflowTrace> Traces { get; set; } = new();
 
-    
+
     #region Mehod
 
     /// <summary>

+ 28 - 20
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -82,17 +82,21 @@ namespace Hotline.FlowEngine.Workflows
         {
             //var nextStepBoxDefine = GetStepBoxDefine(workflow.Definition, dto.NextStepCode);
 
-            var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.Handlers.Count);
+            var isStartCountersign = nextStepBoxDefine.IsStartCountersign(dto.NextHandlers.Count);
             //检查是否支持会签
             if (isStartCountersign && nextStepBoxDefine.CountersignMode == ECountersignMode.UnSupport)
                 throw new UserFriendlyException($"当前节点不支持会签, defineCode: {workflow.Definition.Code}", "当前节点不支持会签");
 
             //1. 如果不是按角色指派,handlers必填 2. 如果按角色指派,handlers可以不选
-            if (nextStepBoxDefine.HandlerType is not EHandlerType.Role && !dto.Handlers.Any())
+            if (nextStepBoxDefine.HandlerType is not EHandlerType.Role && !dto.NextHandlers.Any())
                 throw UserFriendlyException.SameMessage("未指派办理人");
 
             //第二节点的previousId is string.Empty
-            await CreateStepAsync(workflow, nextStepBoxDefine, dto, cancellationToken: cancellationToken);
+            var nextStepBox = await CreateStepAsync(workflow, nextStepBoxDefine, dto, cancellationToken: cancellationToken);
+
+            //更新当前节点名称、时间、会签节点code 等字段
+            workflow.SetWorkflowCurrentStepInfo(isStartCountersign, nextStepBox);
+            await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
             //publish
             _mediator.Publish(new StartWorkflowNotify(workflow, nextStepBoxDefine, dto, isStartCountersign), cancellationToken);
@@ -437,7 +441,7 @@ namespace Hotline.FlowEngine.Workflows
         {
             //更新当前节点名称、时间、会签节点code
             workflow.CloseCountersignStatus();
-            var isCountersign = dto.Handlers.Count > 1;
+            var isCountersign = dto.NextHandlers.Count > 1;
             workflow.SetWorkflowCurrentStepInfo(isCountersign, stepBox);
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
         }
@@ -636,7 +640,7 @@ namespace Hotline.FlowEngine.Workflows
             var stepBox = workflow.StepBoxes.FirstOrDefault(d => d.Code == stepBoxDefine.Code);
             if (stepBox == null)
             {
-                stepBox = CreateStepBox(stepBoxDefine, dto, prevStepBox?.Id ?? string.Empty);
+                stepBox = CreateStepBox(workflow.Id, stepBoxDefine, dto, prevStepBox?.Id ?? string.Empty);
                 await _workflowStepRepository.AddAsync(stepBox, cancellationToken);
             }
 
@@ -703,9 +707,9 @@ namespace Hotline.FlowEngine.Workflows
             }
             else
             {
-                if (!dto.Handlers.Any())
+                if (stepBoxDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
                     throw new UserFriendlyException("未指定节点处理者");
-                var subSteps = CreateSubSteps(stepBox, dto.Handlers, dto.NextMainHandler,
+                var subSteps = CreateSubSteps(stepBox, dto.NextHandlers, dto.NextMainHandler,
                     prevStepId, prevCountersignId, topCountersignId, stepStatus);
                 stepBox.Steps.AddRange(subSteps);
                 await _workflowStepRepository.AddRangeAsync(subSteps, cancellationToken);
@@ -759,10 +763,11 @@ namespace Hotline.FlowEngine.Workflows
             return new();
         }
 
-        private WorkflowStep CreateStepBox(StepDefine stepBasic, BasicWorkflowDto dto, string prevStepBoxId)
+        private WorkflowStep CreateStepBox(string workflowId, StepDefine stepBasic, BasicWorkflowDto dto, string prevStepBoxId)
         {
             var stepBox = _mapper.Map<WorkflowStep>(stepBasic);
             _mapper.Map(dto, stepBox);
+            stepBox.WorkflowId = workflowId;
             stepBox.PreviousId = prevStepBoxId;
             return stepBox;
         }
@@ -776,18 +781,21 @@ namespace Hotline.FlowEngine.Workflows
             string? topCountersignId,
             EWorkflowStepStatus stepStatus)
         {
-            return nextHandlers.Select(d =>
-              {
-                  var step = _mapper.Map<WorkflowStep>(stepBox);
-                  step.ParentId = stepBox.Id;
-                  step.HandlerId = d.Id;
-                  step.IsMain = d.Id == nextMainHandler;
-                  step.PreviousId = prevStepId;
-                  step.PrevCountersignId = prevCountersignId;
-                  step.TopCountersignId = topCountersignId;
-                  step.Status = stepStatus;
-                  return step;
-              }).ToList();
+            var steps = new List<WorkflowStep>();
+            foreach (var nextHandler in nextHandlers)
+            {
+                var step = _mapper.Map<WorkflowStep>(stepBox);
+                step.ParentId = stepBox.Id;
+                step.HandlerId = nextHandler.Id;
+                step.IsMain = nextHandler.Id == nextMainHandler;
+                step.PreviousId = prevStepId;
+                step.PrevCountersignId = prevCountersignId;
+                step.TopCountersignId = topCountersignId;
+                step.Status = stepStatus;
+                steps.Add(step);
+            }
+
+            return steps;
         }
 
         /// <summary>

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

@@ -11,7 +11,8 @@ public class WorkflowStep : StepBasicEntity
     /// <summary>
     /// 被指派办理对象(依据不同指派方式可能为:depCode或userId),该字段subStep才会存在,stepBox不存在
     /// </summary>
-    public string HandlerId { get; set; }
+    [SugarColumn(IsNullable = true)]
+    public string? HandlerId { get; set; }
 
     /// <summary>
     /// 前一级节点Id(stepBox此字段为上级stepBoxId,step为上级stepId),汇总节点无此字段(可能有多个上级来源)
@@ -32,7 +33,7 @@ public class WorkflowStep : StepBasicEntity
     public string? ParentId { get; set; }
 
     [SugarColumn(IsIgnore = true)]
-    public List<WorkflowStep> Steps { get; set; }
+    public List<WorkflowStep> Steps { get; set; } = new();
 
     #region 会签
 

+ 1 - 1
src/Hotline/Orders/IOrderDomainService.cs

@@ -22,6 +22,6 @@ namespace Hotline.Orders
         /// 工单办理(每个节点都会触发)
         /// </summary>
         Task OrderManageAsync(EOrderStatus status, FlowAssignMode assignMode, bool isCountersignEnd, bool isCountersignStart,
-            string workflowId, DateTime currentStepTime, string CurrentStepName, CancellationToken cancellationToken);
+            string workflowId, DateTime? currentStepTime, string? CurrentStepName, CancellationToken cancellationToken);
     }
 }

+ 1 - 1
src/Hotline/Orders/OrderDomainService.cs

@@ -55,7 +55,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     /// </summary>
     public async Task OrderManageAsync(EOrderStatus status, FlowAssignMode assignMode,
         bool isCountersignEnd, bool isCountersignStart,
-        string workflowId, DateTime currentStepTime, string CurrentStepName,
+        string workflowId, DateTime? currentStepTime, string? CurrentStepName,
         CancellationToken cancellationToken)
     {
         var order = await _orderRepository.GetAsync(d => d.WorkflowId == workflowId, cancellationToken);