TANG JIANG 2 жил өмнө
parent
commit
4647d26a18
27 өөрчлөгдсөн 235 нэмэгдсэн , 176 устгасан
  1. 1 1
      src/Hotline.Api/Controllers/OrderController.cs
  2. 23 7
      src/Hotline.Api/Controllers/PbxController.cs
  3. 9 1
      src/Hotline.Api/Controllers/WorkflowController.cs
  4. 1 0
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  5. 63 40
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  6. 1 1
      src/Hotline.Application/Handlers/FlowEngine/NextStepHandler.cs
  7. 1 1
      src/Hotline.Application/Handlers/FlowEngine/StartWorkflowHandler.cs
  8. 3 24
      src/Hotline.Application/Mappers/MapperConfigs.cs
  9. 1 1
      src/Hotline.Share/Dtos/CallCenter/TelRestDto.cs
  10. 1 1
      src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs
  11. 1 1
      src/Hotline.Share/Dtos/FlowEngine/EndWorkflowDto.cs
  12. 2 1
      src/Hotline.Share/Dtos/FlowEngine/StartWorkflowDto.cs
  13. 2 0
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  14. 1 1
      src/Hotline.Share/Dtos/Roles/RoleAuthorityDto.cs
  15. 0 50
      src/Hotline.Share/Dtos/Workflow/WorkflowDefinitionDto.cs
  16. 10 1
      src/Hotline/FlowEngine/Definitions/DefinitionDomainService.cs
  17. 1 0
      src/Hotline/FlowEngine/Definitions/IDefinitionDomainService.cs
  18. 4 3
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  19. 6 3
      src/Hotline/FlowEngine/Workflows/Workflow.cs
  20. 28 20
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  21. 3 2
      src/Hotline/FlowEngine/Workflows/WorkflowStep.cs
  22. 10 0
      src/Hotline/Orders/CommonOpinionTypeConsts.cs
  23. 1 1
      src/Hotline/Orders/IOrderDomainService.cs
  24. 1 1
      src/Hotline/Orders/OrderDomainService.cs
  25. 13 0
      src/Hotline/Settings/ISysDicDataDomainRepository.cs
  26. 18 0
      src/Hotline/Settings/SysDicDataDomainRepository.cs
  27. 30 15
      src/Hotline/Settings/SysDicTypeConsts.cs

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

@@ -160,7 +160,7 @@ public class OrderController : BaseController
         var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
         if (order == null)
             throw UserFriendlyException.SameMessage("无效工单编号");
-        if (order.Status != EOrderStatus.Temporary)
+        if (order.Status != EOrderStatus.Temporary || !string.IsNullOrEmpty(order.WorkflowId))
             throw UserFriendlyException.SameMessage("工单已发起流程");
         var workflowId = await _workflowApplication.StartWorkflowAsync(dto, HttpContext.RequestAborted);
         order.StartFlow(workflowId);

+ 23 - 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;
         }
 
@@ -212,6 +216,17 @@ namespace Hotline.Api.Controllers
 
         #region 话机设备操作
 
+        /// <summary>
+        /// 查询小修流程开启参数
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("flow-start")]
+        public async Task<IReadOnlyList<NextStepOptions>> GetFlowStartOptionsAsync()
+        {
+            return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.TelRestApply,
+                HttpContext.RequestAborted);
+        }
+
         /// <summary>
         /// 分机休息
         /// </summary>
@@ -235,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>

+ 1 - 0
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -22,6 +22,7 @@ namespace Hotline.Application.FlowEngine
         /// 查询流程下一节点配置参数
         /// </summary>
         Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(Workflow workflow, CancellationToken cancellationToken);
+        Task<IReadOnlyList<NextStepOptions>> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询指派办理人的处理方式及实际办理人

+ 63 - 40
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -54,7 +54,12 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
     public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, CancellationToken cancellationToken = default)
     {
-        var definition = await _definitionDomainService.GetLastVersionDefinitionAsync(dto.DefinitionCode, cancellationToken);
+        if (string.IsNullOrEmpty(dto.DefinitionCode) && string.IsNullOrEmpty(dto.DefinitionModuleCode))
+            throw new UserFriendlyException("非法参数");
+
+        var definition = string.IsNullOrEmpty(dto.DefinitionCode)
+            ? await _definitionDomainService.GetLastVersionDefinitionByModuleCodeAsync(dto.DefinitionModuleCode, cancellationToken)
+            : await _definitionDomainService.GetLastVersionDefinitionAsync(dto.DefinitionCode, cancellationToken);
         if (definition == null)
             throw new UserFriendlyException("无效模板名称");
         if (definition.Status != EDefinitionStatus.Enable)
@@ -83,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);
 
         //更新接办部门(详情页面展示)
