xf 1 жил өмнө
parent
commit
d812eb2d07

+ 20 - 20
src/Hotline.Api/Controllers/ArticleController.cs

@@ -26,7 +26,7 @@ using XF.Utility.EnumExtensions;
 namespace Hotline.Api.Controllers
 {
 
-    public class ArticleController: BaseController
+    public class ArticleController : BaseController
     {
         private readonly IRepository<Bulletin> _bulletinRepository;
         private readonly IMapper _mapper;
@@ -66,7 +66,7 @@ namespace Hotline.Api.Controllers
             var list = await _userRepository.Queryable(includeDeleted: false)
                 .Includes(d => d.Account)
                 .Includes(d => d.Organization)
-                .OrderByDescending(x=>x.CreationTime)
+                .OrderByDescending(x => x.CreationTime)
                 .ToListAsync();
             return new List<UserDto>(_mapper.Map<IReadOnlyList<UserDto>>(list));
         }
@@ -87,8 +87,8 @@ namespace Hotline.Api.Controllers
                 .WhereIF(dto.CircularTimeEnd.HasValue, d => d.CircularTime <= dto.CircularTimeEnd)
                 .WhereIF(dto.CircularState != null, d => d.CircularState == dto.CircularState)
                 //.WhereIF(dto.IsRead!=null,d=>d.CircularReadGroups.Any(x=>x.IsRead == dto.IsRead) && (d.CircularReadGroups.Any(x => x.UserId == _sessionContext.RequiredUserId) || d.CircularReadGroups.Any(x => x.OrgId == _sessionContext.RequiredOrgId)))
-                .WhereIF(dto.IsRead != null,d=> (d.CircularReadGroups.Any(x=>x.IsRead == dto.IsRead && x.UserId == _sessionContext.UserId)) ||
-                (d.CircularReadGroups.Any(x=>x.IsRead == dto.IsRead && x.OrgId == _sessionContext.OrgId)))
+                .WhereIF(dto.IsRead != null, d => (d.CircularReadGroups.Any(x => x.IsRead == dto.IsRead && x.UserId == _sessionContext.UserId)) ||
+                (d.CircularReadGroups.Any(x => x.IsRead == dto.IsRead && x.OrgId == _sessionContext.OrgId)))
                 //.Where(d=>d.CircularReadGroups.Any(x=> x.UserId == _sessionContext.RequiredUserId) || d.CircularReadGroups.Any(x=>x.OrgId == _sessionContext.RequiredOrgId))
                 .OrderByDescending(d => d.CreationTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
@@ -105,13 +105,13 @@ namespace Hotline.Api.Controllers
         [HttpGet("circular/query")]
         public async Task<PagedDto<CircularDto>> QueryCircularList([FromQuery] QueryCircularListRequestDto dto)
         {
-            var (total,items) = await _circularRepository.Queryable()
-                .Includes(x=>x.CircularReadGroups)
+            var (total, items) = await _circularRepository.Queryable()
+                .Includes(x => x.CircularReadGroups)
                 .WhereIF(!string.IsNullOrEmpty(dto.CircularTypeId), d => d.CircularTypeId == dto.CircularTypeId)
                 .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
                 .WhereIF(dto.CircularTimeStart.HasValue, d => d.CircularTime >= dto.CircularTimeStart)
                 .WhereIF(dto.CircularTimeEnd.HasValue, d => d.CircularTime <= dto.CircularTimeEnd)
-                .WhereIF(dto.CircularState != null,d=>d.CircularState == dto.CircularState)
+                .WhereIF(dto.CircularState != null, d => d.CircularState == dto.CircularState)
                 .OrderByDescending(d => d.CreationTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
             return new PagedDto<CircularDto>(total, _mapper.Map<IReadOnlyList<CircularDto>>(items));
@@ -162,9 +162,9 @@ namespace Hotline.Api.Controllers
                 var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                 startDto.DefinitionModuleCode = WorkflowModuleConsts.CircularApply;
                 startDto.Title = model.Title;
-                var workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
+                var workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
                 model.WorkflowId = workFlowId;
-                await _circularRepository.UpdateAsync(model,HttpContext.RequestAborted);
+                await _circularRepository.UpdateAsync(model, HttpContext.RequestAborted);
             }
             catch (Exception ex)
             {
@@ -220,7 +220,7 @@ namespace Hotline.Api.Controllers
             {
                 //个人阅读
                 var readGroup = model.CircularReadGroups.FirstOrDefault(x => x.UserId == _sessionContext.RequiredUserId && !x.IsRead);
-                if (readGroup!=null)
+                if (readGroup != null)
                 {
                     readGroup.IsRead = true;
                     readGroup.ReadTime = DateTime.Now;
@@ -232,14 +232,14 @@ namespace Hotline.Api.Controllers
                     model.ReadedNum++;
                     await _circularRepository.UpdateAsync(model, HttpContext.RequestAborted);
                     //处理计数
-                    await _circularRecordDomainService.RecordUserHandle(new List<string> { _sessionContext.RequiredUserId } , false,cancellationToken : HttpContext.RequestAborted);
+                    await _circularRecordDomainService.RecordUserHandle(new List<string> { _sessionContext.RequiredUserId }, false, cancellationToken: HttpContext.RequestAborted);
                 }
             }
             else
             {
                 //部门阅读
                 var readGroup = model.CircularReadGroups.FirstOrDefault(x => x.OrgId == _sessionContext.RequiredOrgId && !x.IsRead);
-                if (readGroup!=null)
+                if (readGroup != null)
                 {
                     readGroup.IsRead = true;
                     readGroup.ReadTime = DateTime.Now;
@@ -266,7 +266,7 @@ namespace Hotline.Api.Controllers
         public async Task<CircularRecordDto> QueryMegCount()
         {
             var list = await _circularRecordRepository.Queryable().Where(x => x.UserId == _sessionContext.UserId || x.OrgId == _sessionContext.OrgId).ToListAsync();
-            if (list!=null && list.Count>0)
+            if (list != null && list.Count > 0)
             {
                 var rsp = new CircularRecordDto();
                 rsp.OrgCount = list.FirstOrDefault(x => x.CircularType == ECircularType.Org)?.RecordCount ?? 0;
@@ -299,14 +299,14 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.QueryBulletinList)]
         [HttpGet("bulletin/query")]
-        public async Task<PagedDto<BulletinDto>> QueryBulletinList([FromQuery]QueryBulletinListRequestDto dto)
+        public async Task<PagedDto<BulletinDto>> QueryBulletinList([FromQuery] QueryBulletinListRequestDto dto)
         {
-            var (total,items) = await _bulletinRepository.Queryable()
+            var (total, items) = await _bulletinRepository.Queryable()
                 .WhereIF(!string.IsNullOrEmpty(dto.BulletinTypeId), d => d.BulletinTypeId == dto.BulletinTypeId)
                 .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
                 .WhereIF(dto.BulletinTimeStart.HasValue, d => d.BulletinTime >= dto.BulletinTimeStart)
                 .WhereIF(dto.BulletinTimeEnd.HasValue, d => d.BulletinTime <= dto.BulletinTimeEnd)
-                .WhereIF(dto.BulletinState!=null ,d=>d.BulletinState == dto.BulletinState)
+                .WhereIF(dto.BulletinState != null, d => d.BulletinState == dto.BulletinState)
                 .OrderByDescending(d => d.CreationTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
@@ -323,7 +323,7 @@ namespace Hotline.Api.Controllers
         public async Task<BulletinDto> BulletinEntity(string id)
         {
             var model = await _bulletinRepository.Queryable()
-                .FirstAsync(x=>x.Id == id, HttpContext.RequestAborted);
+                .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
             return _mapper.Map<BulletinDto>(model);
         }
 
@@ -334,7 +334,7 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [Permission(EPermission.AddBulletin)]
         [HttpPost("bulletin/add")]
-        public async Task AddBulletin([FromBody]BulletinFlowDto dto)
+        public async Task AddBulletin([FromBody] BulletinFlowDto dto)
         {
             var model = _mapper.Map<Bulletin>(dto.Data);
             model.BulletinState = Share.Enums.Article.EBulletinState.InReview;
@@ -345,7 +345,7 @@ namespace Hotline.Api.Controllers
                 var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                 startDto.DefinitionModuleCode = WorkflowModuleConsts.BulletinApply;
                 startDto.Title = model.Title;
-                string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
+                string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
                 model.WorkflowId = workFlowId;
                 await _bulletinRepository.UpdateAsync(model, HttpContext.RequestAborted);
             }
@@ -401,7 +401,7 @@ namespace Hotline.Api.Controllers
 
         #endregion
 
-       
+
 
     }
 }

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

@@ -728,7 +728,7 @@ namespace Hotline.Api.Controllers
 
 			dto.DefinitionModuleCode = moduleCode;
 			dto.Title = knowledge.Title;
-		    await _workflowApplication.StartWorkflowAsync(dto, flowId, HttpContext.RequestAborted);
+		    await _workflowApplication.StartWorkflowAsync(dto, flowId, cancellationToken: HttpContext.RequestAborted);
 		}
 		#endregion
 

+ 29 - 27
src/Hotline.Api/Controllers/OrderController.cs

@@ -755,7 +755,7 @@ public class OrderController : BaseController
             var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
             startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderDelay;
             startDto.Title = model.DelayReason;
-            string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
+            string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
             model.WorkflowId = workFlowId;
             await _orderDelayRepository.UpdateAsync(model, HttpContext.RequestAborted);
         }
@@ -978,7 +978,9 @@ public class OrderController : BaseController
     [HttpPost("screen/startflow")]
     public async Task StartFlow([FromBody] ScreenStartFlowDto dto)
     {
-        int screenCount = await _orderScreenRepository.CountAsync(x => x.VisitDetailId == dto.Data.VisitDetailId && (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval));
+        int screenCount = await _orderScreenRepository.CountAsync(x =>
+            x.VisitDetailId == dto.Data.VisitDetailId &&
+            (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval));
         if (screenCount > 0)
             throw UserFriendlyException.SameMessage("该工单已提起甄别申请,正在审批过程中,不能申请");
 
@@ -1004,7 +1006,7 @@ public class OrderController : BaseController
             var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
             startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderScreen;
             startDto.Title = dto.Data.Content;
-            workflowId = await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
+            workflowId = await _workflowApplication.StartWorkflowAsync(startDto, id, cancellationToken: HttpContext.RequestAborted);
             var screen = await _orderScreenRepository.GetAsync(id, HttpContext.RequestAborted);
             if (screen != null)
             {
@@ -1458,7 +1460,7 @@ public class OrderController : BaseController
             .Includes(d => d.OrderReport)
             .Includes(d => d.OrderDelays)
             .Includes(d => d.OrderScreens)
-            .Includes(d => d.OrderVisits ,x=>x.OrderVisitDetails)
+            .Includes(d => d.OrderVisits, x => x.OrderVisitDetails)
             .FirstAsync(d => d.Id == id);
         if (order == null)
             return new();
@@ -1581,28 +1583,28 @@ public class OrderController : BaseController
         await _orderRepository.UpdateOrderNavAsync(order, HttpContext.RequestAborted);
     }
 
-    /// <summary>
-    /// 开始流程
-    /// </summary>
-    /// <param name="id">工单id</param>
-    /// <param name="dto">流程开启参数</param>
-    /// <returns></returns>
-    [HttpPost("{id}/startflow")]
-    [Obsolete]
-    public async Task StartFlow(string id, [FromBody] StartWorkflowDto dto)
-    {
-        var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
-        if (order == null)
-            throw UserFriendlyException.SameMessage("无效工单编号");
-        if (order.Status != EOrderStatus.WaitForAccept || !string.IsNullOrEmpty(order.WorkflowId))
-            throw UserFriendlyException.SameMessage("工单已发起流程");
-
-        dto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
-        dto.Title = order.Title;
-        order.StartManageFlow();
-        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-        await _workflowApplication.StartWorkflowAsync(dto, order.Id, HttpContext.RequestAborted);
-    }
+    ///// <summary>
+    ///// 开始流程
+    ///// </summary>
+    ///// <param name="id">工单id</param>
+    ///// <param name="dto">流程开启参数</param>
+    ///// <returns></returns>
+    //[HttpPost("{id}/startflow")]
+    //[Obsolete]
+    //public async Task StartFlow(string id, [FromBody] StartWorkflowDto dto)
+    //{
+    //    var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
+    //    if (order == null)
+    //        throw UserFriendlyException.SameMessage("无效工单编号");
+    //    if (order.Status != EOrderStatus.WaitForAccept || !string.IsNullOrEmpty(order.WorkflowId))
+    //        throw UserFriendlyException.SameMessage("工单已发起流程");
+
+    //    dto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
+    //    dto.Title = order.Title;
+    //    order.StartManageFlow();
+    //    await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+    //    await _workflowApplication.StartWorkflowAsync(dto, order.Id, HttpContext.RequestAborted);
+    //}
 
     /// <summary>
     /// 开始工单办理流程
@@ -1629,7 +1631,7 @@ public class OrderController : BaseController
             var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
             startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
             startDto.Title = dto.Data.Title;
-            await _workflowApplication.StartWorkflowAsync(startDto, id, HttpContext.RequestAborted);
+            await _workflowApplication.StartWorkflowAsync(startDto, id, expiredTime, HttpContext.RequestAborted);
         }
         catch (Exception e)
         {

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

@@ -60,7 +60,7 @@ namespace Hotline.Api.Controllers
         private readonly IWexClient _wexClient;
         private readonly IWexTelGroupRepository _wexTelGroupRepository;
         private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
-        
+
 
         public PbxController(
             ITelRepository telRepository,
@@ -114,7 +114,7 @@ namespace Hotline.Api.Controllers
             _systemDicDataCacheManager = systemDicDataCacheManager;
         }
 
-        
+
 
 
         #region 话机
@@ -295,7 +295,7 @@ namespace Hotline.Api.Controllers
                 var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
                 startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
                 startWorkflowDto.Title = dto.Reason;
-                await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, HttpContext.RequestAborted);
+                await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
             }
         }
 
@@ -331,7 +331,7 @@ namespace Hotline.Api.Controllers
             var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
             startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
             startWorkflowDto.Title = dto.Reason;
-            await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, HttpContext.RequestAborted);
+            await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
         }
 
 
