ソースを参照

Merge branch 'release' of http://110.188.24.182:10023/Fengwo/hotline into release

tangjiang 6 ヶ月 前
コミット
cde30c1e15

+ 4 - 0
src/Hotline.Application.Contracts/Validators/FlowEngine/NextWorkflowDtoValidator.cs

@@ -13,6 +13,10 @@ namespace Hotline.Application.Contracts.Validators.FlowEngine
         public NextWorkflowDtoValidator()
         {
             RuleFor(d => d.WorkflowId).NotEmpty();
+            RuleFor(d => d.Opinion)
+                .Cascade(CascadeMode.Stop)
+                .NotEmpty()
+                .MaximumLength(2000);
             //RuleFor(d=>d.ExpiredTime).NotEmpty();
             //RuleFor(d=>d.NextStepCode).NotEmpty();
         }

+ 1 - 0
src/Hotline.Application.Tests/Domain/ZiGongExpireTimeTest.cs

@@ -66,6 +66,7 @@ public class ZiGongExpireTimeTest
 
     [Theory]
     [InlineData("求助三个工作日", "2024-09-12 22:01:28", "CenterToOrg", "2024-09-20 08:30:00")]
+    [InlineData("string", "2024-09-12 22:01:28", "CenterToOrg", "2024-09-20 08:30:00")]
     public async Task CalcExpiredTime_Release_Test(string title, string beginTxt, string flowTxt, string expected)
     {
         var beginTime = DateTime.Parse(beginTxt);

+ 15 - 1
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -11,6 +11,7 @@ using Hotline.Share.Enums.CallCenter;
 using Hotline.Users;
 using MapsterMapper;
 using Microsoft.Extensions.Logging;
+using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Exceptions;
@@ -205,6 +206,7 @@ public abstract class DefaultCallApplication : ICallApplication
     {
         var query = _callNativeRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((d, o) => d.Id == o.CallId)
+            .Where((d, o) => d.GroupId == "1")
             .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), (d, o) => o.No == dto.OrderNo)
             .WhereIF(!string.IsNullOrEmpty(dto.FromNo), d => d.FromNo == dto.FromNo)
             .WhereIF(!string.IsNullOrEmpty(dto.ToNo), d => d.ToNo == dto.ToNo)
@@ -224,13 +226,25 @@ public abstract class DefaultCallApplication : ICallApplication
         query = query.WhereIF(dto.Type == 3, (d, o) => d.AnsweredTime == null);
         query = query.WhereIF(dto.Type == 1, (d, o) => d.Direction == ECallDirection.In);
         query = query.WhereIF(dto.Type == 2, (d, o) => d.Direction == ECallDirection.Out);
-        return await query.Select((d, o) => new CallNativeDto
+        var items = await query.Select((d, o) => new CallNativeDto
         {
             OrderId = o.Id,
             OrderNo = o.No,
             Title = o.Title,
+            Gateway = SqlFunc.Subqueryable<CallNative>()
+            .Where(m => m.GroupId == "0" && m.CallNo == d.CallNo)
+            .Select(m => m.ToNo)
         }, true)
         .ToFixedListAsync(dto, cancellationToken);
+
+        items.Where(m => m.Gateway != null)
+            .ToList().ForEach(m => 
+            {
+                var toNo = m.Gateway;
+                m.Gateway = m.ToNo;
+                m.ToNo = toNo;
+            });
+        return items;
     }
 
     /// <summary>

+ 5 - 0
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -285,6 +285,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// </summary>
     public async Task<Workflow> NextAsync(NextWorkflowDto dto, DateTime? expiredTime = null, CancellationToken cancellationToken = default)
     {
+        var validator = new NextWorkflowDtoValidator();
+        var validResult = await validator.ValidateAsync(dto, cancellationToken);
+        if (!validResult.IsValid)
+            throw new UserFriendlyException(
+                $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
             withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
 

+ 3 - 4
src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs

@@ -161,9 +161,8 @@ public abstract class CallReportApplicationBase : ICallReportApplication
         int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
 
         var callData = await _callNativeRepository.Queryable()
-                .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime)
+                .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime && p.GroupId == "1")
                 .GroupBy(p => p.CreationTime.ToString("yyyy-MM-dd"))