@@ -96,7 +101,54 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     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)
+    {
+        var definition =
+            await _definitionDomainService.GetLastVersionDefinitionByModuleCodeAsync(moduleCode, cancellationToken);
+        if (definition == null)
+            throw new UserFriendlyException($"无效模块编码, modeuleCode: {moduleCode}", "无效模块编码");
+        var startStep = definition.Steps.FirstOrDefault(d => d.StepType == EStepType.Start);
+        var nextStepDefines = definition.FindSteps(startStep.NextSteps);
+        return await GetNextStepOptionsAsync(nextStepDefines);
+    }
+
+    /// <summary>
+    /// 查询指派办理人的处理方式及实际办理人
+    /// </summary>
+    public async Task<FlowAssignMode> GetFlowAssignModeAsync(StepDefine stepDefine, List<string> handlers, CancellationToken cancellationToken)
+    {
+        switch (stepDefine.HandlerType)
+        {
+            case EHandlerType.Role:
+                if (!handlers.Any())
+                {
+                    var roles = await _roleRepository.Queryable()
+                        .Includes(d => d.Accounts)
+                        .Where(d => stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Name))
+                        .ToListAsync();
+                    handlers = roles.SelectMany(d => d.Accounts).Select(d => d.Id).ToList();
+                }
+
+                return new FlowAssignMode(EFlowAssignType.User, handlers);
+            case EHandlerType.OrgLevel:
+            case EHandlerType.OrgType:
+            case EHandlerType.AssignOrg:
+                return new FlowAssignMode(EFlowAssignType.Org, handlers);
+            case EHandlerType.AssignUser:
+                return new FlowAssignMode(EFlowAssignType.User, handlers);
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+    }
 
+
+    #region private
+
+    private async Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(IReadOnlyList<StepDefine> nextStepDefines)
+    {
         //todo 性能问题
         var items = new List<NextStepOptions>();
         foreach (var nextStepDefine in nextStepDefines)
@@ -110,11 +162,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             switch (nextStepDefine.HandlerType)
             {
                 case EHandlerType.AssignUser:
-                    var users = await _userRepository.QueryAsync(d => nextStepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Id));
+                    var users = await _userRepository.QueryAsync(d =>
+                        nextStepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Id));
                     options.NextSteps = users.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
                     break;
                 case EHandlerType.AssignOrg:
-                    var orgs = await _organizeRepository.QueryAsync(d => nextStepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.OrgCode));
+                    var orgs = await _organizeRepository.QueryAsync(d =>
+                        nextStepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.OrgCode));
                     options.NextSteps = orgs.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName)).ToList();
                     break;
                 case EHandlerType.Role:
@@ -151,37 +205,6 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         return items;
     }
 
-    /// <summary>
-    /// 查询指派办理人的处理方式及实际办理人
-    /// </summary>
-    public async Task<FlowAssignMode> GetFlowAssignModeAsync(StepDefine stepDefine, List<string> handlers, CancellationToken cancellationToken)
-    {
-        switch (stepDefine.HandlerType)
-        {
-            case EHandlerType.Role:
-                if (!handlers.Any())
-                {
-                    var roles = await _roleRepository.Queryable()
-                        .Includes(d => d.Accounts)
-                        .Where(d => stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Name))
-                        .ToListAsync();
-                    handlers = roles.SelectMany(d => d.Accounts).Select(d => d.Id).ToList();
-                }
-
-                return new FlowAssignMode(EFlowAssignType.User, handlers);
-            case EHandlerType.OrgLevel:
-            case EHandlerType.OrgType:
-            case EHandlerType.AssignOrg:
-                return new FlowAssignMode(EFlowAssignType.Org, handlers);
-            case EHandlerType.AssignUser:
-                return new FlowAssignMode(EFlowAssignType.User, handlers);
-            default:
-                throw new ArgumentOutOfRangeException();
-        }
-    }
-
-
-    #region private
 
     /// <summary>
     /// 更新接办部门
@@ -198,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();
@@ -222,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();
@@ -234,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 - 24
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -1,10 +1,9 @@
 using Hotline.CallCenter.BlackLists;
 using Hotline.FlowEngine.Definitions;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Identity.Roles;
-using Hotline.KnowledgeBase;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos.Roles;
 using Hotline.Share.Dtos.Users;
 using Hotline.Users;