@@ -448,7 +448,7 @@ namespace Hotline.Api.Controllers
             };
 
             return rsp;
-        } 
+        }
 
 
 

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

@@ -2,6 +2,7 @@
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Definition;
+using Hotline.Share.Dtos.Settings;
 
 namespace Hotline.Application.FlowEngine
 {
@@ -10,7 +11,7 @@ namespace Hotline.Application.FlowEngine
         /// <summary>
         /// 开始流程
         /// </summary>
-        Task<string> StartWorkflowAsync(StartWorkflowDto dto, string externalId, CancellationToken cancellationToken);
+        Task<string> StartWorkflowAsync(StartWorkflowDto dto, string externalId, TimeResult? expiredTime = null, CancellationToken cancellationToken = default);
 
         /// <summary>
         /// 流转至下一节点(节点办理)
@@ -41,7 +42,7 @@ namespace Hotline.Application.FlowEngine
         /// 查询节点配置可选参数
         /// </summary>
         Task<IReadOnlyList<Kv>> GetNextStepOptionsAsync(StepDefineBasic stepDefine, CancellationToken cancellationToken);
-        
+
         ////////
 
         /// <summary>

+ 17 - 2
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -86,7 +86,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         _workflowTraceRepository = workflowTraceRepository;
     }
 
-    public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, string externalId, CancellationToken cancellationToken)
+    public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, string externalId, TimeResult? expiredTime = null, CancellationToken cancellationToken = default)
     {
         var validator = new StartWorkflowDtoValidator();
         var validResult = validator.Validate(dto);
@@ -127,9 +127,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             if (dto.BackToCountersignEnd)
                 throw new UserFriendlyException("下一节点不允许发起会签");
         }
