xf před 1 rokem
rodič
revize
2b521636a2
34 změnil soubory, kde provedl 351 přidání a 218 odebrání
  1. 2 2
      src/Hotline.Api/Controllers/KnowledgeController.cs
  2. 7 9
      src/Hotline.Api/Controllers/OrderController.cs
  3. 1 1
      src/Hotline.Api/Controllers/PbxController.cs
  4. 10 10
      src/Hotline.Api/Controllers/WorkflowController.cs
  5. 2 2
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  6. 34 53
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  7. 8 4
      src/Hotline.Application/Handlers/FlowEngine/EndWorkflowHandler.cs
  8. 1 1
      src/Hotline.Application/Mappers/MapperConfigs.cs
  9. 5 0
      src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs
  10. 3 3
      src/Hotline.Share/Dtos/FlowEngine/DefinedNextStepsDto.cs
  11. 0 10
      src/Hotline.Share/Dtos/FlowEngine/EnabelWfModuleDto.cs
  12. 0 14
      src/Hotline.Share/Dtos/FlowEngine/NextStepDto.cs
  13. 24 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepOptionDto.cs
  14. 0 13
      src/Hotline.Share/Dtos/FlowEngine/NextStepOptions.cs
  15. 1 1
      src/Hotline.Share/Dtos/FlowEngine/NextWorkflowDto.cs
  16. 6 5
      src/Hotline.Share/Dtos/FlowEngine/StepBasicDto.cs
  17. 15 0
      src/Hotline.Share/Dtos/FlowEngine/StepExtension.cs
  18. 1 1
      src/Hotline.Share/Dtos/IdName.cs
  19. 142 35
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  20. 10 7
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  21. 13 3
      src/Hotline.Share/Enums/FlowEngine/EWorkflowTraceStatus.cs
  22. 1 1
      src/Hotline/FlowEngine/Definitions/StepBasic.cs
  23. 1 1
      src/Hotline/FlowEngine/FlowAssignInfo.cs
  24. 1 1
      src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs
  25. 1 0
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  26. 1 8
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  27. 9 2
      src/Hotline/FlowEngine/Workflows/Workflow.cs
  28. 26 17
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  29. 1 1
      src/Hotline/FlowEngine/Workflows/WorkflowStep.cs
  30. 16 9
      src/Hotline/Orders/Order.cs
  31. 2 2
      src/Hotline/Orders/OrderDomainService.cs
  32. 1 1
      src/Hotline/Orders/OrderVisit.cs
  33. 1 1
      src/Hotline/Orders/OrderVisitDetail.cs
  34. 5 0
      src/Hotline/Settings/SysDicTypeConsts.cs

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

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

+ 7 - 9
src/Hotline.Api/Controllers/OrderController.cs

@@ -110,12 +110,12 @@ public class OrderController : BaseController
     {
         var (total, items) = await _orderRepository.Queryable()
             .Includes(d => d.OrderPublished)
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .Where(x => x.Status == EOrderStatus.Filed)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .WhereIF(dto.PubState == EPubState.Pub, d => d.Progress == EProgress.Published || d.Progress == EProgress.Visited)
             .WhereIF(dto.PubState == EPubState.NoPub, d => d.Progress == EProgress.Managing)
-            .WhereIF(!string.IsNullOrEmpty(dto.PubMan), d => d.Employee.Name.Contains(dto.PubMan!) || d.Employee.StaffNo.Contains(dto.PubMan!))
+            .WhereIF(!string.IsNullOrEmpty(dto.PubMan), d => d.Acceptor.Name.Contains(dto.PubMan!) || d.Acceptor.StaffNo.Contains(dto.PubMan!))
             .WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublished.PublishState)
             .WhereIF(dto.PubRange == EPublicState.NoPub, d=>!d.OrderPublished.PublishState)
             .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
@@ -197,7 +197,7 @@ public class OrderController : BaseController
     public async Task<PublishOrderPageBaseDto> PublishOrderPageBase(string id)
     {
         var order = await _orderRepository.Queryable()
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .Includes(d => d.OrderComplain)
             .FirstAsync(d => d.Id == id);
 
@@ -331,7 +331,7 @@ public class OrderController : BaseController
     public async Task<PagedDto<OrderDto>> CanDelayOrderList([FromQuery]CanDelayOrderListDto dto)
     {
         var (total,items) = await _orderRepository.Queryable()
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.Filed && 
             SqlFunc.Subqueryable<OrderDelay>().Where(s=>s.OrderId == d.Id && s.DelayState == EDelayState.Examining).NotAny())
@@ -447,7 +447,6 @@ public class OrderController : BaseController
     public async Task<PagedDto<OrderDto>> Query([FromQuery] QueryOrderDto dto)
     {
         var (total, items) = await _orderRepository.Queryable()
-            .Includes(d => d.Employee)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
             .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
@@ -456,7 +455,7 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
             //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
             .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Workflow.ActualHandleOrgCode))
-            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Employee.Name.Contains(dto.NameOrNo!) || d.Employee.StaffNo.Contains(dto.NameOrNo!))
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!))
             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
             .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
             .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))
@@ -498,7 +497,7 @@ public class OrderController : BaseController
     public async Task<OrderDto> Get(string id)
     {
         var order = await _orderRepository.Queryable()
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .Includes(d => d.OrderComplain)
             .Includes(d => d.OrderReport)
             .FirstAsync(d => d.Id == id);
@@ -536,7 +535,6 @@ public class OrderController : BaseController
     public async Task<string> Add([FromBody] AddOrderDto dto)
     {
         var order = _mapper.Map<Order>(dto);
-        order.EmployeeId = _sessionContext.RequiredUserId;
         return await _orderDomainService.AddAsync(order, HttpContext.RequestAborted);
     }
 
@@ -610,7 +608,7 @@ public class OrderController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpGet("flow-start")]
-    public async Task<DefineWithSelectionStepsDto> GetFlowStartOptionsAsync()
+    public async Task<DefinedNextStepsDto> GetFlowStartOptionsAsync()
     {
         return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderManage, HttpContext.RequestAborted);
     }

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

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

+ 10 - 10
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -290,15 +290,15 @@ public class WorkflowController : BaseController
     /// 查询当前流程下一步待选节点
     /// </summary>
     [HttpGet("{workflowId}/nextsteps")]