@@ -41,29 +40,9 @@ namespace Hotline.Application.Mappers
             config.NewConfig<UpdateDefinitionDto, Definition>()
                 .Ignore(d => d.Id);
 
-            config.NewConfig<KnowledgeApply, KnowledgeApplyPageDto>()
-              .Map(d => d.CreationName, x => x.User.Name)
-                .Map(d => d.CreationOrgName, x => x.SystemOrganize.OrgName);
-
-            config.NewConfig<Hotline.KnowledgeBase.Knowledge, KnowledgeDataDto>()
-              .Map(d => d.CreationName, x => x.User.Name)
-                .Map(d => d.KnowledgeTypeName, x => x.KnowledgeType.SpliceName);
-
-            config.NewConfig<Hotline.KnowledgeBase.Knowledge, KnowledgeApprovalDataDto>()
-            .Map(d => d.CreationName, x => x.User.Name)
-              .Map(d => d.KnowledgeTypeName, x => x.KnowledgeType.SpliceName)
-                 .Map(d => d.CreateBMName, x => x.SystemOrganize.OrgName);
+            config.NewConfig<WorkflowStep, WorkflowStep>()
+                .Ignore(d => d.Id);
 
-            config.NewConfig<KnowledgeWorkFlow, KnowledgeApprovalDataDto>()
-                .Map(d => d.CreationName, x => x.Knowledge.User.Name)
-                .Map(d => d.KnowledgeTypeName, x => x.Knowledge.KnowledgeType.SpliceName)
-                .Map(d => d.CreateBMName, x => x.Knowledge.SystemOrganize.OrgName)
-                .Map(d => d.Id, x => x.Knowledge.Id)
-                .Map(d => d.Title, x => x.Knowledge.Title)
-                .Map(d => d.PageView, x => x.Knowledge.PageView)
-                .Map(d => d.Status, x => x.Knowledge.Status)
-                .Map(d => d.WorkflowModuleStatus, x => x.WorkflowModuleStatus)
-                .Map(d => d.Time, x => x.Workflow.CurrentStepTime);
             #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 - 1
src/Hotline.Share/Dtos/FlowEngine/StartWorkflowDto.cs

@@ -5,7 +5,8 @@
         /// <summary>
         /// 模板编码
         /// </summary>
-        public string DefinitionCode { get; set; }
+        public string? DefinitionCode { get; set; }
+        public string? DefinitionModuleCode { get; set; }
 
         /// <summary>
         /// 流程title

+ 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>

+ 1 - 1
src/Hotline.Share/Dtos/Roles/RoleAuthorityDto.cs

@@ -22,7 +22,7 @@ namespace Hotline.Share.Dtos.Roles
 
         public EAuthorityType AuthorityType { get; set; }
 
-        public string PermissionCode { get; set; }
+        public string TableId { get; set; }
     }
 
     public record UpdateDataAuthorityDto

+ 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; }
-}

+ 10 - 1
src/Hotline/FlowEngine/Definitions/DefinitionDomainService.cs

@@ -34,7 +34,7 @@ public class DefinitionDomainService : IDefinitionDomainService, IScopeDependenc
         var definitionTemp = await _definitionRepository.GetAsync(id, cancellationToken);
         if (definitionTemp == null)
             throw UserFriendlyException.SameMessage("无效模板编号");
-        if(definitionTemp.Status != EDefinitionStatus.Temporary)
+        if (definitionTemp.Status != EDefinitionStatus.Temporary)
             throw UserFriendlyException.SameMessage("非草稿模板不允许发布");
 
         ValidateDefinition(definitionTemp);
@@ -70,6 +70,15 @@ public class DefinitionDomainService : IDefinitionDomainService, IScopeDependenc
             .FirstAsync();
     }
 
+    public async Task<Definition?> GetLastVersionDefinitionByModuleCodeAsync(string moduleCode, CancellationToken cancellationToken)
+    {
+        return await _definitionRepository.Queryable()
+            .Where(d => d.ModuleCode == moduleCode)
+            .OrderByDescending(d => d.Version)
+            .Take(1)
+            .FirstAsync();
+    }
+
     /// <summary>
     /// 未开启的流程,查找第2个节点的模板配置信息,用作开始流程的时候传参
     /// </summary>

+ 1 - 0
src/Hotline/FlowEngine/Definitions/IDefinitionDomainService.cs

@@ -18,6 +18,7 @@ namespace Hotline.FlowEngine.Definitions
 
         Task<int> GetLastVersionAsync(string code, CancellationToken cancellationToken);
         Task<Definition?> GetLastVersionDefinitionAsync(string code, CancellationToken cancellationToken);