-                //.GroupBy(p => new { CreationTime = p.CreationTime.ToString("yyyy-MM-dd"), CallNo = p.CallNo })
                 .Select(p => new QueryCallsDetailStatistics
                 {
                     Date = p.CreationTime.ToString("yyyy-MM-dd"),
@@ -172,8 +171,8 @@ public abstract class CallReportApplicationBase : ICallReportApplication
                     NotAcceptedHang = SqlFunc.AggregateSum(SqlFunc.IIF(p.Duration == 0 && p.RingDuration <= noConnectByeTimes && p.RingDuration > 0 && p.Direction == ECallDirection.In, 1, 0)), //呼入队列挂断
                     InNotAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.Duration == 0 && p.TelNo != "0" && p.Direction == ECallDirection.In, 1, 0)), // 挂机量
                     IvrByeCount = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.BeginIvrTime.HasValue && !p.BeginQueueTime.HasValue && !p.BeginRingTime.HasValue && p.AnsweredTime == null, 1, 0)), //IVR挂断
-                    OutConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.TelNo != "0" && p.AnsweredTime != null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出接通量
-                    OutNotAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.TelNo != "0" && p.AnsweredTime == null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出未接量
+                    OutConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.AnsweredTime != null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出接通量
+                    OutNotAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.AnsweredTime == null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出未接量
                 })
                 .OrderBy(p => p.Date)
                 .ToListAsync(cancellationToken);

+ 84 - 79
src/Hotline.Application/Subscribers/InternalCapSubscriber.cs