-    public async Task<DefineWithSelectionStepsDto> GetNextStepDefine(string workflowId)
+    public async Task<DefinedNextStepsDto> GetNextStepDefine(string workflowId)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true,
             cancellationToken: HttpContext.RequestAborted);
         var nextStepDefines = _workflowDomainService.GetNextStepDefines(workflow);
-        return new DefineWithSelectionStepsDto
+        return new DefinedNextStepsDto
         {
             Id = workflow.DefinitionId,
-            Steps = nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList(),
+            Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines),//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList(),
             ExpiredTime = workflow.ExpiredTime
         };
     }
@@ -307,7 +307,7 @@ public class WorkflowController : BaseController
     /// 查询当前流程下一节点待选配置
     /// </summary>
     [HttpGet("step-options")]
-    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptions([FromQuery] QueryNextStepOptionDto dto)
+    public async Task<NextStepOptionDto> GetNextStepOptions([FromQuery] QueryNextStepOptionDto dto)
     {
         var definition = await _definitionRepository.GetAsync(dto.DefineId, HttpContext.RequestAborted);
         if (definition == null)
@@ -348,16 +348,16 @@ public class WorkflowController : BaseController
     /// <returns></returns>
     [Permission(EPermission.FlowRecall)]
     [HttpGet("{workflowId}/recall")]
-    public async Task<DefineWithSelectionStepsDto> GetRecallOptions(string workflowId)
+    public async Task<DefinedNextStepsDto> GetRecallOptions(string workflowId)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
         var stepCodes = workflow.StepBoxes.Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End)
             .Select(d => d.Code).ToList();
         var nextStepDefines = workflow.Definition.FindSteps(stepCodes);
-        return new DefineWithSelectionStepsDto
+        return new DefinedNextStepsDto
         {
             Id = workflow.DefinitionId,
-            Steps = nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
+            Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines)//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
         };
     }
 
@@ -379,15 +379,15 @@ public class WorkflowController : BaseController
     /// <param name="workflowId"></param>
     /// <returns></returns>
     [HttpGet("{workflowId}/jump")]
-    public async Task<DefineWithSelectionStepsDto> GetJumpOptions(string workflowId)
+    public async Task<DefinedNextStepsDto> GetJumpOptions(string workflowId)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: HttpContext.RequestAborted);
         var steps = workflow.Definition.Steps.Where(d => d.StepType != EStepType.Start && d.StepType != EStepType.End).ToList();
         var nextStepDefines = workflow.Definition.FindSteps(steps.Select(d => d.Code));
-        return new DefineWithSelectionStepsDto
+        return new DefinedNextStepsDto
         {
             Id = workflow.DefinitionId,
-            Steps = nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
+            Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(nextStepDefines)//nextStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
         };
     }
 

+ 2 - 2
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -32,7 +32,7 @@ namespace Hotline.Application.FlowEngine
         /// <summary>
         /// 查询流程开始节点的下一节点配置
         /// </summary>
-        Task<DefineWithSelectionStepsDto> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken);
+        Task<DefinedNextStepsDto> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询节点配置可选参数
@@ -40,6 +40,6 @@ namespace Hotline.Application.FlowEngine
         /// <param name="stepDefine"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken);
+        Task<NextStepOptionDto> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken);
     }
 }

+ 34 - 53
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -1,5 +1,6 @@
 using Hotline.Application.Contracts.Validators.FlowEngine;
 using Hotline.Caching.Interfaces;
+using Hotline.Caching.Services;
 using Hotline.FlowEngine;
 using Hotline.FlowEngine.Definitions;
 using Hotline.FlowEngine.WfModules;
@@ -9,6 +10,8 @@ using Hotline.Identity.Roles;
 using Hotline.Orders;
 using Hotline.SeedData;
 using Hotline.Settings;
+using Hotline.Settings.TimeLimits;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Identity;
@@ -34,6 +37,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     private readonly ISystemOrganizeRepository _organizeRepository;
     private readonly IRoleRepository _roleRepository;
     private readonly IWfModuleCacheManager _wfModuleCacheManager;
+    private readonly ISystemDomainService _systemDomainService;
     private readonly IUserDomainService _userDomainService;
     private readonly IAccountDomainService _accountDomainService;
     private readonly ISessionContext _sessionContext;
@@ -50,6 +54,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         ISystemOrganizeRepository organizeRepository,
         IRoleRepository roleRepository,
         IWfModuleCacheManager wfModuleCacheManager,
+        ISystemDomainService systemDomainService,
         ISessionContext sessionContext,
         IMapper mapper)
     {
@@ -63,6 +68,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         _organizeRepository = organizeRepository;
         _roleRepository = roleRepository;
         _wfModuleCacheManager = wfModuleCacheManager;
+        _systemDomainService = systemDomainService;
         _sessionContext = sessionContext;
         _mapper = mapper;
     }
@@ -155,7 +161,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         await _workflowDomainService.JumpAsync(workflow, dto, targetStepDefine, dto.IsStartCountersign, flowAssignMode, cancellationToken);
     }
 
-    public async Task<DefineWithSelectionStepsDto> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken)
+    public async Task<DefinedNextStepsDto> GetStartOptionsAsync(string moduleCode, CancellationToken cancellationToken)
     {
         var wfModule = await GetWorkflowModuleAsync(moduleCode, cancellationToken);
         var definition = wfModule.Definition;
@@ -172,10 +178,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var secondStepDefines = definition.FindSteps(firstStep.NextSteps.Select(d => d.Code));
 
 
-        return new DefineWithSelectionStepsDto
+        return new DefinedNextStepsDto
         {
             Id = definition.Id,
-            Steps = secondStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
+            Steps = _mapper.Map<IReadOnlyList<StepBasicDto>>(secondStepDefines)//secondStepDefines.Select(d => new KeyValuePair<string, string>(d.Code, d.Name)).ToList()
         };
     }
 
@@ -186,30 +192,34 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
     /// <exception cref="ArgumentOutOfRangeException"></exception>