+        Task<Definition?> GetLastVersionDefinitionByModuleCodeAsync(string moduleCode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 未开启的流程,查找start节点配置的nextSteps信息,用作开启流程的传参

+ 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 会签
 

+ 10 - 0
src/Hotline/Orders/CommonOpinionTypeConsts.cs

@@ -57,5 +57,15 @@ namespace Hotline.Orders
         /// 知识诉求常用意见
         /// </summary>
         public const string KnowledgeLocution = "KnowledgeLocution";
+
+        /// <summary>
+        /// 小休原因
+        /// </summary>
+        public const string RestReason = "RestReason";
+
+        /// <summary>
+        /// 小休常用意见
+        /// </summary>
+        public const string Rest = "Rest";
     }
 }

+ 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);

+ 13 - 0
src/Hotline/Settings/ISysDicDataDomainRepository.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Settings
+{
+    public interface ISysDicDataDomainRepository
+    {
+        Task<IReadOnlyList<SysDicData>> GetSysDicDataByCode(string code);
+    }
+}

+ 18 - 0
src/Hotline/Settings/SysDicDataDomainRepository.cs

@@ -0,0 +1,18 @@
+using XF.Domain.Dependency;
+
+namespace Hotline.Settings
+{
+    public class SysDicDataDomainRepository : ISysDicDataDomainRepository, IScopeDependency
+    {
+        private readonly ISysDicDataRepository _sysDicDataRepository;
+        public SysDicDataDomainRepository(ISysDicDataRepository sysDicDataRepository)
+        {
+            _sysDicDataRepository = sysDicDataRepository;
+        }
+
+        public async Task<IReadOnlyList<SysDicData>> GetSysDicDataByCode(string code)
+        {
+            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeCode == code).ToTreeAsync(x => x.Children, x => x.ParentId, "");
+        }
+    }
+}

+ 30 - 15
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -6,72 +6,87 @@
 public class SysDicTypeConsts
 {
     /// <summary>
-    /// 证件类型
+    /// 证件类型(字典)
     /// </summary>
     public const string LicenceType = "LicenceType";
 
     /// <summary>
-    /// 身份类型
+    /// 提供方身份类型(字典)
     /// </summary>
-    public const string IdentityType = "IdentityType";
+    public const string ProviderIdentityType = "ProviderIdentityType";
 
     /// <summary>
-    /// 身份
+    /// 提供方身份(字典)
     /// </summary>
     public const string Identity = "Identity";
 
     /// <summary>
-    /// 国籍/地区
+    /// 国籍/地区(字典)
     /// </summary>
     public const string Nationality = "Nationality";
 
     /// <summary>
-    /// 民族
+    /// 民族(字典)
     /// </summary>
     public const string Nation = "Nation";
 
     /// <summary>
-    /// 市场主体类型
+    /// 市场主体类型(字典)
     /// </summary>
     public const string MarketType = "MarketType";
 
     /// <summary>
-    /// 行业分类
+    /// 行业分类(数据错误(编码重复))
     /// </summary>
     public const string IndustryClassify = "IndustryClassify";
 
     /// <summary>
-    /// 商品分类/品牌
+    /// 商品分类/品牌(字典)
     /// </summary>
     public const string Brand = "Brand";
 
     /// <summary>
-    /// 客体类别
+    /// 客体类别(字典)
     /// </summary>
     public const string ObjectClassify = "ObjectClassify";
 
     /// <summary>
-    /// 销售方式
+    /// 销售方式(字典)
     /// </summary>
     public const string SalesMode = "SalesMode";
 
     /// <summary>
-    /// 电商平台
+    /// 电商平台(字典)
     /// </summary>
     public const string ECommercePlatform = "ECommercePlatform";
 
     /// <summary>
-    /// 投诉问题类别
+    /// 投诉问题类别(字典)
     /// </summary>
     public const string ComplainClassify = "ComplainClassify";
 
     /// <summary>
-    /// 举报问题类别
+    /// 举报问题类别(字典)
     /// </summary>
     public const string ReportClassify = "ReportClassify";
 
     /// <summary>
-    /// 年龄段
+    /// 年龄段(字典)
     /// </summary>
     public const string AgeRange = "AgeRange";
+
+    /// <summary>
+    /// 来源渠道(省:诉求渠道)
+    /// </summary>
+    public const string SourceChannel = "SourceChannel";
+
+    /// <summary>
+    /// 工单类型
+    /// </summary>
+    public const string OrderType = "OrderType";
+
+    /// <summary>
+    /// 紧急程度
+    /// </summary>
+    public const string Urgency = "Urgency";
 }