+
         //todo
         var workflow = await _workflowDomainService.CreateWorkflowAsync(wfModule, dto.Title,
-            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, externalId, "", DateTime.Now, cancellationToken);
+            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, externalId, expiredTime?.RuleStr,
+            expiredTime?.EndTime, cancellationToken);
 
         //startstep
         var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
@@ -637,6 +639,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 Key = stepDefine.Code,
                 Value = stepDefine.Name,
                 InputRealHandler = stepDefine.StepType == EStepType.Summary,
+                BusinessType = stepDefine.BusinessType,
                 Items = handlers
             });
         }
@@ -823,6 +826,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             Key = prevStep.Code,
             Value = text,//parentStep.Name,//todo name不对,目前为definition.name,需改为x级部门办理
             BackToCountersignEnd = true,
+            BusinessType = prevStep.BusinessType,
             Items = handlers//new List<Kv> { new(prevStep.HandlerId, prevStep.HandlerName) },
         };
     }
@@ -866,6 +870,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     {
         int orgLevel;
         List<Kv> items;
+        EBusinessType businessType;
         var levelOneOrgCode = _sessionContext.RequiredOrgId.GetHigherOrgCode();
         switch (policy)
         {
@@ -879,6 +884,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                         .Where(d => d.IsCenter)
                         .Select(d => new Kv { Key = d.Id, Value = d.Name })
                         .ToListAsync(cancellationToken);
+                    businessType = EBusinessType.Center;
                 }
                 else
                 {
@@ -886,6 +892,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                         .Where(d => !d.IsCenter && d.Level == orgLevel && d.Id.StartsWith(levelOneOrgCode))
                         .Select(d => new Kv { Key = d.Id, Value = d.Name })
                         .ToListAsync(cancellationToken);
+                    businessType = EBusinessType.Department;
                 }
                 break;
             case EDynamicPolicy.OrgUp:
@@ -895,6 +902,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     .Where(d => d.Level == orgLevel && d.Id.StartsWith(levelOneOrgCode))
                     .Select(d => new Kv { Key = d.Id, Value = d.Name })
                     .ToListAsync(cancellationToken);
+                businessType = _sessionContext.OrgIsCenter
+                    ? EBusinessType.Center
+                    : _sessionContext.OrgLevel == 1
+                        ? EBusinessType.Center
+                        : EBusinessType.Department;
                 break;
             case EDynamicPolicy.OrgDownCenterTop:
                 if (_sessionContext.OrgIsCenter)
@@ -913,6 +925,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                         .Select(d => new Kv { Key = d.Id, Value = d.Name })
                         .ToListAsync(cancellationToken);
                 }
+                businessType = EBusinessType.Department;
                 break;
             case EDynamicPolicy.OrgDown:
                 orgLevel = _sessionContext.OrgLevel + 1;
@@ -920,6 +933,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     .Where(d => d.Level == orgLevel && d.Id.StartsWith(levelOneOrgCode))
                     .Select(d => new Kv { Key = d.Id, Value = d.Name })
                     .ToListAsync(cancellationToken);
+                businessType = EBusinessType.Department;
                 break;
             default:
                 throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
@@ -929,6 +943,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         {
             Key = orgLevel.ToString(),
             Value = orgLevel == 0 ? "热线中心" : $"{orgLevel.ToChinese()}级部门",
+            BusinessType = businessType,
             Items = items
         };
     }

+ 51 - 29
src/Hotline.Application/Handlers/FlowEngine/NextStepHandler.cs

@@ -1,15 +1,20 @@
 using DotNetCore.CAP;
 using Hotline.Application.FlowEngine;
+using Hotline.FlowEngine;
 using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
+using Hotline.FlowEngine.Workflows;
 using Hotline.KnowledgeBase;
 using Hotline.Orders;
 using Hotline.Repository.SqlSugar.CallCenter;
 using Hotline.Repository.SqlSugar.Orders;
 using Hotline.Settings;
+using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Settings;
 using Hotline.Share.Mq;
 using MapsterMapper;
 using MediatR;
@@ -26,6 +31,8 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
     private readonly IOrderDomainService _orderDomainService;
     private readonly IKnowledgeDomainService _knowledgeDomainService;
     private readonly IOrderRepository _orderRepository;
+    private readonly ITimeLimitDomainService _timeLimitDomainService;
+    private readonly IWorkflowDomainService _workflowDomainService;
     private readonly ICapPublisher _capPublisher;
     private readonly IMapper _mapper;
     private readonly ILogger<NextStepHandler> _logger;
@@ -35,6 +42,8 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
         IOrderDomainService orderDomainService,
         IKnowledgeDomainService knowledgeDomainService,
         IOrderRepository orderRepository,
+        ITimeLimitDomainService timeLimitDomainService,
+        IWorkflowDomainService workflowDomainService,
         ICapPublisher capPublisher,
         IMapper mapper,
         ILogger<NextStepHandler> logger,
@@ -43,6 +52,8 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
         _orderDomainService = orderDomainService;
         _knowledgeDomainService = knowledgeDomainService;
         _orderRepository = orderRepository;
+        _timeLimitDomainService = timeLimitDomainService;
+        _workflowDomainService = workflowDomainService;
         _capPublisher = capPublisher;
         _mapper = mapper;
         _logger = logger;
@@ -62,8 +73,8 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
         if (!string.IsNullOrEmpty(notification.Trace.Tag))
             currentTag = System.Text.Json.JsonSerializer.Deserialize<DefinitionTag>(notification.Trace.Tag);
         DefinitionTag? nextTag = null;
-        if (!string.IsNullOrEmpty(notification.nextStepDefine.Tag))
-            nextTag = System.Text.Json.JsonSerializer.Deserialize<DefinitionTag>(notification.nextStepDefine.Tag);
+        if (!string.IsNullOrEmpty(notification.NextStepDefine.Tag))
+            nextTag = System.Text.Json.JsonSerializer.Deserialize<DefinitionTag>(notification.NextStepDefine.Tag);
 
 
         switch (workflow.ModuleCode)
@@ -72,38 +83,49 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
                 var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, cancellationToken);
                 order.CheckIfFiled();
                 _mapper.Map(workflow, order);
-                await _orderRepository.UpdateAsync(order, cancellationToken);
 
-                var orderDto = _mapper.Map<OrderDto>(order);
-                if (notification.IsCenterToOrg)
-                    await _capPublisher.PublishAsync(EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: cancellationToken);
 
-                if (notification.HandlerOrgCode.CheckIfOrgLevelIs(1))
-                    await _capPublisher.PublishAsync(EventNames.HotlineOrderLevelOneOrgHandled, new OrderFlowDto
-                    {
-                        Order = orderDto,
-                        WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace)
-                    }, cancellationToken: cancellationToken);
+                //var orderDto = _mapper.Map<OrderDto>(order);
+                //if (notification.IsCenterToOrg)
+                //    await _capPublisher.PublishAsync(EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: cancellationToken);
+
+                //if (notification.HandlerOrgCode.CheckIfOrgLevelIs(1))
+                //    await _capPublisher.PublishAsync(EventNames.HotlineOrderLevelOneOrgHandled, new OrderFlowDto
+                //    {
+                //        Order = orderDto,
+                //        WorkflowTrace = _mapper.Map<WorkflowTraceDto>(notification.Trace)
+                //    }, cancellationToken: cancellationToken);
 
-                if (currentTag is not null)
+                if (notification.FlowDirection is EFlowDirection.CenterToOrg or EFlowDirection.OrgToCenter)
                 {
-                    if (currentTag.Type == TagDefaults.TagType.Org)
+                    //todo 1. calc expiredTime 2. update order.expiredTime 3. update workflow.expiredTime 4. publish province
+                    //todo 1. calc expiredTime with 1 day 2. update order.expiredTime 3. update workflow.expiredTime 4. publish province
+                    TimeResult expiredTime;
+                    if (notification.FlowDirection is EFlowDirection.CenterToOrg)
                     {
-                        switch (currentTag.Value)
-                        {
-                            case TagDefaults.TagValue.Province:
-
-                                break;
-                        }
+                        expiredTime =
+                            _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode, false);
+                        order.CenterToOrg(expiredTime.EndTime);
                     }