-    public async Task<IReadOnlyList<KeyValuePair<string, string>>> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken)
+    public async Task<NextStepOptionDto> GetNextStepOptionsAsync(StepDefine stepDefine, CancellationToken cancellationToken)
     {
-        if (stepDefine.StepType == EStepType.End) return new List<KeyValuePair<string, string>>();
+        if (stepDefine.StepType == EStepType.End) return new();
 
+        var handlers = new List<IdName>();
         switch (stepDefine.HandlerType)
         {
             case EHandlerType.AssignUser:
                 var users = await _userRepository.QueryAsync(d =>
                     !d.IsDeleted &&
                     stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Id));
-                return users.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
+                handlers = users.Select(d => new IdName(d.Id, d.Name)).ToList();
+                break;
             case EHandlerType.AssignOrg:
                 var orgs = await _organizeRepository.QueryAsync(d =>
                     d.IsEnable &&
                     stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.OrgCode));
-                return orgs.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
+                handlers = orgs.Select(d => new IdName(d.OrgCode, d.OrgName))
                     .ToList();
+                break;
             case EHandlerType.Role:
                 var roles = await _roleRepository.Queryable()
                     .Includes(d => d.Accounts.Where(x => !x.IsDeleted && x.Status == EAccountStatus.Normal).ToList(), x => x.User)
                     .Where(d => stepDefine.HandlerClassifies.Select(d => d.Id).Contains(d.Name))
-                    .ToListAsync();
+                    .ToListAsync(cancellationToken);
                 var users1 = roles.SelectMany(d => d.Accounts).Select(d => d.User);
-                return users1.Select(d => new KeyValuePair<string, string>(d.Id, d.Name)).ToList();
+                handlers = users1.Select(d => new IdName(d.Id, d.Name)).ToList();
+                break;
             case EHandlerType.OrgLevel:
                 //当前操作人所属部门的下级部门并且属于配置orgLevel的部门
                 var levels = stepDefine.HandlerClassifies.Select(d => d.Id).Select(d => int.Parse(d));
@@ -217,8 +227,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 var orgs1 = await _organizeRepository.QueryAsync(d =>
                     d.IsEnable && d.OrgCode.StartsWith(levelOneOrg) &&
                     levels.Contains(d.OrgLevel));
-                return orgs1.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
-                    .ToList();
+                handlers = orgs1.Select(d => new IdName(d.OrgCode, d.OrgName)).ToList();
+                break;
             case EHandlerType.OrgType:
                 var types = stepDefine.HandlerClassifies.Select(d => d.Id)
                     .Select(d => Enum.Parse<EOrgType>(d));
@@ -226,12 +236,21 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 var org2 = await _organizeRepository.QueryAsync(d =>
                     d.IsEnable && d.OrgCode.StartsWith(levelOneOrg1) &&
                     types.Contains(d.OrgType));
-                return org2.Select(d => new KeyValuePair<string, string>(d.OrgCode, d.OrgName))
-                    .ToList();
-
+                handlers = org2.Select(d => new IdName(d.OrgCode, d.OrgName)).ToList();
+                break;
             default:
                 throw new ArgumentOutOfRangeException();
         }
+
+        var dto = new NextStepOptionDto { Handlers = handlers };
+
+        if (stepDefine.Properties.Contains(SysDicTypeConsts.OrderRedoReason))
+        {
+            var orderRedoReasons = await _systemDomainService.GetSysDicDataByCodeAsync(SysDicTypeConsts.OrderRedoReason);
+            dto.OrderRedoReasonOptions = orderRedoReasons.Select(d => new IdName(d.DicDataValue, d.DicDataName)).ToList();
+        }
+
+        return dto;
     }
 
 
@@ -270,7 +289,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
 
     #region private
-    
+
     /// <summary>
     /// 查询流程业务模块
     /// </summary>
@@ -359,43 +378,5 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         }
     }
 
-    private async Task<bool> CheckIfFlowOutFromCallCenterAsync(StepDefine nextStepBoxDefine, string mainHandler, CancellationToken CancellationToken)
-    {
-        //current is center & next is not center return true
-        var isFromCallCenter = IsOrgFromCallCenter(_sessionContext.RequiredOrgCode);
-        if (!isFromCallCenter) return false;
-
-        var isOutCallCenter = await CheckNextStepHandlerIsOutCallCenterAsync(nextStepBoxDefine, mainHandler, CancellationToken);
-        return isFromCallCenter && isOutCallCenter;
-    }
-
-    private async Task<bool> CheckNextStepHandlerIsOutCallCenterAsync(StepDefine nextStepBoxDefine, string mainHandler, CancellationToken cancellationToken)
-    {
-        if (nextStepBoxDefine.HandlerType is EHandlerType.AssignUser or EHandlerType.Role)
-        {
-            //mainHandler is userId
-            var handler = await _userRepository.GetAsync(mainHandler, cancellationToken);
-            if (handler == null)
-                throw new UserFriendlyException($"mainHandler未找到对应User, handler: {mainHandler}");
-            if (string.IsNullOrEmpty(handler.OrgCode))
-                throw UserFriendlyException.SameMessage($"该用户未配置所属部门, userId: {mainHandler}");
-            return !IsOrgFromCallCenter(handler.OrgCode);
-        }
-        else
-        {
-            //mainHandler is orgCode
-            return !IsOrgFromCallCenter(mainHandler);
-        }
-    }
-
-    /// <summary>
-    /// 是否为呼叫中心
-    /// </summary>
-    /// <returns></returns>
-    private bool IsOrgFromCallCenter(string orgCode) =>
-        string.CompareOrdinal(orgCode, OrgSeedData.CallCenterCode) == 0;
-
-
-
     #endregion
 }

+ 8 - 4
src/Hotline.Application/Handlers/FlowEngine/EndWorkflowHandler.cs

@@ -7,6 +7,7 @@ using Hotline.KnowledgeBase;
 using Hotline.Orders;
 using Hotline.Repository.SqlSugar.Orders;
 using Hotline.Settings;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Mq;
 using MapsterMapper;
@@ -79,10 +80,13 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
                 _mapper.Map(workflow, order);
                 order.Filed();
                 await _orderRepository.UpdateAsync(order, cancellationToken);
-                
-                await _capPublisher.PublishAsync(EventNames.HotlineOrderFiled, _mapper.Map<OrderDto>(order),
-                    cancellationToken: cancellationToken);
-                
+
+                await _capPublisher.PublishAsync(EventNames.HotlineOrderFiled, new OrderFlowDto
+                {
+                    Order = _mapper.Map<OrderDto>(order),
+                    WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace)
+                }, cancellationToken: cancellationToken);
+
                 break;
         }
     }

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