@@ -238,96 +238,101 @@ namespace Hotline.Application.Subscribers
         [CapSubscribe(EventNames.HotlineOrderAutomaticDelay)]
         public async Task AutomaticDelay(PublishAutomaticDelayDto dto, CancellationToken cancellationToken) 
         {
-            var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-			var expiredTime = DateTime.Now.AddHours(1);
-			if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
-			{
-				if (order.ExpiredTime <= expiredTime)
+            var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
+            if (bool.Parse(enabled))
+            {
+				var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
+				var expiredTime = DateTime.Now.AddHours(1);
+				if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
 				{
-                    var delayAny= await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
-                    if (!delayAny)
-                    {
-						var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.AutomaticDelayNum > 0).ToListAsync(cancellationToken);
-						var delay = new OrderDelay();
-						if (delays.Any())
+					if (order.ExpiredTime <= expiredTime)
+					{
+						var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
+						if (!delayAny)
 						{
-							delay = delays.First();
-							delay.AfterDelay = (await _expireTime
-								.CalcEndTime(delay.BeforeDelay.Value, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
-							await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now,AfterDelay = delay.AfterDelay })
-								.Where(x => x.Id == delay.Id).ExecuteCommandAsync(cancellationToken);
-						}
-						else
-						{
-                            delay.OrderId = order.Id;
-							delay.EmployeeId = "";
-							delay.EmployeeName = "系统自动延期";
-							delay.ApplyOrgName = OrgSeedData.CenterName;
-							delay.ApplyOrgCode = OrgSeedData.CenterId;
-							delay.DelayApplyType = EDelayApplyType.LocalApply;
-							delay.BeforeDelay = order.ExpiredTime;
-							delay.DelayState = EDelayState.Pass;
-							delay.DelayReason = "系统自动延期";
-							delay.ApplyDelayTime = DateTime.Now;
-							delay.No = order.No;
-							delay.AutomaticDelayNum = 1;
-							delay.DelayNum = 1;
-							delay.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
-							delay.IsProDelay = false;
-                            delay.CreatorOrgId = OrgSeedData.CenterId;
-							delay.CreatorOrgName = OrgSeedData.CenterName;
-							delay.CreatorName = "系统自动延期";
-							if (delay.BeforeDelay != null)
+							var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.AutomaticDelayNum > 0).ToListAsync(cancellationToken);
+							var delay = new OrderDelay();
+							if (delays.Any())
 							{
+								delay = delays.First();
 								delay.AfterDelay = (await _expireTime
 									.CalcEndTime(delay.BeforeDelay.Value, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+								await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delay.AfterDelay })
+									.Where(x => x.Id == delay.Id).ExecuteCommandAsync(cancellationToken);
 							}
-							await _orderDelayRepository.AddAsync(delay,false, cancellationToken);
-						}
-						//处理工单延期
-						await _orderApplication.DelayOrderExpiredTimeAsync(order.Id, delay.DelayNum,
-							delay.DelayUnit, delay.IsProDelay, cancellationToken);
-						//发送短信
-						var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
-						var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
-						if (steps.Any())
-						{
-                            foreach (var step in steps)
-                            {
-	                            var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
-	                            var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
-	                            if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
-	                            {
-		                            roleIds.Add(step.RoleId);
-	                            }
-	                            var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
-	                            foreach (var user in userList)
-	                            {
-		                            if (!string.IsNullOrEmpty(user.PhoneNo))
-		                            {
-			                            //发送短信
-			                            var messageDto = new Share.Dtos.Push.MessageDto
-			                            {
-				                            PushBusiness = EPushBusiness.AutomaticDelay,
-				                            ExternalId = order.Id,
-				                            OrderId = order.Id,
-				                            PushPlatform = EPushPlatform.Sms,
-				                            Remark = order.Title,
-				                            Name = user.Name,
-				                            TemplateCode = "1015",
-				                            Params = new List<string>() { order.No },
-				                            TelNumber = user.PhoneNo,
-			                            };
-			                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
-		                            }
-	                            }
+							else
+							{
+								delay.OrderId = order.Id;
+								delay.EmployeeId = "";
+								delay.EmployeeName = "系统自动延期";
+								delay.ApplyOrgName = OrgSeedData.CenterName;
+								delay.ApplyOrgCode = OrgSeedData.CenterId;
+								delay.DelayApplyType = EDelayApplyType.LocalApply;
+								delay.BeforeDelay = order.ExpiredTime;
+								delay.DelayState = EDelayState.Pass;
+								delay.DelayReason = "系统自动延期";
+								delay.ApplyDelayTime = DateTime.Now;
+								delay.No = order.No;
+								delay.AutomaticDelayNum = 1;
+								delay.DelayNum = 1;
+								delay.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
+								delay.IsProDelay = false;
+								delay.CreatorOrgId = OrgSeedData.CenterId;
+								delay.CreatorOrgName = OrgSeedData.CenterName;
+								delay.CreatorName = "系统自动延期";
+								if (delay.BeforeDelay != null)
+								{
+									delay.AfterDelay = (await _expireTime
+										.CalcEndTime(delay.BeforeDelay.Value, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+								}
+								await _orderDelayRepository.AddAsync(delay, false, cancellationToken);
+							}
+							//处理工单延期
+							await _orderApplication.DelayOrderExpiredTimeAsync(order.Id, delay.DelayNum,
+								delay.DelayUnit, delay.IsProDelay, cancellationToken);
+							//发送短信
+							var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
+							var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
+							if (steps.Any())
+							{
+								foreach (var step in steps)
+								{
+									var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
+									var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
+									if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
+									{
+										roleIds.Add(step.RoleId);
+									}
+									var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
+									foreach (var user in userList)
+									{
+										if (!string.IsNullOrEmpty(user.PhoneNo))
+										{
+											//发送短信
+											var messageDto = new Share.Dtos.Push.MessageDto
+											{
+												PushBusiness = EPushBusiness.AutomaticDelay,
+												ExternalId = order.Id,
+												OrderId = order.Id,
+												PushPlatform = EPushPlatform.Sms,
+												Remark = order.Title,
+												Name = user.Name,
+												TemplateCode = "1015",
+												Params = new List<string>() { order.No },
+												TelNumber = user.PhoneNo,
+											};
+											await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+										}
+									}
+								}
 							}
 						}
 					}
+					order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
+					_capPublisher.PublishDelay(order.ExpiredTime.Value - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay, new PublishAutomaticDelayDto() { OrderId = order.Id });
 				}
-                order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-				_capPublisher.PublishDelay(order.ExpiredTime.Value - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay, new PublishAutomaticDelayDto() { OrderId = order.Id });
 			}
+		
 		}
 
         /// <summary>

+ 5 - 0
src/Hotline.Share/Dtos/CallCenter/CallNativeDto.cs

@@ -132,5 +132,10 @@ namespace Hotline.Share.Dtos.CallCenter
         public string? OrderNo { get; set; }
 
         public string? Title { get; set; }
+
+        /// <summary>
+        /// 中继号码
+        /// </summary>
+        public string Gateway { get; set; }
     }
 }

+ 59 - 67
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -28,17 +28,14 @@ namespace Hotline.FlowEngine.Workflows
         private readonly IRepository<WorkflowStep> _workflowStepRepository;
         private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IRepository<WorkflowSupplement> _workflowSupplementRepository;
-
         private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
-
-        //private readonly IRepository<WorkflowStepHandler> _workflowStepHandlerRepository;
-        private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
         private readonly Publisher _publisher;
         private readonly ILogger<WorkflowDomainService> _logger;
         private readonly IFileRepository _fileRepository;
         private readonly IRepository<User> _userRepository;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+        private readonly ISessionContextProvider _sessionContextProvider;
 
         public WorkflowDomainService(
             IWorkflowRepository workflowRepository,
@@ -46,7 +43,6 @@ namespace Hotline.FlowEngine.Workflows
             IRepository<WorkflowTrace> workflowTraceRepository,
             IRepository<WorkflowSupplement> workflowSupplementRepository,
             IRepository<WorkflowCountersign> workflowCountersignRepository,
-            //IRepository<WorkflowStepHandler> workflowStepHandlerRepository,
             ISystemSettingCacheManager systemSettingCacheManager,
             ISessionContextProvider sessionContextProvider,
             IMapper mapper,
@@ -59,13 +55,12 @@ namespace Hotline.FlowEngine.Workflows
             _workflowTraceRepository = workflowTraceRepository;
             _workflowSupplementRepository = workflowSupplementRepository;
             _workflowCountersignRepository = workflowCountersignRepository;
-            //_workflowStepHandlerRepository = workflowStepHandlerRepository;
-            _sessionContext = sessionContextProvider.SessionContext;
             _mapper = mapper;
             _publisher = publisher;
             _logger = logger;
             _fileRepository = fileRepository;
             _systemSettingCacheManager = systemSettingCacheManager;
+            _sessionContextProvider = sessionContextProvider;
         }
 
         public async Task<Workflow> CreateWorkflowAsync(WorkflowModule wfModule, string title, string userId,
@@ -111,9 +106,9 @@ namespace Hotline.FlowEngine.Workflows
                     PublishStrategy.ParallelWhenAll, cancellationToken);
 
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
-                workflow.UpdateActualStepWhenHandle(startStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
+                workflow.UpdateActualStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
 
-                workflow.UpdateCurrentStepWhenHandle(startStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
+                workflow.UpdateCurrentStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
 
                 var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, expiredTime, cancellationToken);
                 return;
@@ -235,8 +230,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询工作流包含当前用户结束会签权限(是否可结束)
         /// </summary>
-        public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, WorkflowTrace?
-                Trace)>
+        public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, WorkflowTrace? Trace)>
             GetWorkflowHandlePermissionAsync(
                 string workflowId, string userId, string orgId, string[] roleIds,
                 CancellationToken cancellationToken = default)