+                    else
+                    {
+                        expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.Day, 1, true);
+                        order.OrgToCenter(expiredTime.EndTime);
+                    }
+                    //workflow.expiredTime
+                    //publish
+                    await _workflowDomainService.UpdateExpiredTimeAsync(expiredTime.EndTime, expiredTime.RuleStr, null, null, cancellationToken);
                 }
 
+
+
+                await _orderRepository.UpdateAsync(order, cancellationToken);
                 break;
             case WorkflowModuleConsts.KnowledgeAdd:
             case WorkflowModuleConsts.KnowledgeUpdate:
             case WorkflowModuleConsts.KnowledgeDelete:
             case WorkflowModuleConsts.OrderScreen:
-                var screen = await _orderScreenRepository.Queryable().Includes(x=>x.Order).Where(x=>x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
+                var screen = await _orderScreenRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                 if (screen != null)
                 {
                     screen.Status = EScreenStatus.Approval;
@@ -111,11 +133,11 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
                 }
                 if (nextTag is not null)
                 {
-	                if (nextTag.Type == TagDefaults.TagType.Org)
-	                {
-		                switch (nextTag.Value)
-		                {
-			                case TagDefaults.TagValue.Province:
+                    if (nextTag.Type == TagDefaults.TagType.Org)
+                    {
+                        switch (nextTag.Value)
+                        {
+                            case TagDefaults.TagValue.Province:
                                 if (screen != null)
                                 {
                                     var screenDto = _mapper.Map<OrderScreenListDto>(screen);
@@ -132,10 +154,10 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
                                     }
                                 }
                                 break;
-		                }
-	                }
+                        }
+                    }
                 }
-				break;
+                break;
             case WorkflowModuleConsts.OrderDelay:
                 if (nextTag is not null)
                 {

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

@@ -1,4 +1,6 @@
-namespace Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Enums.FlowEngine;
+
+namespace Hotline.Share.Dtos.FlowEngine;
 
 /// <summary>
 /// 工作流流转基础信息
@@ -16,6 +18,11 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// </summary>
     public bool BackToCountersignEnd { get; set; }
 
+    /// <summary>
+    /// 节点业务类型
+    /// </summary>
+    public EBusinessType BusinessType { get; set; }
+
     /// <summary>
     /// 根据办理者类型不同,此字段为不同内容
     /// <example>

+ 2 - 0
src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs

@@ -30,6 +30,8 @@ public class NextStepOption : Kv
     /// </summary>
     public bool InputRealHandler { get; set; }
 
+    public EBusinessType BusinessType { get; set; }
+
     public IReadOnlyList<Kv> Items { get; set; }
 }
 