@@ -157,7 +157,6 @@ namespace Hotline.Application.Mappers
             config.ForType<Order, OrderDto>()
                 .IgnoreIf((s, d) => s.OrderComplain == null, d => d.OrderComplain)
                 .IgnoreIf((s, d) => s.OrderReport == null, d => d.OrderReport)
-                .IgnoreIf((s, d) => s.Employee == null, d => d.EmployeeName, d => d.EmployeeStaffNo)
                 .IgnoreIf((s, d) => s.Hotspot == null, d => d.Hotspot)
                 //.IgnoreIf((s, d) => s.Workflow == null, d => d.Workflow)
                 //.Ignore(d => d.Workflow.Definition)
@@ -208,6 +207,7 @@ namespace Hotline.Application.Mappers
                 .Map(d => d.OrgLevelOneName, s => s.OrgLevelOneName)
                 .Map(d => d.AcceptorId, s => s.AcceptorId)
                 .Map(d => d.AcceptorName, s => s.AcceptorName)
+                .Map(d => d.AcceptorStaffNo, s => s.AcceptorStaffNo)
                 .Map(d => d.ProcessType, s => s.ProcessType)
                 .Map(d => d.AssignUserIds, s => s.AssignUserIds)
                 .Map(d => d.AssignOrgCodes, s => s.AssignOrgCodes)

+ 5 - 0
src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs

@@ -32,4 +32,9 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// 发起会签
     /// </summary>
     public bool IsStartCountersign { get; set; } = false;
+
+    /// <summary>
+    /// 扩展信息
+    /// </summary>
+    public StepExtension Extension { get; set; } = new();
 }

+ 3 - 3
src/Hotline.Share/Dtos/FlowEngine/DefineWithSelectionStepsDto.cs → src/Hotline.Share/Dtos/FlowEngine/DefinedNextStepsDto.cs

@@ -7,13 +7,13 @@ using System.Threading.Tasks;
 namespace Hotline.Share.Dtos.FlowEngine
 {
     /// <summary>
-    /// 只含待选step的define
+    /// 配置好的下一节点
     /// </summary>
-    public class DefineWithSelectionStepsDto
+    public class DefinedNextStepsDto
     {
         public string Id { get; set; }
 
-        public IReadOnlyList<KeyValuePair<string, string>> Steps { get; set; }
+        public IReadOnlyList<StepBasicDto> Steps { get; set; }
 
         public DateTime ExpiredTime { get; set; }
     }

+ 0 - 10
src/Hotline.Share/Dtos/FlowEngine/EnabelWfModuleDto.cs

@@ -1,10 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Hotline.Share.Dtos.FlowEngine
-{
-    public record EnableWfModuleDto(string WfModuleId, bool Enable);
-}

+ 0 - 14
src/Hotline.Share/Dtos/FlowEngine/NextStepDto.cs

@@ -1,14 +0,0 @@
-namespace Hotline.Share.Dtos.FlowEngine
-{
-    public class NextStepDto
-    {
-        public string? Predicate { get; set; }
-
-        public StepBasicDto StepInfo { get; set; }
-
-        /// <summary>
-        /// 被选择
-        /// </summary>
-        public bool Selected { get; set; }
-    }
-}

+ 24 - 0
src/Hotline.Share/Dtos/FlowEngine/NextStepOptionDto.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.FlowEngine
+{
+    /// <summary>
+    /// 下一节点的可选项
+    /// </summary>
+    public class NextStepOptionDto
+    {
+        /// <summary>
+        /// 办理人/部门(待选项)
+        /// </summary>
+        public IReadOnlyList<IdName> Handlers { get; set; }
+
+        /// <summary>
+        /// 工单重办理由待选项,对应code:OrderRedoReason
+        /// </summary>
+        public IReadOnlyList<IdName> OrderRedoReasonOptions { get; set; }
+    }
+}

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

@@ -1,13 +0,0 @@
-namespace Hotline.Share.Dtos.FlowEngine;
-
-/// <summary>
-/// 下一节点配置参数
-/// </summary>
-public class NextStepOptions
-{
-    public string Code { get; set; } = string.Empty;
-
-    public string Name { get; set; } = string.Empty;
-
-    public IReadOnlyList<KeyValuePair<string, string>> NextSteps { get; set; } = new List<KeyValuePair<string, string>>();
-}

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

@@ -8,7 +8,7 @@ public class NextWorkflowDto : BasicWorkflowDto
     public string WorkflowId { get; set; }
 
     /// <summary>
-    /// 当前节点到期时间(期满时间)
+    /// 下一节点到期时间(节点期满时间)
     /// </summary>
     public DateTime ExpiredTime { get; set; }
 }

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

@@ -23,11 +23,6 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// </summary>
         public EBusinessProperty BusinessProperty { get; set; }
 
-        ///// <summary>
-        ///// 只允许该角色下本部门人办理,否则该角色下所有人均可办理(办理者类型为角色时此字段有值)
-        ///// </summary>
-        //public bool? OnlySelfOrg { get; set; }
-
         /// <summary>
         /// 办理者分类(或是直接保存办理者)
         /// <example>
@@ -50,5 +45,11 @@ namespace Hotline.Share.Dtos.FlowEngine
         /// 会签汇总节点code(不支持发起会签节点无此字段)
         /// </summary>
         public string? CountersignEndCode { get; set; }
+
+        /// <summary>
+        /// 节点属性配置
+        /// </summary>
+        public List<string> Properties { get; set; } = new();
+
     }
 }

+ 15 - 0
src/Hotline.Share/Dtos/FlowEngine/StepExtension.cs

@@ -0,0 +1,15 @@
+namespace Hotline.Share.Dtos.FlowEngine;
+
+public class StepExtension
+{
+    /// <summary>
+    /// 省延期申请
+    /// </summary>
+    public bool? ApplyDelayProvince { get; set; }
+
+    /// <summary>
+    /// 工单重办理由
+    /// </summary>
+    public string? OrderRedoReason { get; set; }
+    public string? OrderRedoReasonCode { get; set; }
+}

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/IdName.cs → src/Hotline.Share/Dtos/IdName.cs