@@ -284,13 +278,13 @@ namespace Hotline.FlowEngine.Workflows
             string? orgAreaCode, string? orgAreaName,
             CancellationToken cancellationToken)
         {
-            if (!workflow.IsCanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
-                    _sessionContext.Roles)) return;
+            if (!workflow.IsCanHandle(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId,
+                    _sessionContextProvider.SessionContext.Roles)) return;
             //工单完成以后查看的场景
             if (workflow.Status != EWorkflowStatus.Runnable) return;
 
-            var currentStep = GetUnHandleStep(workflow.Steps, _sessionContext.RequiredOrgId,
-                _sessionContext.RequiredUserId, _sessionContext.Roles);
+            var currentStep = GetUnHandleStep(workflow.Steps, _sessionContextProvider.SessionContext.RequiredOrgId,
+                _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.Roles);
             if (currentStep.Status is not EWorkflowStepStatus.WaitForAccept) return;
 
             if (currentStep.Handlers.All(d => d.Key != orgId && d.Key != userId)) return;
@@ -372,9 +366,9 @@ namespace Hotline.FlowEngine.Workflows
 
                     //结束会签
                     currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
-                        _sessionContext.RequiredUserId, _sessionContext.UserName,
-                        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
+                        _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                        _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                        _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName);
                     await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
                 }
             }