+ 385 - 385
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -11,35 +11,35 @@ using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Order
 {
-	public class OrderDto : UpdateOrderDto
-	{
-		#region 工单属性
+    public class OrderDto : UpdateOrderDto
+    {
+        #region 工单属性
 
-		/// <summary>
-		/// 工单状态
-		/// </summary>
-		public EOrderStatus Status { get; set; }
-		public string StatusText => Status.GetDescription();
+        /// <summary>
+        /// 工单状态
+        /// </summary>
+        public EOrderStatus Status { get; set; }
+        public string StatusText => Status.GetDescription();
 
-		/// <summary>
-		/// 过期状态
-		/// </summary>
-		public EExpiredStatus ExpiredStatus { get; set; }
+        /// <summary>
+        /// 过期状态
+        /// </summary>
+        public EExpiredStatus ExpiredStatus { get; set; }
 
-		/// <summary>
-		/// 处理方式(直办、交办)
-		/// </summary>
-		public EProcessType ProcessType { get; set; }
+        /// <summary>
+        /// 处理方式(直办、交办)
+        /// </summary>
+        public EProcessType ProcessType { get; set; }
 
-		///// <summary>
-		///// 进展情况
-		///// </summary>
-		//public EProgress Progress { get; set; }
+        ///// <summary>
+        ///// 进展情况
+        ///// </summary>
+        //public EProgress Progress { get; set; }
 
-		/// <summary>
-		/// 是否公开
-		/// </summary>
-		public bool IsPublicity { get; set; }
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool IsPublicity { get; set; }
 
         /// <summary>
         /// 工单编码(20220101000001)
@@ -51,202 +51,202 @@ namespace Hotline.Share.Dtos.Order
 		/// </summary>
 		public bool IsNo110 { get; set; }
 
-		#region 流程信息
+        #region 流程信息
 
-		/// <summary>
-		/// 工单开始时间(受理/接办时间=流程开启时间)
-		/// </summary>
-		public DateTime? StartTime { get; set; }
+        /// <summary>
+        /// 工单开始时间(受理/接办时间=流程开启时间)
+        /// </summary>
+        public DateTime? StartTime { get; set; }
 
-		/// <summary>
-		/// 过期时间
-		/// </summary>
-		public DateTime? ExpiredTime { get; set; }
+        /// <summary>
+        /// 过期时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
 
-		/// <summary>
-		/// 交办时间(中心交部门办理时间)
-		/// </summary>
-		public DateTime? CenterToOrgTime { get; set; }
+        /// <summary>
+        /// 交办时间(中心交部门办理时间)
+        /// </summary>
+        public DateTime? CenterToOrgTime { get; set; }
 
-		/// <summary>
-		/// 归档时间(暂为流程结束时间,因流程结束自动归档)
-		/// </summary>
-		public DateTime? FiledTime { get; set; }
+        /// <summary>
+        /// 归档时间(暂为流程结束时间,因流程结束自动归档)
+        /// </summary>
+        public DateTime? FiledTime { get; set; }
 
-		/// <summary>
-		/// 办结时长(分钟)
-		/// 办结时间-交办时间
-		/// </summary>
-		public double HandleDuration { get; set; }
+        /// <summary>
+        /// 办结时长(分钟)
+        /// 办结时间-交办时间
+        /// </summary>
+        public double HandleDuration { get; set; }
 
-		/// <summary>
-		/// 办结工作日时长(分钟)
-		/// </summary>
-		public double HandleDurationWorkday { get; set; }
+        /// <summary>
+        /// 办结工作日时长(分钟)
+        /// </summary>
+        public double HandleDurationWorkday { get; set; }
 
-		/// <summary>
-		/// 全流程时长(分钟)
-		/// 归档时间-创建时间
-		/// </summary>
-		public double AllDuration { get; set; }
+        /// <summary>
+        /// 全流程时长(分钟)
+        /// 归档时间-创建时间
+        /// </summary>
+        public double AllDuration { get; set; }
 
-		/// <summary>
-		/// 办理时间限制(如:24小时、7个工作日)
-		/// </summary>
-		public string? TimeLimit { get; set; }
+        /// <summary>
+        /// 办理时间限制(如:24小时、7个工作日)
+        /// </summary>
+        public string? TimeLimit { get; set; }
 
-		public int? TimeLimitCount { get; set; }
+        public int? TimeLimitCount { get; set; }
 
-		public ETimeType? TimeLimitUnit { get; set; }
+        public ETimeType? TimeLimitUnit { get; set; }
 
-		#region 实际办理信息(节点,部门,意见)
+        #region 实际办理信息(节点,部门,意见)
 
-		/// <summary>
-		/// 实际办理节点code(会签状态此字段保存最外层会签发起节点code)
-		/// </summary>
-		public string? ActualHandleStepCode { get; set; }
+        /// <summary>
+        /// 实际办理节点code(会签状态此字段保存最外层会签发起节点code)
+        /// </summary>
+        public string? ActualHandleStepCode { get; set; }
 
-		/// <summary>
-		/// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
-		/// </summary>
-		public string? ActualHandleStepName { get; set; }
+        /// <summary>
+        /// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
+        /// </summary>
+        public string? ActualHandleStepName { get; set; }
 
-		/// <summary>
-		/// 到达实际办理节点时间(stepBox创建时间)
-		/// </summary>
-		public DateTime? ActualHandleStepCreateTime { get; set; }
+        /// <summary>
+        /// 到达实际办理节点时间(stepBox创建时间)
+        /// </summary>
+        public DateTime? ActualHandleStepCreateTime { get; set; }
 
-		/// <summary>
-		/// 实际办理节点签收时间
-		/// </summary>
-		public DateTime? ActualHandleStepAcceptTime { get; set; }
+        /// <summary>
+        /// 实际办理节点签收时间
+        /// </summary>
+        public DateTime? ActualHandleStepAcceptTime { get; set; }
 
-		/// <summary>
-		/// 实际办理时间
-		/// </summary>
-		public DateTime? ActualHandleTime { get; set; }
+        /// <summary>
+        /// 实际办理时间
+        /// </summary>
+        public DateTime? ActualHandleTime { get; set; }
 
-		/// <summary>
-		/// 实际办理人id
-		/// </summary>
-		public string? ActualHandlerId { get; set; }
+        /// <summary>
+        /// 实际办理人id
+        /// </summary>
+        public string? ActualHandlerId { get; set; }
 
-		/// <summary>
-		/// 实际办理人名称
-		/// </summary>
-		public string? ActualHandlerName { get; set; }
+        /// <summary>
+        /// 实际办理人名称
+        /// </summary>
+        public string? ActualHandlerName { get; set; }
 
-		/// <summary>
-		/// 实际办理部门名称
-		/// </summary>
-		public string? ActualHandleOrgName { get; set; }
+        /// <summary>
+        /// 实际办理部门名称
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
 
-		/// <summary>
-		/// 实际办理部门编码
-		/// </summary>
-		public string? ActualHandleOrgCode { get; set; }
+        /// <summary>
+        /// 实际办理部门编码
+        /// </summary>
+        public string? ActualHandleOrgCode { get; set; }
 
-		/// <summary>
-		/// 实际办理部门行政区划编码
-		/// </summary>
-		public string? ActualHandleOrgAreaCode { get; set; }
+        /// <summary>
+        /// 实际办理部门行政区划编码
+        /// </summary>
+        public string? ActualHandleOrgAreaCode { get; set; }
 
-		/// <summary>
-		/// 实际办理部门行政区划名称
-		/// </summary>
-		public string? ActualHandleOrgAreaName { get; set; }
+        /// <summary>
+        /// 实际办理部门行政区划名称
+        /// </summary>
+        public string? ActualHandleOrgAreaName { get; set; }
 
-		/// <summary>
-		/// 实际办理意见(办理中...or 最终办理意见)
-		/// </summary>
-		public string ActualOpinion { get; set; } = "办理中...";
+        /// <summary>
+        /// 实际办理意见(办理中...or 最终办理意见)
+        /// </summary>
+        public string ActualOpinion { get; set; } = "办理中...";
 
-		/// <summary>
-		/// 真实办理人姓名(手动填写)
-		/// </summary>
-		public string? RealHandlerName { get; set; }
+        /// <summary>
+        /// 真实办理人姓名(手动填写)
+        /// </summary>
+        public string? RealHandlerName { get; set; }
 
-		/// <summary>
-		/// 真实办理人电话(手动填写)
-		/// </summary>
-		public string? RealHandlerPhone { get; set; }
+        /// <summary>
+        /// 真实办理人电话(手动填写)
+        /// </summary>
+        public string? RealHandlerPhone { get; set; }
 
-		/// <summary>
-		/// 沟通方式(手动填写)
-		/// </summary>
-		public ERealCommunicationMode? RealCommunicationMode { get; set; }
+        /// <summary>
+        /// 沟通方式(手动填写)
+        /// </summary>
+        public ERealCommunicationMode? RealCommunicationMode { get; set; }
 
-		/// <summary>
-		/// 沟通时间(手动填写)
-		/// </summary>
-		public DateTime? RealCommunicationTime { get; set; }
+        /// <summary>
+        /// 沟通时间(手动填写)
+        /// </summary>
+        public DateTime? RealCommunicationTime { get; set; }
 
-		/// <summary>
-		/// 沟通地点(手动填写)
-		/// </summary>
-		public string? RealCommunicationAddress { get; set; }
+        /// <summary>
+        /// 沟通地点(手动填写)
+        /// </summary>
+        public string? RealCommunicationAddress { get; set; }
 
-		#endregion
+        #endregion
 
-		#region 当前办理节点信息
+        #region 当前办理节点信息
 
-		/// <summary>
-		/// 当前办理节点code(非会签:当前被指派节点,会签:会签发起节点)
-		/// </summary>
-		public string? CurrentStepCode { get; set; }
+        /// <summary>
+        /// 当前办理节点code(非会签:当前被指派节点,会签:会签发起节点)
+        /// </summary>
+        public string? CurrentStepCode { get; set; }
 
-		/// <summary>
-		/// 当前节点名称
-		/// </summary>
-		public string? CurrentStepName { get; set; }
+        /// <summary>
+        /// 当前节点名称
+        /// </summary>
+        public string? CurrentStepName { get; set; }
 
-		/// <summary>
-		/// 到达当前节点时间(stepBox创建时间)
-		/// </summary>
-		public DateTime? CurrentStepCreateTime { get; set; }
+        /// <summary>
+        /// 到达当前节点时间(stepBox创建时间)
+        /// </summary>
+        public DateTime? CurrentStepCreateTime { get; set; }
 
-		#endregion
+        #endregion
 
-		#region 一级部门
+        #region 一级部门
 
-		/// <summary>
-		/// 一级部门code
-		/// </summary>
-		public string? OrgLevelOneCode { get; set; }
+        /// <summary>
+        /// 一级部门code
+        /// </summary>
+        public string? OrgLevelOneCode { get; set; }
 
-		/// <summary>
-		/// 一级部门名称
-		/// </summary>
-		public string? OrgLevelOneName { get; set; }
+        /// <summary>
+        /// 一级部门名称
+        /// </summary>
+        public string? OrgLevelOneName { get; set; }
 
-		#endregion
+        #endregion
 
-		#region 受理人(开启流程的话务员)
+        #region 受理人(开启流程的话务员)
 
-		/// <summary>
-		/// 受理人id
-		/// </summary>
-		public string? AcceptorId { get; set; }
+        /// <summary>
+        /// 受理人id
+        /// </summary>
+        public string? AcceptorId { get; set; }
 
-		/// <summary>
-		/// 受理人名称
-		/// </summary>
-		public string? AcceptorName { get; set; }
+        /// <summary>
+        /// 受理人名称
+        /// </summary>
+        public string? AcceptorName { get; set; }
 
-		/// <summary>
-		/// 受理人工号
-		/// </summary>
-		public string? AcceptorStaffNo { get; set; }
+        /// <summary>
+        /// 受理人工号
+        /// </summary>
+        public string? AcceptorStaffNo { get; set; }
 
-		/// <summary>
-		/// 受理人部门编码
-		/// </summary>
-		public string? AcceptorOrgCode { get; set; }
+        /// <summary>
+        /// 受理人部门编码
+        /// </summary>
+        public string? AcceptorOrgCode { get; set; }
 
-		/// <summary>
-		/// 受理人部门名称
-		/// </summary>
-		public string? AcceptorOrgName { get; set; }
+        /// <summary>
+        /// 受理人部门名称
+        /// </summary>
+        public string? AcceptorOrgName { get; set; }
 
         #endregion
 
@@ -254,7 +254,7 @@ namespace Hotline.Share.Dtos.Order
         /// 会签类型
         /// </summary>
         public ECounterSignType? CounterSignType { get; set; }
-        //public string? CounterSignTypeText => CounterSignType.GetDescription();
+        public string? CounterSignTypeText => CounterSignType?.GetDescription() ?? "未会签";
 
         #endregion
 
@@ -264,67 +264,67 @@ namespace Hotline.Share.Dtos.Order
         public string CreationTime { get; set; }
 
 
-		public string? ContactMask { get; set; }
+        public string? ContactMask { get; set; }
 
-		public string SmsSendedText => SmsSended ? "已发送" : "未发送";
+        public string SmsSendedText => SmsSended ? "已发送" : "未发送";
 
-		/// <summary>
-		/// 市民查询密码
-		/// </summary>
-		public string? Password { get; set; }
+        /// <summary>
+        /// 市民查询密码
+        /// </summary>
+        public string? Password { get; set; }
 
-		public string WorkflowId { get; set; }
-		public WorkflowDto Workflow { get; set; }
+        public string WorkflowId { get; set; }
+        public WorkflowDto Workflow { get; set; }
 
-		/// <summary>
-		/// 来电/信人性别
-		/// </summary>
-		public string FromGenderText => FromGender.GetDescription();
+        /// <summary>
+        /// 来电/信人性别
+        /// </summary>
+        public string FromGenderText => FromGender.GetDescription();
 
-		/// <summary>
-		/// 来电/信人身份
-		/// </summary>
-		public string IdentityTypeText => IdentityType.GetDescription();
+        /// <summary>
+        /// 来电/信人身份
+        /// </summary>
+        public string IdentityTypeText => IdentityType.GetDescription();
 
-		/// <summary>
-		/// 工单类型
-		/// </summary>
-		public string OrderTypeText => OrderType.GetDescription();
+        /// <summary>
+        /// 工单类型
+        /// </summary>
+        public string OrderTypeText => OrderType.GetDescription();
 
-		///// <summary>
-		///// 受理类型
-		///// </summary>
-		////public string AcceptTypeText => AcceptType.GetDescription();
+        ///// <summary>
+        ///// 受理类型
+        ///// </summary>
+        ////public string AcceptTypeText => AcceptType.GetDescription();
 
-		/// <summary>
-		/// 紧急程度
-		/// </summary>
-		public string EmergencyLevelText => EmergencyLevel.GetDescription();
+        /// <summary>
+        /// 紧急程度
+        /// </summary>
+        public string EmergencyLevelText => EmergencyLevel.GetDescription();
 
-		/// <summary>
-		/// 超期时间描述(需求:超期3天、0.5天后超期)
-		/// </summary>
-		public string ExpiredText => CalculateExpiredText();
-
-		private string CalculateExpiredText()
-		{
-			//todo 完整处理方案:1.创建待过期表,Id,过期时间,即将过期时间等字段。2.延迟消息通知处理过期,删除子表数据,处理order过期状态字段。3.此处即可采用expiredStatus进行判断
-			//todo 目前暂时采用过期时间计算
-			if (!ExpiredTime.HasValue)
-				return string.Empty;
-			var days = (DateTime.Now - ExpiredTime.Value).TotalDays;
-			switch (days)
-			{
-				case > 0:
-					return $"超期{days:N1}天";
-				case < 0:
-					return $"{days:N1}天后超期";
-				default:
-					return "超期不到1天";
-			}
-		}
-
-		public HotspotDto? Hotspot { get; set; }
+        /// <summary>
+        /// 超期时间描述(需求:超期3天、0.5天后超期)
+        /// </summary>
+        public string ExpiredText => CalculateExpiredText();
+
+        private string CalculateExpiredText()
+        {
+            //todo 完整处理方案:1.创建待过期表,Id,过期时间,即将过期时间等字段。2.延迟消息通知处理过期,删除子表数据,处理order过期状态字段。3.此处即可采用expiredStatus进行判断
+            //todo 目前暂时采用过期时间计算
+            if (!ExpiredTime.HasValue)
+                return string.Empty;
+            var days = (DateTime.Now - ExpiredTime.Value).TotalDays;
+            switch (days)
+            {
+                case > 0:
+                    return $"超期{days:N1}天";
+                case < 0:
+                    return $"{days:N1}天后超期";
+                default:
+                    return "超期不到1天";
+            }
+        }
+
+        public HotspotDto? Hotspot { get; set; }
 
         /// <summary>
         /// 延期
@@ -338,209 +338,209 @@ namespace Hotline.Share.Dtos.Order
 
         public List<RepeatableEventDetailOpDto> RepeatableEventDetails { get; set; } = new();
 
-		public List<OrderVisitDto> OrderVisits { get; set; }
+        public List<OrderVisitDto> OrderVisits { get; set; }
 
     }
 
-	public class UpdateOrderDto : AddOrderDto
-	{
-		public string Id { get; set; }
-	}
+    public class UpdateOrderDto : AddOrderDto
+    {
+        public string Id { get; set; }
+    }
 
-	public class AddOrderDto : Position
-	{
-		#region 来电信息
+    public class AddOrderDto : Position
+    {
+        #region 来电信息
 
-		/// <summary>
-		/// 来源渠道
-		/// </summary>
-		public string SourceChannel { get; set; }
-		public string SourceChannelCode { get; set; }
+        /// <summary>
+        /// 来源渠道
+        /// </summary>
+        public string SourceChannel { get; set; }
+        public string SourceChannelCode { get; set; }
 
-		/// <summary>
-		/// 渠道为电话时,此字段存在
-		/// </summary>
-		public string? CallId { get; set; }
+        /// <summary>
+        /// 渠道为电话时,此字段存在
+        /// </summary>
+        public string? CallId { get; set; }
 
-		/// <summary>
-		/// 来电归属地
-		/// </summary>
-		public string? CallAddress { get; set; }
+        /// <summary>
+        /// 来电归属地
+        /// </summary>
+        public string? CallAddress { get; set; }
 
-		/// <summary>
-		/// 来电号码
-		/// </summary>
-		public string? FromPhone { get; set; }
+        /// <summary>
+        /// 来电号码
+        /// </summary>
+        public string? FromPhone { get; set; }
 
-		/// <summary>
-		/// 转接号码(转接来源)
-		/// </summary>
-		public string? TransferPhone { get; set; }
+        /// <summary>
+        /// 转接号码(转接来源)
+        /// </summary>
+        public string? TransferPhone { get; set; }
 
-		/// <summary>
-		/// 来电/信人姓名
-		/// </summary>
-		public string FromName { get; set; }
+        /// <summary>
+        /// 来电/信人姓名
+        /// </summary>
+        public string FromName { get; set; }
 
-		/// <summary>
-		/// 来电/信人性别
-		/// </summary>
-		public EGender FromGender { get; set; }
+        /// <summary>
+        /// 来电/信人性别
+        /// </summary>
+        public EGender FromGender { get; set; }
 
-		/// <summary>
-		/// 来电/信人身份
-		/// </summary>
-		public EIdentityType IdentityType { get; set; }
+        /// <summary>
+        /// 来电/信人身份
+        /// </summary>
+        public EIdentityType IdentityType { get; set; }
 
-		/// <summary>
-		/// 证件类型
-		/// </summary>
-		public string? LicenceTypeCode { get; set; }
+        /// <summary>
+        /// 证件类型
+        /// </summary>
+        public string? LicenceTypeCode { get; set; }
 
-		public string? LicenceType { get; set; }
+        public string? LicenceType { get; set; }
 
-		/// <summary>
-		/// 证件号码
-		/// </summary>
-		public string? LicenceNo { get; set; }
+        /// <summary>
+        /// 证件号码
+        /// </summary>
+        public string? LicenceNo { get; set; }
 
-		/// <summary>
-		/// 年龄段
-		/// </summary>
-		public string? AgeRangeCode { get; set; }
+        /// <summary>
+        /// 年龄段
+        /// </summary>
+        public string? AgeRangeCode { get; set; }
 
-		public string? AgeRange { get; set; }
+        public string? AgeRange { get; set; }
 
-		/// <summary>
-		/// 联系电话
-		/// </summary>
-		public string? Contact { get; set; }
+        /// <summary>
+        /// 联系电话
+        /// </summary>
+        public string? Contact { get; set; }
 
-		/// <summary>
-		/// 是否接受短信,勾选校验手机号
-		/// </summary>
-		public bool AcceptSms { get; set; }
+        /// <summary>
+        /// 是否接受短信,勾选校验手机号
+        /// </summary>
+        public bool AcceptSms { get; set; }
 
-		/// <summary>
-		/// 是否已发送短信
-		/// </summary>
-		public bool SmsSended { get; set; }
+        /// <summary>
+        /// 是否已发送短信
+        /// </summary>
+        public bool SmsSended { get; set; }
 
-		/// <summary>
-		/// 是否保密
-		/// </summary>
-		public bool IsSecret { get; set; }
+        /// <summary>
+        /// 是否保密
+        /// </summary>
+        public bool IsSecret { get; set; }
 
-		/// <summary>
-		/// 工作单位(当“来电/信人身份”为“企业”时必填,其他情况非必填)
-		/// </summary>
-		public string? Company { get; set; }
+        /// <summary>
+        /// 工作单位(当“来电/信人身份”为“企业”时必填,其他情况非必填)
+        /// </summary>
+        public string? Company { get; set; }
 
-		#endregion
+        #endregion
 
-		#region 诉求信息
+        #region 诉求信息
 
-		/// <summary>
-		/// 工单类型
-		/// </summary>
-		public EOrderType OrderType { get; set; }
+        /// <summary>
+        /// 工单类型
+        /// </summary>
+        public EOrderType OrderType { get; set; }
 
-		/// <summary>
-		/// 受理类型
-		/// </summary>
-		//public EAcceptType AcceptType { get; set; }
-		public string AcceptType { get; set; }
-		public string AcceptTypeCode { get; set; }
+        /// <summary>
+        /// 受理类型
+        /// </summary>
+        //public EAcceptType AcceptType { get; set; }
+        public string AcceptType { get; set; }
+        public string AcceptTypeCode { get; set; }
 
-		/// <summary>
-		/// 紧急程度
-		/// </summary>
-		public EEmergencyLevel EmergencyLevel { get; set; } = EEmergencyLevel.Normal;
+        /// <summary>
+        /// 紧急程度
+        /// </summary>
+        public EEmergencyLevel EmergencyLevel { get; set; } = EEmergencyLevel.Normal;
 
-		public string Title { get; set; }
+        public string Title { get; set; }
 
-		#region 热点
+        #region 热点
 
-		/// <summary>
-		/// 热点
-		/// </summary>
-		public string HotspotId { get; set; }
-		public string HotspotName { get; set; }
-		public string HotspotSpliceName { get; set; }
+        /// <summary>
+        /// 热点
+        /// </summary>
+        public string HotspotId { get; set; }
+        public string HotspotName { get; set; }
+        public string HotspotSpliceName { get; set; }
 
-		/// <summary>
-		/// 外部数据(为前端提供级联功能)
-		/// </summary>
-		public string HotspotExternal { get; set; }
+        /// <summary>
+        /// 外部数据(为前端提供级联功能)
+        /// </summary>
+        public string HotspotExternal { get; set; }
 
-		#endregion
+        #endregion
 
-		/// <summary>
-		/// 事发时间
-		/// </summary>
-		public DateTime? IncidentTime { get; set; }
+        /// <summary>
+        /// 事发时间
+        /// </summary>
+        public DateTime? IncidentTime { get; set; }
 
-		/// <summary>
-		/// 重复工单Id
-		/// </summary>
-		public List<string>? DuplicateIds { get; set; }
+        /// <summary>
+        /// 重复工单Id
+        /// </summary>
+        public List<string>? DuplicateIds { get; set; }
 
-		/// <summary>
-		/// 推送分类
-		/// </summary>
-		public string? PushTypeCode { get; set; }
+        /// <summary>
+        /// 推送分类
+        /// </summary>
+        public string? PushTypeCode { get; set; }
 
-		public string? PushType { get; set; }
+        public string? PushType { get; set; }
 
-		/// <summary>
-		/// 附件
-		/// </summary>
-		public List<string> Additions { get; set; } = new();
+        /// <summary>
+        /// 附件
+        /// </summary>
+        public List<string> Additions { get; set; } = new();
 
-		/// <summary>
-		/// 诉求内容
-		/// </summary>
-		public string Content { get; set; }
+        /// <summary>
+        /// 诉求内容
+        /// </summary>
+        public string Content { get; set; }
 
-		#endregion
+        #endregion
 
-		/// <summary>
-		/// 来源,区分省平台或110等其他平台同步过来的工单
-		/// </summary>
-		public ESource Source { get; set; } = ESource.Hotline;
+        /// <summary>
+        /// 来源,区分省平台或110等其他平台同步过来的工单
+        /// </summary>
+        public ESource Source { get; set; } = ESource.Hotline;
 
-		/// <summary>
-		/// 投诉
-		/// </summary>
-		public OrderComplainDto OrderComplain { get; set; }
+        /// <summary>
+        /// 投诉
+        /// </summary>
+        public OrderComplainDto OrderComplain { get; set; }
 
-		/// <summary>
-		/// 举报
-		/// </summary>
-		public OrderReportDto OrderReport { get; set; }
+        /// <summary>
+        /// 举报
+        /// </summary>
+        public OrderReportDto OrderReport { get; set; }
 
-		/// <summary>
-		/// 附件列表
-		/// </summary>
-		public List<FileDto> Files { get; set; } = new();
+        /// <summary>
+        /// 附件列表
+        /// </summary>
+        public List<FileDto> Files { get; set; } = new();
 
-		/// <summary>
-		/// 标签名称
-		/// </summary>
-		public List<string> Tags { get; set; } = new();
+        /// <summary>
+        /// 标签名称
+        /// </summary>
+        public List<string> Tags { get; set; } = new();
 
-		/// <summary>
-		/// 企业名称
-		/// </summary>
-		public string? EnterpriseName { get; set; }
+        /// <summary>
+        /// 企业名称
+        /// </summary>
+        public string? EnterpriseName { get; set; }
 
-		/// <summary>
-		/// 专班名称
-		/// </summary>
-		public string? ZhuanBanMingCheng { get; set; }
+        /// <summary>
+        /// 专班名称
+        /// </summary>
+        public string? ZhuanBanMingCheng { get; set; }
 
-		#region  重复性事件
-		public List<RepeatableEventDetailOpDto> RepeatableEventDetails { get; set; } = new();
+        #region  重复性事件
+        public List<RepeatableEventDetailOpDto> RepeatableEventDetails { get; set; } = new();
         #endregion
 
         /// <summary>

+ 0 - 1
src/Hotline.Share/Enums/FlowEngine/EBusinessType.cs

@@ -25,6 +25,5 @@ public enum EBusinessType
     /// <summary>
     /// 归档节点
     /// </summary>
-    [Description("归档节点")]
     File = 3,
 }

+ 18 - 0
src/Hotline/FlowEngine/EFlowDirection.cs

@@ -0,0 +1,18 @@
+namespace Hotline.FlowEngine;
+
+public enum EFlowDirection
+{
+    /// <summary>
+    /// 中心流转至部门
+    /// </summary>
+    CenterToOrg = 0,
+
+    /// <summary>
+    /// 部门流转至中心
+    /// </summary>
+    OrgToCenter = 1,
+
+    CenterToCenter = 2,
+
+    OrgToOrg = 3,
+}

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

@@ -9,8 +9,8 @@ public record WorkflowNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotific
 
 public record StartWorkflowNotify(Workflow Workflow, BasicWorkflowDto Dto, FlowAssignInfo FlowAssignInfo) : WorkflowNotify(Workflow, Dto);
 
-public record NextStepNotify(Workflow Workflow, BasicWorkflowDto Dto, WorkflowTrace Trace, StepDefine nextStepDefine,
-    bool IsCenterToOrg, bool IsCountersignEnd, string HandlerOrgCode, FlowAssignInfo FlowAssignInfo) : WorkflowNotify(Workflow, Dto);
+public record NextStepNotify(Workflow Workflow, BasicWorkflowDto Dto, WorkflowTrace Trace, StepDefine NextStepDefine,
+    EFlowDirection FlowDirection, string HandlerOrgCode) : WorkflowNotify(Workflow, Dto);
 
 public record AcceptWorkflowNotify(Workflow Workflow) : INotification;
 

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

@@ -4,6 +4,7 @@ using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Settings;
 using XF.Domain.Entities;
 
 namespace Hotline.FlowEngine.Workflows
@@ -110,5 +111,11 @@ namespace Hotline.FlowEngine.Workflows
         /// 撤销流程
         /// </summary>
         Task CancelAsync(CancelDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 更新期满时间
+        /// </summary>
+        Task UpdateExpiredTimeAsync(DateTime expiredTime, string timelimitText, int? timelimie,
+            ETimeType? timelimitUnit, CancellationToken cancellationToken);
     }
 }

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

@@ -4,20 +4,15 @@ using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Dtos.FlowEngine.Definition;
-using Hotline.Share.Dtos.Settings;
-using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Settings;
 using MapsterMapper;
 using MediatR;
 using Microsoft.Extensions.Logging;
-using System.Diagnostics;
-using System.Threading;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Entities;
 using XF.Domain.Exceptions;
-using XF.Domain.Extensions;
 using XF.Domain.Repository;
 
 namespace Hotline.FlowEngine.Workflows
@@ -361,10 +356,11 @@ namespace Hotline.FlowEngine.Workflows
                 return;
             }
 
-            //是否从中心流转出去,重新计算expiredTime 
-            var isCenterToOrg = CheckIfFlowFromCenterToOrg(currentStep, nextStepDefine);
-            //if (isCenterToOrg)
-            //    workflow.CenterToOrg(CalculateExpiredTime(workflow.WorkflowDefinition.Code));//todo 过期时间
+            ////是否从中心流转出去,重新计算expiredTime 
+            //var isCenterToOrg = CheckIfFlowFromCenterToOrg(currentStep, nextStepDefine);
+            //var isOrgToCenter = false;
+            ////if (isCenterToOrg)
+            ////    workflow.CenterToOrg(CalculateExpiredTime(workflow.WorkflowDefinition.Code));//todo 过期时间
 
             //创建下一/N个节点(会签汇总节点:会签未全部办理时不创建,最后一个会签办理节点创建会签汇总节点)
             var nextSteps = await CreateNextStepsAsync(workflow, nextStepDefine, currentStep, dto, flowAssignInfo,
@@ -404,10 +400,27 @@ namespace Hotline.FlowEngine.Workflows
 
             #endregion
 
-            await _mediator.Publish(new NextStepNotify(workflow, dto, trace, nextStepDefine,
-                isCenterToOrg, isCountersignOver,
-                _sessionContext.RequiredOrgId, flowAssignInfo), cancellationToken);
+            var flowDirection = CheckFlowDirection(currentStep, dto);
+            await _mediator.Publish(
+                new NextStepNotify(workflow, dto, trace, nextStepDefine, flowDirection, _sessionContext.RequiredOrgId),
+                cancellationToken);
+
+        }
 
+        private EFlowDirection CheckFlowDirection(WorkflowStep currentStep, BasicWorkflowDto dto)
+        {
+            if (currentStep.BusinessType is EBusinessType.Center or EBusinessType.Send)
+            {
+                return dto.BusinessType is EBusinessType.Department or EBusinessType.File
+                    ? EFlowDirection.CenterToOrg
+                    : EFlowDirection.CenterToCenter;
+            }
+            else
+            {
+                return dto.BusinessType is EBusinessType.Center or EBusinessType.Send
+                    ? EFlowDirection.OrgToCenter
+                    : EFlowDirection.OrgToOrg;
+            }
         }
 
         //更新目标节点前一节点的会签办理完成状态
@@ -873,7 +886,6 @@ namespace Hotline.FlowEngine.Workflows
             await _mediator.Publish(new CancelWorkflowNotify(workflow), cancellationToken);
         }
 