@@ -1,4 +1,4 @@
-namespace Hotline.Share.Dtos.FlowEngine;
+namespace Hotline.Share.Dtos;
 
 public class IdName
 {

+ 142 - 35
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Data.SqlTypes;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -13,29 +14,67 @@ namespace Hotline.Share.Dtos.Order
     public class OrderDto : UpdateOrderDto
     {
         #region 工单属性
+        
+        /// <summary>
+        /// 工单状态
+        /// </summary>
+        public EOrderStatus Status { get; set; }
+        public string StatusText => Status.GetDescription();
 
         /// <summary>
-        /// 来源渠道名称
+        /// 过期状态
         /// </summary>
-        public string SourceChannelText { get; set; }
+        public EExpiredStatus ExpiredStatus { get; set; }
 
         /// <summary>
-        /// 当前节点名称
+        /// 处理方式(直办、交办)
         /// </summary>
-        public string CurrentStepName { get; set; }
+        public EProcessType ProcessType { get; set; }
 
         /// <summary>
-        /// 到达当前节点时间
+        /// 进展情况
         /// </summary>
-        public DateTime? CurrentStepTime { get; set; }
+        public EProgress Progress { get; set; }
 
         /// <summary>
-        /// 工单状态
+        /// 是否公开
         /// </summary>
-        public EOrderStatus Status { get; set; }
+        public bool IsPublicity { get; set; }
+
+        /// <summary>
+        /// 是否为省工单
+        /// </summary>
+        public bool IsProvince { get; set; }
+
+        /// <summary>
+        /// 工单编码(20220101000001)
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 省工单编号(冗余)
+        /// </summary>
+        public string? FromProvinceNo { get; set; }
+
+        /// <summary>
+        /// 同步省工单编号(按省工单要求生成的编号,冗余)
+        /// </summary>
+        public string? ToProvinceNo { get; set; }
+
+        /// <summary>
+        /// 省过期时间(省工单才有)
+        /// </summary>
+        public DateTime? ExpiredTimeProvince { get; set; }
 
         /// <summary>
-        /// 开始时间
+        /// 110工单编号(从110来的和推送给110的都用该字段记录唯一标识)
+        /// </summary>
+        public string? No110 { get; set; }
+
+        #region 流程信息
+
+        /// <summary>
+        /// 工单开始时间(受理/接办时间=流程开启时间)
         /// </summary>
         public DateTime? StartTime { get; set; }
 
@@ -45,52 +84,122 @@ namespace Hotline.Share.Dtos.Order
         public DateTime? ExpiredTime { get; set; }
 
         /// <summary>
-        /// 工单办理完成时间,实际办理部门的办理时间(汇总节点的上一个非汇总节点办理完成时间,开启会签时清空该字段
+        /// 归档时间(暂为流程结束时间,因流程结束自动归档
         /// </summary>
-        public DateTime? CompleteTime { get; set; }
+        public DateTime? FiledTime { get; set; }
+
+        #region 实际办理信息(节点,部门,意见)
 
         /// <summary>
-        /// 归档时间(暂为流程结束时间,因流程结束自动归档
+        /// 实际办理节点code(会签状态此字段保存最外层会签发起节点code
         /// </summary>
-        public DateTime? FiledTime { get; set; }
+        public string? ActualHandleStepCode { get; set; }
 
         /// <summary>
-        /// 过期状态
+        /// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
         /// </summary>
-        public EExpiredStatus ExpiredStatus { get; set; }
+        public string? ActualHandleStepName { get; set; }
+
+        /// <summary>
+        /// 到达实际办理节点时间(stepBox创建时间)
+        /// </summary>
+        public DateTime? ActualHandleStepCreateTime { get; set; }
+
+        /// <summary>
+        /// 实际办理时间
+        /// </summary>
+        public DateTime? ActualHandleTime { get; set; }
+
+        /// <summary>
+        /// 实际办理人id
+        /// </summary>
+        public string? ActualHandlerId { get; set; }
+
+        /// <summary>
+        /// 实际办理人名称
+        /// </summary>
+        public string? ActualHandlerName { get; set; }
+
+        /// <summary>
+        /// 实际办理部门名称
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
+
+        /// <summary>
+        /// 实际办理部门编码
+        /// </summary>
+        public string? ActualHandleOrgCode { get; set; }
+
+        /// <summary>
+        /// 实际办理意见(办理中...or 最终办理意见)
+        /// </summary>
+        public string ActualOpinion { get; set; } = "办理中...";
 
         #endregion
 
-        public string CreationTime { get; set; }
+        #region 当前办理节点信息
 
-        public string StatusText => Status.GetDescription();
+        /// <summary>
+        /// 当前办理节点code(非会签:当前被指派节点,会签:会签发起节点)
+        /// </summary>
+        public string? CurrentStepCode { get; set; }
 
-        public string? ContactMask { get; set; }
+        /// <summary>
+        /// 当前节点名称
+        /// </summary>
+        public string? CurrentStepName { get; set; }
 
         /// <summary>
-        /// 工单编码(202201010001)
+        /// 到达当前节点时间(stepBox创建时间
         /// </summary>
-        public string No { get; set; }
+        public DateTime? CurrentStepCreateTime { get; set; }
+
+        #endregion
+
+        #region 一级部门
 
         /// <summary>
-        /// 受理人姓名
+        /// 一级部门code
         /// </summary>
-        public string EmployeeName { get; set; }
+        public string? OrgLevelOneCode { get; set; }
 
         /// <summary>
-        /// 受理人工号
+        /// 一级部门名称
         /// </summary>
-        public string? EmployeeStaffNo { get; set; }
+        public string? OrgLevelOneName { get; set; }
+
+        #endregion
+
+        #region 受理人(开启流程的话务员)
 
         /// <summary>
-        /// 处理方式(直办、交办)
+        /// 受理人id
         /// </summary>
-        public EProcessType ProcessType { get; set; }
+        public string? AcceptorId { get; set; }
 
         /// <summary>
-        /// 进展情况
+        /// 受理人名称
         /// </summary>
-        public EProgress Progress { get; set; }
+        public string? AcceptorName { get; set; }
+        
+        /// <summary>
+        /// 受理人工号
+        /// </summary>
+        public string? AcceptorStaffNo { get; set; }
+
+        #endregion
+
+        #endregion
+
+
+        #endregion
+
+        public string CreationTime { get; set; }
+
+        
+        public string? ContactMask { get; set; }
+        
+        public string SmsSendedText => SmsSended ? "已发送" : "未发送";
 
         public string WorkflowId { get; set; }
         public WorkflowDto Workflow { get; set; }
@@ -160,17 +269,13 @@ namespace Hotline.Share.Dtos.Order
         /// 来源渠道
         /// </summary>
         public string SourceChannel { get; set; }
+        public string SourceChannelCode { get; set; }
 
         /// <summary>
         /// 渠道为电话时,此字段存在
         /// </summary>
         public string? CallId { get; set; }
 
-        ///// <summary>
-        ///// 接线员工(userId)
-        ///// </summary>
-        //public string EmployeeId { get; set; }
-
         /// <summary>
         /// 来电号码
         /// </summary>
@@ -230,8 +335,6 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool SmsSended { get; set; }
 
-        public string SmsSendedText => SmsSended ? "已发送" : "未发送";
-
         /// <summary>
         /// 是否保密
         /// </summary>
@@ -262,6 +365,8 @@ namespace Hotline.Share.Dtos.Order
         public EEmergencyLevel EmergencyLevel { get; set; } = EEmergencyLevel.Normal;
 
         public string Title { get; set; }
+        
+        #region 热点
 
         /// <summary>
         /// 热点
@@ -275,6 +380,8 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string HotspotExternal { get; set; }
 
+        #endregion
+
         /// <summary>
         /// 事发时间
         /// </summary>

+ 10 - 7
src/Hotline.Share/Dtos/Order/QueryOrderDto.cs

@@ -4,7 +4,6 @@ using System.ComponentModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
-using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Requests;
@@ -89,6 +88,11 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public EPubState PubState { get; set; }
 
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string OrderTitle { get; set; }
+
         /// <summary>
         /// 发布人
         /// </summary>
@@ -123,13 +127,12 @@ namespace Hotline.Share.Dtos.Order
 
     }
 
-    public record QueryOrderVisitDto: PagedKeywordRequest
+    public record QueryOrderVisitDto : PagedKeywordRequest
     {
         public EVisitStateQuery VisitState { get; set; }
-
     }
 
-    public record VisitDetailListDto: PagedKeywordRequest
+    public record VisitDetailListDto : PagedKeywordRequest
     {
         public EVisitStateQuery VisitState { get; set; }
     }
@@ -208,7 +211,7 @@ namespace Hotline.Share.Dtos.Order
     }
 
 