@@ -386,10 +380,10 @@ namespace Hotline.FlowEngine.Workflows
             if (isStartCountersign)
             {
                 var exists = workflow.Countersigns.Any(d =>
-                    !d.IsCompleted() && d.StarterId == _sessionContext.RequiredUserId);
+                    !d.IsCompleted() && d.StarterId == _sessionContextProvider.SessionContext.RequiredUserId);
                 if (exists)
                     throw new UserFriendlyException("该用户在当前流程存在未结束会签");
-                await StartCountersignAsync(_sessionContext, workflow, currentStep, dto, flowAssignInfo.FlowAssignType,
+                await StartCountersignAsync(_sessionContextProvider.SessionContext, workflow, currentStep, dto, flowAssignInfo.FlowAssignType,
                     counterSignType, expiredTime, cancellationToken);
             }
 
@@ -432,7 +426,7 @@ namespace Hotline.FlowEngine.Workflows
                         //throw new UserFriendlyException(
                         //    $"会签数据异常, workflowId: {currentStep.WorkflowId}, countersignId: {currentStep.CountersignId}",
                         //    "会签数据异常");
-                        countersign.MemberHandled(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
+                        countersign.MemberHandled(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId);
                         //update cs
                         await _workflowCountersignRepository.UpdateNav(countersign)
                             .Include(d => d.Members)
@@ -475,12 +469,12 @@ namespace Hotline.FlowEngine.Workflows
             if (workflow.ActualHandleStepId == currentStep.Id)
             {
                 //更新实际办理节点信息
-                workflow.UpdateActualStepWhenHandle(currentStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
+                workflow.UpdateActualStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
             }
 
             if (workflow.CurrentStepId == currentStep.Id)
             {
-                workflow.UpdateCurrentStepWhenHandle(currentStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
+                workflow.UpdateCurrentStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
             }
 
             //检查是否流转到流程终点
@@ -526,7 +520,7 @@ namespace Hotline.FlowEngine.Workflows
 
             //更新会签实际办理对象信息
             if (currentStep.IsActualHandled)
-                workflow.AddCsActualHandler(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
+                workflow.AddCsActualHandler(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId);
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
@@ -541,7 +535,7 @@ namespace Hotline.FlowEngine.Workflows
             var currentTrace = workflow.Traces.First(d => d.Id == currentStep.Id);
             await _publisher.PublishAsync(
                 new NextStepNotify(workflow, dto, flowAssignInfo, currentTrace, nextStepDefine,
-                    _sessionContext.RequiredOrgId, expiredTime.HasValue), PublishStrategy.ParallelWhenAll,
+                    _sessionContextProvider.SessionContext.RequiredOrgId, expiredTime.HasValue), PublishStrategy.ParallelWhenAll,
                 cancellationToken);
         }
 
@@ -822,9 +816,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 批量修改工单办理对象
         /// </summary>
         public async Task ChangeHandlerBatchAsync(
-            IReadOnlyList<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep>
-                steps
-                )> handlers,
+            IReadOnlyList<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)> handlers,
             CancellationToken cancellationToken)
         {
             foreach (var handler in handlers)
@@ -992,7 +984,7 @@ namespace Hotline.FlowEngine.Workflows
         {
             var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
                 cancellationToken: cancellationToken);
-            // workflow.Assign(EFlowAssignType.User, _sessionContext.RequiredUserId);
+            // workflow.Assign(EFlowAssignType.User, _sessionContextProvider.SessionContext.RequiredUserId);
             //
             // workflow.HandlerOrgs = new();
             // workflow.HandlerUsers = new List<HandlerGroupItem>
@@ -1399,7 +1391,7 @@ namespace Hotline.FlowEngine.Workflows
                 case EPathPolicy.DirectUpper:
                     break;
                 case EPathPolicy.DirectUpperCenterIsTop:
-                    var currentOrgLevel = _sessionContext.RequiredOrgId.CalcOrgLevel();
+                    var currentOrgLevel = _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel();
                     if (currentOrgLevel == 1)
                     {
                         nextStepDefines = nextStepDefines.Where(d => d.IsCenter()).ToList();
@@ -1430,9 +1422,9 @@ namespace Hotline.FlowEngine.Workflows
             var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
                 cancellationToken: cancellationToken);
 
-            var currentStep = GetUnHandleStep(workflow.Steps, _sessionContext.RequiredOrgId,
-                _sessionContext.RequiredUserId, _sessionContext.Roles);
-            //var (currentStepBox, currentStep) = GetUnCompleteStep(workflow.Steps, _sessionContext.RequiredOrgId, _sessionContext.RequiredUserId);
+            var currentStep = GetUnHandleStep(workflow.Steps, _sessionContextProvider.SessionContext.RequiredOrgId,
+                _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.Roles);
+            //var (currentStepBox, currentStep) = GetUnCompleteStep(workflow.Steps, _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.RequiredUserId);
 
             var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
 
@@ -1518,7 +1510,7 @@ namespace Hotline.FlowEngine.Workflows
             workflow.Complete(endStep, dto.ReviewResult);
 
             //需求调整:归档时当前节点显示为归档节点
-            workflow.UpdateCurrentStepWhenHandle(endStep, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, _sessionContext.OrgLevel);
+            workflow.UpdateCurrentStepWhenHandle(endStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
             workflow.UpdateCurrentStepAcceptTime(endStep.AcceptTime.Value);
 
             //workflow.UpdateActualStepWhenHandle(endStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
@@ -1554,7 +1546,7 @@ namespace Hotline.FlowEngine.Workflows
         public ECounterSignType? GetCounterSignType(bool isStartCountersign)
         {
             if (!isStartCountersign) return null;
-            return _sessionContext.OrgIsCenter ? ECounterSignType.Center : ECounterSignType.Department;
+            return _sessionContextProvider.SessionContext.OrgIsCenter ? ECounterSignType.Center : ECounterSignType.Department;
         }
 
         /// <summary>
@@ -1945,10 +1937,10 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         private void HandleStep(WorkflowStep step, string opinion, string nextStepCode)
         {
-            step.Handle(_sessionContext.RequiredUserId, _sessionContext.UserName,
-                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-                _sessionContext.OrgIsCenter, opinion, nextStepCode);
+            step.Handle(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName,
+                _sessionContextProvider.SessionContext.OrgIsCenter, opinion, nextStepCode);
 
             //var handler = step.FindActualHandler(current.Roles, current.RequiredUserId, current.RequiredOrgId);
             //if (handler is not null)
@@ -2275,10 +2267,10 @@ namespace Hotline.FlowEngine.Workflows
                 foreach (var trace in uncompleteTraces)
                 {
                     trace.Handle(
-                        _sessionContext.RequiredUserId, _sessionContext.UserName,
-                        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-                        _sessionContext.OrgIsCenter, dto.Opinion);
+                        _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                        _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                        _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName,
+                        _sessionContextProvider.SessionContext.OrgIsCenter, dto.Opinion);
                 }
 
                 //await _workflowTraceRepository.UpdateRangeAsync(uncompleteTraces, cancellationToken);
@@ -2333,9 +2325,9 @@ namespace Hotline.FlowEngine.Workflows
                 foreach (var unCompleteCountersign in unCompleteCountersigns)
                 {
                     unCompleteCountersign.End(null, null, EBusinessType.File,
-                        _sessionContext.RequiredUserId, _sessionContext.UserName,
-                        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
+                        _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                        _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                        _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName);
                 }
 
                 await _workflowCountersignRepository.UpdateRangeAsync(unCompleteCountersigns, cancellationToken);
@@ -2427,21 +2419,21 @@ namespace Hotline.FlowEngine.Workflows
 
             var handler = new FlowStepHandler
             {
-                Key = _sessionContext.UserId,
-                Value = _sessionContext.UserName,
-                UserId = _sessionContext.RequiredUserId,
-                Username = _sessionContext.UserName,
-                OrgId = _sessionContext.OrgId,
-                OrgName = _sessionContext.OrgName,
+                Key = _sessionContextProvider.SessionContext.UserId,
+                Value = _sessionContextProvider.SessionContext.UserName,
+                UserId = _sessionContextProvider.SessionContext.RequiredUserId,
+                Username = _sessionContextProvider.SessionContext.UserName,
+                OrgId = _sessionContextProvider.SessionContext.OrgId,
+                OrgName = _sessionContextProvider.SessionContext.OrgName,
             };
 
             var step = CreateStep(workflow, endStepDefine, prevStep, EFlowAssignType.User, handler,
                 null, null, EWorkflowStepStatus.WaitForAccept,
                 ECountersignPosition.None, expiredTime, endStepDefine.Name, true, businessType: EBusinessType.File,flowDirection: dto.FlowDirection);
 
-            //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
-            //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-            //    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
+            //step.Accept(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+            //    _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+            //    _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName);
 
             HandleStep(step, "流程归档", string.Empty);
 
@@ -2589,7 +2581,7 @@ namespace Hotline.FlowEngine.Workflows
                         throw new UserFriendlyException(
                             $"TerminalDynamicMark parse to int failed, tMark: {currentStepDefine.TerminalDynamicMark}");
                     var leadRoleCode = _systemSettingCacheManager.GetSetting(SettingConstants.RoleLingDao)?.SettingValue[0];
-                    var isLead = _sessionContext.Roles.Any(x => x == leadRoleCode);
+                    var isLead = _sessionContextProvider.SessionContext.Roles.Any(x => x == leadRoleCode);
                     return (currentOrgLevel <= tMark2) && isLead;
                 case EDynamicPolicy.OrgDownCenterTop:
                 case EDynamicPolicy.OrgDown:
@@ -2724,16 +2716,16 @@ namespace Hotline.FlowEngine.Workflows
             ref List<WorkflowStep> updateSteps, ref List<WorkflowTrace> updateTraces)
         {
             var isHandled = step.Status is EWorkflowStepStatus.Handled;
-            var opinion = $"会签未办理完成,由 {_sessionContext.OrgName} 的 {_sessionContext.UserName} 终止办理";
+            var opinion = $"会签未办理完成,由 {_sessionContextProvider.SessionContext.OrgName} 的 {_sessionContextProvider.SessionContext.UserName} 终止办理";
             if (step.IsStartCountersign)
                 step.CountersignEnd();
 
             if (step.Status is not EWorkflowStepStatus.Handled)
             {
-                step.Handle(_sessionContext.RequiredUserId, _sessionContext.UserName,
-                    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-                    _sessionContext.OrgIsCenter, opinion);
+                step.Handle(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                    _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                    _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName,
+                    _sessionContextProvider.SessionContext.OrgIsCenter, opinion);
             }
 
             updateSteps.Add(step);
@@ -2776,9 +2768,9 @@ namespace Hotline.FlowEngine.Workflows
             //todo 1. trace? 先确定展现形式 2. end cs
 
             countersign.End(null, null, businessType,
-                _sessionContext.RequiredUserId, _sessionContext.UserName,
-                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
+                _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName);
 
             /*
             * //结束step会签信息
@@ -2787,9 +2779,9 @@ namespace Hotline.FlowEngine.Workflows
 
                    //结束会签
                    currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
-                       _sessionContext.RequiredUserId, _sessionContext.UserName,
-                       _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                       _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
+                       _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.UserName,
+                       _sessionContextProvider.SessionContext.RequiredOrgId, _sessionContextProvider.SessionContext.OrgName,
+                       _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName);
                    await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
             */
 

+ 17 - 6
src/Hotline/Settings/TimeLimitDomain/ExpireTimeLimitBase.cs

@@ -121,7 +121,7 @@ public abstract class ExpireTimeLimitBase
     /// </summary>
     /// <param name="code"></param>
     /// <returns></returns>
-    public virtual TimeConfig GetOrderTimeLimitConfig(string? code = null)
+    public TimeConfig GetOrderTimeLimitConfigBase(string? code = null)
     {
         if (string.IsNullOrEmpty(code))
         {
@@ -135,6 +135,17 @@ public abstract class ExpireTimeLimitBase
         }
     }
 
+    /// <summary>
+    /// 获取办理时限配置
+    /// </summary>
+    /// <param name="code"></param>
+    /// <returns></returns>
+    public virtual TimeConfig GetOrderTimeLimitConfig(string? code = null)
+    {
+        return GetOrderTimeLimitConfigBase(code);
+    }
+
+
     /// <summary>
     /// 计算期满时间
     /// </summary>
@@ -149,11 +160,11 @@ public abstract class ExpireTimeLimitBase
             throw new UserFriendlyException("中心派至部门的工单期满时间需受理类型参数");
         var timeConfig = flowDirection switch
         {
-            EFlowDirection.CenterToOrg => GetOrderTimeLimitConfig(order.AcceptTypeCode),
-            EFlowDirection.OrgToCenter => GetOrderTimeLimitConfig(),
-            EFlowDirection.FiledToCenter => GetOrderTimeLimitConfig(),
-			EFlowDirection.CenterToCenter => GetOrderTimeLimitConfig(order.AcceptTypeCode),
-            EFlowDirection.FiledToOrg => GetOrderTimeLimitConfig(order.AcceptTypeCode),
+            EFlowDirection.CenterToOrg => GetOrderTimeLimitConfigBase(order.AcceptTypeCode),
+            EFlowDirection.OrgToCenter => GetOrderTimeLimitConfigBase(),
+            EFlowDirection.FiledToCenter => GetOrderTimeLimitConfigBase(),
+			EFlowDirection.CenterToCenter => GetOrderTimeLimitConfigBase(order.AcceptTypeCode),
+            EFlowDirection.FiledToOrg => GetOrderTimeLimitConfigBase(order.AcceptTypeCode),
 			_ => throw new ArgumentOutOfRangeException(nameof(flowDirection), flowDirection, null)
         };
 

+ 6 - 1
src/Hotline/Settings/TimeLimitDomain/ZiGongExpireTimeLimit.cs

@@ -61,6 +61,11 @@ public class ZiGongExpireTimeLimit : ExpireTimeLimitBase, ICalcExpireTime, IScop
         return await base.CalcExpiredTime(beginTime, flowDirection, order);
     }
 
+    public override TimeConfig GetOrderTimeLimitConfig(string? code = null)
+    {
+        return GetTimeConfigByOrderAsync(new OrderTimeClacInfo(code)).GetAwaiter().GetResult();
+    }
+
     /// <summary>
     /// 根据订单信息获取时间配置
     /// </summary>
@@ -109,7 +114,7 @@ public class ZiGongExpireTimeLimit : ExpireTimeLimitBase, ICalcExpireTime, IScop
                 return false;
             return true;
         });
-        if (busCode is null && code.IsNullOrEmpty()) base.GetOrderTimeLimitConfig();
+        if (busCode.IsNullOrEmpty() && code.IsNullOrEmpty()) base.GetOrderTimeLimitConfigBase();
         var inventory = await _timeLimitSettingInventoryRepository.GetByCode(code);
         if (inventory is not null) return inventory.Adapt<TimeConfig>();
         var timeConfig = await _timeLimitSettingRepository.GetByBusCode(busCode)