-
         #region private method
 
         /// <summary>
@@ -1275,8 +1287,8 @@ namespace Hotline.FlowEngine.Workflows
             var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
 
             var step = CreateStep(endStepDefine, prevStep, workflow.Id, null, new List<Kv> { handler },
-                 null, null, null,
-                     EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, DateTime.Now, endStepDefine.Name, true);
+                null, null, null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, DateTime.Now,
+                endStepDefine.Name, true, EBusinessType.File);
 
             //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
             //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
@@ -1315,7 +1327,7 @@ namespace Hotline.FlowEngine.Workflows
 
             return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignInfo.FlowAssignType, handlers,
                 null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, expiredTime, true,
-                cancellationToken);
+                 cancellationToken);
         }
 
         private async Task<List<WorkflowStep>> CreateStepsAsync(
@@ -1344,7 +1356,7 @@ namespace Hotline.FlowEngine.Workflows
                 {
                     var step = CreateStep(stepDefine, prevStep, workflow.Id, flowAssignType, new List<Kv> { handler },
                         dto.NextStepCode, dto.NextMainHandler, countersignId,
-                        stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin);
+                        stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, dto.BusinessType);
 
                     steps.Add(step);
                 }
@@ -1353,7 +1365,7 @@ namespace Hotline.FlowEngine.Workflows
             {
                 var step = CreateStep(stepDefine, prevStep, workflow.Id, flowAssignType, handlers,
                     dto.NextStepCode, dto.NextMainHandler, countersignId,
-                    stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin);
+                    stepStatus, csPosition, expiredTime, dto.NextStepName, isOrigin, dto.BusinessType);
 
                 steps.Add(step);
             }