-    public record CanDelayOrderListDto: PagedKeywordRequest
+    public record CanDelayOrderListDto : PagedKeywordRequest
     {
 
     }
@@ -227,7 +230,7 @@ namespace Hotline.Share.Dtos.Order
         public List<string> FileIds { get; set; }
     }
 
-    public record DelayListDto: PagedKeywordRequest
+    public record DelayListDto : PagedKeywordRequest
     {
         /// <summary>
         /// 是否已办 true:已办 false:待办
@@ -254,7 +257,7 @@ namespace Hotline.Share.Dtos.Order
         /// 未回访
         /// </summary>
         [Description("未回访")]
-        NoVisit =2,
+        NoVisit = 2,
     }
 
 

+ 13 - 3
src/Hotline.Share/Enums/FlowEngine/EWorkflowTraceStatus.cs

@@ -9,8 +9,6 @@ namespace Hotline.Share.Enums.FlowEngine
 {
     public enum EWorkflowTraceStatus
     {
-        //正常流转、退回、撤回、跳转、办理中
-
         ///// <summary>
         ///// 流程开始
         ///// </summary>
@@ -33,12 +31,24 @@ namespace Hotline.Share.Enums.FlowEngine
         /// 退回
         /// </summary>
         [Description("退回")]
-        Back = 3,
+        Previous = 3,
 
         /// <summary>
         /// 跳转
         /// </summary>
         [Description("跳转")]
         Jump = 4,
+
+        /// <summary>
+        /// 撤销(发起人操作)
+        /// </summary>
+        [Description("撤销")]
+        Cancel = 5,
+
+        /// <summary>
+        /// 重办
+        /// </summary>
+        [Description("重办")]
+        Redo = 6,
     }
 }

+ 1 - 1
src/Hotline/FlowEngine/Definitions/StepBasic.cs

@@ -1,4 +1,4 @@
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
 

+ 1 - 1
src/Hotline/FlowEngine/FlowAssignInfo.cs

@@ -1,5 +1,5 @@
 using Hotline.FlowEngine.Workflows;
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using XF.Domain.Entities;
 
 namespace Hotline.FlowEngine;

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

@@ -29,7 +29,7 @@ public record RecallNotify(Workflow Workflow, NextWorkflowDto Dto, bool IsOrgToC
 
 public record JumpNotify(Workflow Workflow, NextWorkflowDto Dto, FlowAssignInfo FlowAssignInfo, bool IsCenterToOrg, bool IsOrgToCenter) : INotification;
 
-public record EndWorkflowNotify(Workflow Workflow) : INotification;
+public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace) : INotification;
 
 public record TerminalWorkflowNotify(Workflow Workflow) : INotification;
 

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

@@ -1,5 +1,6 @@
 using Hotline.FlowEngine.Definitions;
 using Hotline.FlowEngine.WfModules;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
 using XF.Domain.Entities;

+ 1 - 8
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -1,4 +1,5 @@
 using Hotline.FlowEngine.Definitions;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
@@ -184,12 +185,4 @@ public abstract class StepBasicEntity : CreationEntity
     public bool IsOrg() => BusinessProperty is EBusinessProperty.Department;
 
     #endregion
-}
-
-public class StepExtension
-{
-    /// <summary>
-    /// 省延期申请
-    /// </summary>
-    public bool? ApplyDelayProvince { get; set; }
 }

+ 9 - 2
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -1,6 +1,6 @@
 using Hotline.FlowEngine.Definitions;
 using Hotline.Orders;
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using SqlSugar;
@@ -229,6 +229,12 @@ public class Workflow : CreationEntity
     [SugarColumn(IsNullable = true)]
     public string? AcceptorName { get; set; }
 
+    /// <summary>
+    /// 受理人工号
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public string? AcceptorStaffNo { get; set; }
+
     #endregion
 
     [Navigate(NavigateType.OneToOne, nameof(DefinitionId))]
@@ -529,10 +535,11 @@ public class Workflow : CreationEntity
     /// <summary>
     /// 更新受理人信息
     /// </summary>
-    public void UpdateAcceptor(string userId, string userName)
+    public void UpdateAcceptor(string userId, string userName, string? staffNo)
     {
         AcceptorId = userId;
         AcceptorName = userName;
+        AcceptorStaffNo = staffNo;
     }
 
     /// <summary>

+ 26 - 17
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -2,6 +2,7 @@
 using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WfModules;
 using Hotline.Settings;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
@@ -124,7 +125,7 @@ namespace Hotline.FlowEngine.Workflows
                 workflow.StartCountersign(firstStepBox.Code, counterSignType);
 
             //更新受理人信息
-            workflow.UpdateAcceptor(_sessionContext.RequiredUserId, _sessionContext.UserName);
+            workflow.UpdateAcceptor(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo);
 
             workflow.UpdateHandlers(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgCode,
             flowAssignInfo.FlowAssignType, flowAssignInfo.HandlerObjects);
@@ -320,13 +321,13 @@ namespace Hotline.FlowEngine.Workflows
                 //create endStep
                 var (_, endStep) = await CreateEndStepAsync(workflow, nextStepBoxDefine, currentStepBox, currentStep, cancellationToken);
                 //update endTrace
-                await NextTraceAsync(workflow, dto, endStep, cancellationToken);
+                var endTrace = await NextTraceAsync(workflow, dto, endStep, cancellationToken);
 
                 workflow.Complete();
 
                 await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
-                await _mediator.Publish(new EndWorkflowNotify(workflow), cancellationToken);
+                await _mediator.Publish(new EndWorkflowNotify(workflow, endTrace), cancellationToken);
                 return;
             }
 
@@ -450,7 +451,7 @@ namespace Hotline.FlowEngine.Workflows
             await ResetStepBoxStatusAsync(prevStepBox, cancellationToken);
 
             //复制上一个节点为待接办
-            var newPrevStep = await CreateByAsync(workflow, prevStep, cancellationToken);
+            var newPrevStep = await CreatePrevStepAsync(workflow, prevStep, cancellationToken);
 
             //remove workflow.steps
             await _workflowStepRepository.RemoveRangeAsync(new List<WorkflowStep> { currentStepBox, currentStep, prevStep }, cancellationToken);
@@ -773,7 +774,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 复制一个节点为待接办
         /// </summary>
-        private async Task<WorkflowStep> CreateByAsync(Workflow workflow, WorkflowStep step, CancellationToken cancellationToken)
+        private async Task<WorkflowStep> CreatePrevStepAsync(Workflow workflow, WorkflowStep step, CancellationToken cancellationToken)
         {
             step.Reset();
             var newStep = _mapper.Map<WorkflowStep>(step);
@@ -787,7 +788,7 @@ namespace Hotline.FlowEngine.Workflows
             newStep.IsStartedCountersignComplete = step.IsStartedCountersignComplete;
             await _workflowStepRepository.AddAsync(newStep, cancellationToken);
 
-            await CreateTraceAsync(workflow, newStep, EWorkflowTraceStatus.Back, cancellationToken);
+            await CreateTraceAsync(workflow, newStep, EWorkflowTraceStatus.Previous, cancellationToken);
 
             return newStep;
         }
@@ -1049,7 +1050,8 @@ namespace Hotline.FlowEngine.Workflows
                 throw UserFriendlyException.SameMessage("无办理权限");
         }
 
-        private async Task<(WorkflowStep startStepBox, WorkflowStep startStep, WorkflowStep firstStepBox)> CreateStartAndFirstStepAsync(Workflow workflow, BasicWorkflowDto dto, CancellationToken cancellationToken)
+        private async Task<(WorkflowStep startStepBox, WorkflowStep startStep, WorkflowStep firstStepBox)> CreateStartAndFirstStepAsync(
+            Workflow workflow, BasicWorkflowDto dto, CancellationToken cancellationToken)
         {
             if (workflow.StepBoxes.Any())
                 throw UserFriendlyException.SameMessage("无法重复创建开始节点");
@@ -1067,7 +1069,7 @@ namespace Hotline.FlowEngine.Workflows
 
             //开始节点的下一个节点(工单业务:话务员节点)
             var firstStepCode = workflow.Definition.FindStartStep().NextSteps.First().Code;
-            var startStep = await CreateStartSubStepAsync(handler, firstStepCode, startStepBox, cancellationToken);
+            var startStep = await CreateStartSubStepAsync(handler, firstStepCode, startStepBox, dto, cancellationToken);
 
             //开始节点trace
             await CreateTraceAsync(workflow, startStep, cancellationToken: cancellationToken);
@@ -1156,7 +1158,8 @@ namespace Hotline.FlowEngine.Workflows
         {
             //开始节点既不发起会签,也不处于会签中
             var subStep = CreateSubStep(stepBox, new List<IdName> { handler }, dto.NextStepCode, dto.NextMainHandler,
-                null, null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Now);
+                null, null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Now,
+                _mapper.Map<StepExtension>(dto.Extension));
             subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgCode, _sessionContext.OrgName);
             //step办理状态
@@ -1176,11 +1179,13 @@ namespace Hotline.FlowEngine.Workflows
             IdName handler,
             string nextStepCode,
             WorkflowStep stepBox,
+            BasicWorkflowDto dto,
             CancellationToken cancellationToken)
         {
             //开始节点既不发起会签,也不处于会签中
             var subStep = CreateSubStep(stepBox, new List<IdName> { handler }, nextStepCode, null,
-                null, null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Today);
+                null, null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Today,
+                _mapper.Map<StepExtension>(dto.Extension));
             subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgCode, _sessionContext.OrgName);
 
@@ -1203,7 +1208,7 @@ namespace Hotline.FlowEngine.Workflows
             CancellationToken cancellationToken)
         {
             var subStep = CreateSubStep(currentStepBox, new List<IdName> { handler }, null, null, prevStep.Id,
-                null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Today);
+                null, EWorkflowStepStatus.Completed, EStepCountersignStatus.None, DateTime.Today, new());
             subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.RequiredOrgCode,
                 _sessionContext.OrgName);
             subStep.Complete(_sessionContext.RequiredUserId, _sessionContext.UserName,
@@ -1237,17 +1242,18 @@ namespace Hotline.FlowEngine.Workflows
             var countersignId = isPrevStartCountersign ? prevStep.StartCountersignId : prevStep.CountersignId;
 
             List<WorkflowStep> subSteps;
+            var stepExtension = _mapper.Map<StepExtension>(dto.Extension);
             if (stepBoxDefine.HandlerType is EHandlerType.AssignUser or EHandlerType.AssignOrg)
             {
                 subSteps = CreateSubSteps(isPrevStartCountersign, stepBox, stepBox.HandlerClassifies, dto.NextStepCode, dto.NextMainHandler,
-                    prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime);
+                    prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime, stepExtension);
             }
             else
             {
                 if (stepBoxDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
                     throw new UserFriendlyException("未指定节点处理者");
                 subSteps = CreateSubSteps(isPrevStartCountersign, stepBox, dto.NextHandlers, dto.NextStepCode, dto.NextMainHandler,
-                    prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime);
+                    prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime, stepExtension);
             }
             stepBox.Steps.AddRange(subSteps);
             await _workflowStepRepository.AddRangeAsync(subSteps, cancellationToken);