@@ -1399,7 +1411,8 @@ namespace Hotline.FlowEngine.Workflows
             ECountersignPosition countersignPosition,
             DateTime expiredTime,
             string stepName,
-            bool isOrigin
+            bool isOrigin,
+            EBusinessType businessType
             )
         {
             if (!handlers.Any())
@@ -1422,6 +1435,7 @@ namespace Hotline.FlowEngine.Workflows
             //step.TimeLimit = GetTimeLimit("");
             step.IsOrigin = isOrigin;
             step.Name = stepName;
+            step.BusinessType = businessType;
 
             return step;
         }

+ 14 - 25
src/Hotline/Orders/Order.cs

@@ -649,31 +649,6 @@ namespace Hotline.Orders
         public void UpdateHandlingStatus(bool isInCountersign) =>
             Status = isInCountersign ? EOrderStatus.Countersigning : EOrderStatus.Handling;
 
-        ///// <summary>
-        ///// 接办
-        ///// </summary>
-        //public void Accept()
-        //{
-        //    if (Status is EOrderStatus.Countersigning) return;
-        //    Status = EOrderStatus.WaitForHandle;
-        //}
-
-        ///// <summary>
-        ///// 最终办理
-        ///// </summary>
-        //public void FinalManage()
-        //{
-        //    Status = EOrderStatus.Completed;
-        //}
-
-        ///// <summary>
-        ///// 撤回最终办理
-        ///// </summary>
-        //public void RecallFinalManage()
-        //{
-        //    Status = EOrderStatus.WaitForSign;
-        //}
-
         /// <summary>
         /// 归档
         /// </summary>
@@ -710,6 +685,20 @@ namespace Hotline.Orders
             Status = EOrderStatus.Visited;
         }
 
+        public void CenterToOrg(DateTime expiredTime)
+        {
+            ProcessType = EProcessType.Jiaoban;
+            ExpiredTime = expiredTime;
+            CenterToOrgTime = DateTime.Now;
+        }
+
+        public void OrgToCenter(DateTime expiredTime)
+        {
+            ProcessType = EProcessType.Zhiban;
+            ExpiredTime = expiredTime;
+            CenterToOrgTime = null;
+        }
+
         #endregion
     }
 }