@@ -1316,7 +1322,8 @@ namespace Hotline.FlowEngine.Workflows
             string? countersignId,
             EWorkflowStepStatus stepStatus,
             EStepCountersignStatus countersignStatus,
-            DateTime expiredTime)
+            DateTime expiredTime,
+            StepExtension extension)
         {
             if (countersignStatus is EStepCountersignStatus.None && !string.IsNullOrEmpty(countersignId))
                 throw UserFriendlyException.SameMessage("非法参数");
@@ -1330,7 +1337,7 @@ namespace Hotline.FlowEngine.Workflows
                 foreach (var handler in handlers)
                 {
                     var step = CreateSubStep(stepBox, new List<IdName> { handler }, nextStepCode, nextMainHandler,
-                        prevStepId, countersignId, stepStatus, countersignStatus, expiredTime);
+                        prevStepId, countersignId, stepStatus, countersignStatus, expiredTime, extension);
 
                     steps.Add(step);
                 }
@@ -1338,7 +1345,7 @@ namespace Hotline.FlowEngine.Workflows
             else
             {
                 var step = CreateSubStep(stepBox, handlers, nextStepCode, nextMainHandler,
-                    prevStepId, countersignId, stepStatus, countersignStatus, expiredTime);
+                    prevStepId, countersignId, stepStatus, countersignStatus, expiredTime, extension);
 
                 steps.Add(step);
             }
@@ -1355,7 +1362,8 @@ namespace Hotline.FlowEngine.Workflows
             string? countersignId,
             EWorkflowStepStatus stepStatus,
             EStepCountersignStatus countersignStatus,
-            DateTime expiredTime)
+            DateTime expiredTime,
+            StepExtension extension)
         {
             if (!handlers.Any())
                 throw new UserFriendlyException("非法参数");
@@ -1373,6 +1381,7 @@ namespace Hotline.FlowEngine.Workflows
             step.StepCountersignStatus = countersignStatus;
             step.ExpiredTime = expiredTime;
             step.TimeLimit = GetTimeLimit("");//todo 过期时间
+            step.Extension = extension;
 
             return step;
         }

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

@@ -1,4 +1,4 @@
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
 

+ 16 - 9
src/Hotline/Orders/Order.cs

@@ -31,11 +31,6 @@ namespace Hotline.Orders
         [SugarColumn(IsNullable = true)]
         public string? CallId { get; set; }
 
-        /// <summary>
-        /// 接线员工(userId)
-        /// </summary>
-        public string EmployeeId { get; set; }
-
         /// <summary>
         /// 来电号码
         /// </summary>
@@ -258,6 +253,12 @@ namespace Hotline.Orders
         /// </summary>
         public DateTime? ExpiredTimeProvince { get; set; }
 
+        /// <summary>
+        /// 110工单编号(从110来的和推送给110的都用该字段记录唯一标识)
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string? No110 { get; set; }
+
         #endregion
 
         #region 流程信息
@@ -384,6 +385,12 @@ namespace Hotline.Orders
         [SugarColumn(IsNullable = true)]
         public string? AcceptorName { get; set; }
 
+        /// <summary>
+        /// 受理人工号
+        /// </summary>
+        [SugarColumn(IsNullable = true)]
+        public string? AcceptorStaffNo { get; set; }
+
         #endregion
 
         #endregion
@@ -392,10 +399,10 @@ namespace Hotline.Orders
     public partial class Order
     {
         /// <summary>
-        /// 接线员(服务人)
+        /// 受理人
         /// </summary>
-        [Navigate(NavigateType.OneToOne, nameof(EmployeeId))]
-        public User Employee { get; set; }
+        [Navigate(NavigateType.OneToOne, nameof(AcceptorId))]
+        public User Acceptor { get; set; }
 
         /// <summary>
         /// 热点
@@ -443,7 +450,7 @@ namespace Hotline.Orders
 
         public void Init(string employeeId)
         {
-            EmployeeId = employeeId;
+            AcceptorId = employeeId;
             if (!string.IsNullOrEmpty(Contact))
                 ContactMask = Contact.MaskPhoneNumber();
             Status = EOrderStatus.WaitForAccept;

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

@@ -78,7 +78,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
             throw UserFriendlyException.SameMessage("无效工单编号");
         var order = await _orderRepository.Queryable()
             .Includes(d => d.Hotspot)
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .FirstAsync(d => d.Id == orderId, cancellationToken);
 
         if (order == null)
@@ -94,7 +94,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
             throw UserFriendlyException.SameMessage("无效流程编号");
         var order = await _orderRepository.Queryable()
             .Includes(d => d.Hotspot)
-            .Includes(d => d.Employee)
+            .Includes(d => d.Acceptor)
             .FirstAsync(d => d.WorkflowId == workflowId);
         if (order == null)
             throw new UserFriendlyException($"无效流程编号, workflowId: {workflowId}", "无效流程编号");

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

@@ -1,4 +1,4 @@
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using Hotline.Share.Enums.Order;
 using Hotline.Users;
 using SqlSugar;

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

@@ -1,5 +1,5 @@
 using Hotline.Settings.Hotspots;
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos;
 using Hotline.Share.Enums.Order;
 using SqlSugar;
 using XF.Domain.Repository;

+ 5 - 0
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -124,4 +124,9 @@ public class SysDicTypeConsts
     /// 流程节点属性
     /// </summary>
     public const string WorkflowStepProperty = "WorkflowStepProperty";
+
+    /// <summary>
+    /// 工单重办理由
+    /// </summary>
+    public const string OrderRedoReason = "OrderRedoReason";
 }