Эх сурвалжийг харах

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

田爽 10 сар өмнө
parent
commit
c19a5ca2c4
30 өөрчлөгдсөн 663 нэмэгдсэн , 102 устгасан
  1. 1 0
      src/Hotline.Api/Controllers/IdentityController.cs
  2. 144 3
      src/Hotline.Api/Controllers/OrderController.cs
  3. 1 0
      src/Hotline.Api/Controllers/WebPortalController.cs
  4. 18 0
      src/Hotline.Api/Controllers/WorkflowController.cs
  5. 9 1
      src/Hotline.Api/Realtimes/RealtimeMethods.cs
  6. 13 1
      src/Hotline.Api/Realtimes/RealtimeService.cs
  7. 1 0
      src/Hotline.Application/Bigscreen/DataScreenRefreshService.cs
  8. 1 0
      src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs
  9. 43 0
      src/Hotline.Application/CallCenter/Calls/CurrentWaitNumService.cs
  10. 43 0
      src/Hotline.Application/CallCenter/Calls/ToDayWaitNumService.cs
  11. 1 0
      src/Hotline.Application/CallCenter/Calls/TrApplication.cs
  12. 1 0
      src/Hotline.Application/Handlers/FlowEngine/WorkflowRecallHandler.cs
  13. 27 11
      src/Hotline.Application/Identity/IdentityAppService.cs
  14. 1 0
      src/Hotline.Application/Orders/OrderApplication.cs
  15. 1 0
      src/Hotline.Application/Quality/QualityApplication.cs
  16. 9 0
      src/Hotline.Share/Dtos/FlowEngine/Workflow/ChangeHandlerDto.cs
  17. 15 0
      src/Hotline.Share/Dtos/Order/Migration/GetOrderMigrationDto.cs
  18. 128 0
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  19. 19 0
      src/Hotline.Share/Enums/Order/EVisitState.cs
  20. 12 0
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  21. 32 0
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  22. 3 2
      src/Hotline/Orders/IOrderDomainService.cs
  23. 38 76
      src/Hotline/Orders/OrderDomainService.cs
  24. 31 0
      src/Hotline/Orders/OrderVisit.cs
  25. 1 0
      src/Hotline/Push/MessageCodeDomainService.cs
  26. 1 0
      src/Hotline/Quality/QualityDomainService.cs
  27. 19 1
      src/Hotline/Realtimes/IRealtimeService.cs
  28. 15 7
      src/Hotline/Settings/SettingConstants.cs
  29. 7 0
      src/Tr.Sdk/Tels/ITrClient.Tel.cs
  30. 28 0
      src/Tr.Sdk/Tels/QueryQueueWaitNumRequest.cs

+ 1 - 0
src/Hotline.Api/Controllers/IdentityController.cs

@@ -7,6 +7,7 @@ using System.Security.Cryptography;
 using System.Text;
 using Hotline.Api.Filter;
 using Hotline.Application.Systems;
+using Hotline.Settings;
 using XC.RSAUtil;
 using XF.Domain.Constants;
 using XF.Domain.Exceptions;

+ 144 - 3
src/Hotline.Api/Controllers/OrderController.cs

@@ -29,6 +29,7 @@ using Hotline.Share.Dtos.Enterprise;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Order.Migration;
 using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.FlowEngine;
@@ -44,7 +45,9 @@ using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.OpenApi.Writers;
 using MiniExcelLibs;
+using MongoDB.Driver;
 using NPOI.SS.Formula.Functions;
 using NPOI.SS.Util;
 using Org.BouncyCastle.Utilities;
@@ -399,6 +402,7 @@ public class OrderController : BaseController
         orderVisit.VisitState = EVisitState.WaitForVisit;
         orderVisit.PublishTime = DateTime.Now;
         orderVisit.IsCanHandle = true;
+        orderVisit.EmployeeId = _sessionContext.RequiredUserId;
 
         if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
         {
@@ -592,6 +596,30 @@ public class OrderController : BaseController
             .OrderByDescending(x => x.CreationTime).ToListAsync(HttpContext.RequestAborted);
     }
 
+    /// <summary>
+    /// 查询发布平移待办理人
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    /// <exception cref="UserFriendlyException"></exception>
+    [HttpGet("published/migration")]
+    public async Task<IReadOnlyList<FlowStepHandler>> PublishMigration()
+    {
+        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan);
+        var roles = setting?.SettingValue.ToList();
+        var users = await _userRepository.Queryable()
+            .Includes(d => d.Organization)
+            .Where(d => d.Roles.Any(x => roles.Contains(x.Name)))
+            .ToListAsync(HttpContext.RequestAborted);
+        return users.Select(d => new FlowStepHandler
+        {
+            UserId = d.Id,
+            Username = d.Name,
+            OrgId = d.OrgId,
+            OrgName = d.Organization.Name
+        }).ToList();
+    }
+
     #endregion
 
     #region 工单回访
@@ -640,8 +668,6 @@ public class OrderController : BaseController
         return rsp;
     }
 
-
-
     /// <summary>
     /// 回访详情
     /// </summary>
@@ -720,7 +746,6 @@ public class OrderController : BaseController
         return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
     }
 
-
     /// <summary>
     /// 回访保存
     /// </summary>
@@ -769,7 +794,13 @@ public class OrderController : BaseController
         {
             visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
         }
+        visit.OrgJudge = dto.OrgJudge;
+        visit.SeatJudge = dto.SeatJudge;
 
+        if (visit.OrgJudge==true || visit.SeatJudge==true)
+        {
+            visit.JudgeState = EJudgeState.Judging;
+        }
         //_mapper.Map(dto.VisitDetails,visit.OrderVisitDetails);
         for (int i = 0; i < visit.OrderVisitDetails.Count; i++)
         {
@@ -834,6 +865,72 @@ public class OrderController : BaseController
         //}
     }
 
+    /// <summary>
+    /// 扭转列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("visit/judge-query")]
+    public async Task<PagedDto<OrderVisitDto>> VisitJudgeQuery([FromQuery] VisitJudgeQueryReq dto)
+    {
+        var (total,items) =await _orderVisitRepository.Queryable()
+            .Includes(x => x.Order)
+            .Includes(x => x.Employee)
+            .Where(x => x.VisitState == EVisitState.Visited)
+            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No == dto.No)
+            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title))
+            .WhereIF(!string.IsNullOrEmpty(dto.VisitUserName), x => x.Employee.Name.Contains(dto.VisitUserName))
+            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.Order.AcceptTypeCode)) //受理类型
+            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.Order.HotspotId)) //热点类型
+            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.Order.ActualHandleOrgCode)) //接办部门
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Order.AcceptorName.Contains(dto.NameOrNo!) || d.Order.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
+            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+            .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.Order.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
+            .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.Order.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
+            .WhereIF(dto.VisitTimeStart.HasValue, d => d.VisitTime >= dto.VisitTimeStart) //回访开始时间
+            .WhereIF(dto.VisitTimeEnd.HasValue, d => d.VisitTime <= dto.VisitTimeEnd)
+            .WhereIF(dto.IsIng == true, d=>d.JudgeState == EJudgeState.Judging)
+            .WhereIF(dto.IsIng == false,d=>d.JudgeState != EJudgeState.Judging)
+            .WhereIF(dto.JudgeState!=null,d=>d.JudgeState == dto.JudgeState)
+            .WhereIF(dto.OrgJudge!=null,d=>d.OrgJudge == dto.OrgJudge)
+            .WhereIF(dto.SeatJudge!=null,d=>d.SeatJudge == dto.SeatJudge)
+            .OrderByDescending(x => x.VisitTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
+    }
+
+    /// <summary>
+    /// 扭转满意度
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("visit/judge")]
+    public async Task<JudgeVisitRsp> JudgeVisit([FromBody] JudgeVisitReq dto)
+    {
+        int error = 0;
+        foreach (var id in dto.Ids)
+        {
+            var visit = await _orderVisitRepository.Queryable().FirstAsync(d => d.Id == id, HttpContext.RequestAborted);
+            if (visit!= null && visit.VisitState == EVisitState.Visited)
+            {
+                visit.JudgeState = dto.IsAgree ? EJudgeState.Agreed : EJudgeState.UnAgreed;
+                visit.JudgeUserId = _sessionContext.RequiredUserId;
+                visit.JudgeUserName = _sessionContext.UserName;
+                visit.JudgeTime = DateTime.Now;
+                visit.JudgeContent = dto.JudgeContent;
+                await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
+            }
+            else
+            {
+                error++;
+            }
+        }
+        return new JudgeVisitRsp() { ErrorCount = error, SuccessCount = dto.Ids.Count - error };
+    }
+
+
+
     /// <summary>
     /// 批量分配回访人员
     /// </summary>
@@ -5403,4 +5500,48 @@ public class OrderController : BaseController
         return _mapper.Map<IReadOnlyList<OrderModifyingRecordsDto>>(list);
     }
     #endregion
+
+    #region 工单平移
+
+    /// <summary>
+    /// 查询工单平移待办理人
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("migration/{orderId}")]
+    public async Task<GetOrderMigrationDto> Migration(string orderId)
+    {
+        var steps = await _workflowStepRepository.Queryable()
+            .Where(d => d.ExternalId == orderId && d.Status != EWorkflowStepStatus.Handled)
+            .ToListAsync(HttpContext.RequestAborted);
+
+        if (!steps.Any())
+            throw new UserFriendlyException("未查询到待办理节点");
+        if (steps.Count > 1)
+            throw new UserFriendlyException("多个待办理节点暂不支持平移");
+        var step = steps.First();
+        if (step.BusinessType is not EBusinessType.Center and EBusinessType.Send)
+            throw UserFriendlyException.SameMessage("当前办理节点非中心暂不支持平移");
+
+        var setting = step.BusinessType is EBusinessType.Center
+            ? _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi)
+            : _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan);
+        var roles = setting?.SettingValue.ToList();
+        var users = await _userRepository.Queryable()
+            .Includes(d => d.Organization)
+            .Where(d => d.Roles.Any(x => roles.Contains(x.Name)))
+            .ToListAsync(HttpContext.RequestAborted);
+        return new GetOrderMigrationDto
+        {
+            StepId = step.Id,
+            Handlers = users.Select(d => new FlowStepHandler
+            {
+                UserId = d.Id,
+                Username = d.Name,
+                OrgId = d.OrgId,
+                OrgName = d.Organization.Name
+            }).ToList()
+        };
+    }
+
+    #endregion
 }

+ 1 - 0
src/Hotline.Api/Controllers/WebPortalController.cs

@@ -26,6 +26,7 @@ using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
 using Hotline.Share.Dtos.Order;
 using Org.BouncyCastle.Ocsp;
 using System.Threading;
+using Hotline.Settings;
 
 namespace Hotline.Api.Controllers
 {

+ 18 - 0
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -45,6 +45,7 @@ public class WorkflowController : BaseController
     private readonly IRepository<Role> _roleRepository;
     private readonly ISystemDomainService _systemDomainService;
     private readonly IWfModuleDomainService _wfModuleDomainService;
+    private readonly IRepository<WorkflowStep> _workflowStepRepository;
     private readonly IRepository<WorkflowModule> _wfModuleRepository;
     private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
     private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
@@ -66,6 +67,7 @@ public class WorkflowController : BaseController
         IRepository<Role> roleRepository,
         ISystemDomainService systemDomainService,
         IWfModuleDomainService wfModuleDomainService,
+        IRepository<WorkflowStep> workflowStepRepository,
         IRepository<WorkflowModule> wfModuleRepository,
         IRepository<WorkflowTrace> workflowTraceRepository,
         IRepository<WorkflowCountersign> workflowCountersignRepository,
@@ -87,6 +89,7 @@ public class WorkflowController : BaseController
         _roleRepository = roleRepository;
         _systemDomainService = systemDomainService;
         _wfModuleDomainService = wfModuleDomainService;
+        _workflowStepRepository = workflowStepRepository;
         _wfModuleRepository = wfModuleRepository;
         _sessionContext = sessionContext;
         _mapper = mapper;
@@ -650,6 +653,21 @@ public class WorkflowController : BaseController
         };
     }
 
+    /// <summary>
+    /// 改变某节点办理人
+    /// </summary>
+    [HttpPost("change-handler")]
+    public async Task ChangeHandler([FromBody] ChangeHandlerDto dto)
+    {
+        var step = await _workflowStepRepository.GetAsync(dto.StepId, HttpContext.RequestAborted);
+        if (step is null)
+            throw new UserFriendlyException("无效节点编号");
+        await _workflowDomainService.ChangeHandlerBatchAsync(new List<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)>
+            {
+                new(dto.Handler.UserId,dto.Handler.Username,dto.Handler.OrgId,dto.Handler.OrgName, new List<WorkflowStep>{step})
+            }, HttpContext.RequestAborted);
+    }
+
     #endregion
 
 }

+ 9 - 1
src/Hotline.Api/Realtimes/RealtimeMethods.cs

@@ -73,7 +73,15 @@
         #endregion
 
         #region 司法大屏
-        public static string EnforcementOrderHandlingDetail = "EnforcementOrderHandlingDetail"; 
+        public static string EnforcementOrderHandlingDetail = "EnforcementOrderHandlingDetail";
+        #endregion
+
+        #region 话务排队信息
+
+        public static string ToDayWaitNum = "ToDayWaitNum";
+
+        public static string CurrentWaitNum = "CurrentWaitNum";
+
         #endregion
     }
 }

+ 13 - 1
src/Hotline.Api/Realtimes/RealtimeService.cs

@@ -230,8 +230,17 @@ public class RealtimeService : IRealtimeService, IScopeDependency
     public Task EnforcementOrderHandlingDetailAsync(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.EnforcementBigDataScreen, RealtimeMethods.EnforcementOrderHandlingDetail, obj, cancellationToken);
 
-    
 
+    #region 话务排队信息
+
+    public Task TodayWaitNumAsync(int count, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.CallCenter, RealtimeMethods.ToDayWaitNum, count, cancellationToken);
+
+    public Task CurrentWaitNumAsync(int count, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.CallCenter, RealtimeMethods.CurrentWaitNum, count, cancellationToken);
+
+
+    #endregion
     #region private
 
     private async Task SendCallCenterMsgAsync(string userId, string msg, object? value, CancellationToken cancellationToken)
@@ -264,4 +273,7 @@ public class RealtimeService : IRealtimeService, IScopeDependency
         _hubContext.Clients.Group(groupName).SendAsync(method, value, cancellationToken);
 
     #endregion
+
+   
+
 }

+ 1 - 0
src/Hotline.Application/Bigscreen/DataScreenRefreshService.cs

@@ -12,6 +12,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Settings;
 using XF.Domain.Constants;
 
 namespace Hotline.Application.Bigscreen

+ 1 - 0
src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs

@@ -1,5 +1,6 @@
 using Hotline.Caching.Interfaces;
 using Hotline.Realtimes;
+using Hotline.Settings;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;

+ 43 - 0
src/Hotline.Application/CallCenter/Calls/CurrentWaitNumService.cs

@@ -0,0 +1,43 @@
+using Hotline.Caching.Interfaces;
+using Hotline.Realtimes;
+using Hotline.Settings;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.CallCenter.Calls
+{
+    public class CurrentWaitNumService : BackgroundService
+    {
+        private readonly IServiceScopeFactory _serviceScopeFactory;
+
+        public CurrentWaitNumService(IServiceScopeFactory serviceScopeFactory)
+        {
+            _serviceScopeFactory = serviceScopeFactory;
+        }
+
+        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            using var scope = _serviceScopeFactory.CreateScope();
+            var realtimeService = scope.ServiceProvider.GetRequiredService<IRealtimeService>();
+            var _systemSettingCacheManager = scope.ServiceProvider.GetRequiredService<ISystemSettingCacheManager>();
+            int times = 3000;//5秒
+            var callinQueueIds = _systemSettingCacheManager.GetSetting(SettingConstants.CallInQueueId)?.SettingValue.ToList();
+            while(!stoppingToken.IsCancellationRequested)
+            {
+                try
+                {
+
+                }
+                catch{}
+                await Task.Delay(times);
+            }
+
+
+        }
+    }
+}

+ 43 - 0
src/Hotline.Application/CallCenter/Calls/ToDayWaitNumService.cs

@@ -0,0 +1,43 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Realtimes;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.CallCenter.Calls
+{
+    public class ToDayWaitNumService : BackgroundService
+    {
+        private readonly IServiceScopeFactory _serviceScopeFactory;
+        public ToDayWaitNumService(IServiceScopeFactory serviceScopeFactory)
+        {
+                _serviceScopeFactory = serviceScopeFactory;
+        }
+
+        protected async override Task ExecuteAsync(CancellationToken stoppingToken)
+        {
+            using var scope = _serviceScopeFactory.CreateScope();
+            var realtimeService = scope.ServiceProvider.GetRequiredService<IRealtimeService>();
+            var _trcallrecordRepoository = scope.ServiceProvider.GetRequiredService<IRepository<TrCallRecord>>();
+            int times = 60000;//一分钟
+            while (!stoppingToken.IsCancellationRequested)
+            {
+                try
+                {
+                    int count = await _trcallrecordRepoository.Queryable()
+                        .Where(x => x.CreatedTime.Date == DateTime.Now.Date)
+                        .Where(x => x.QueueTims > 0 && x.Duration == 0)
+                        .CountAsync();
+                    await realtimeService.TodayWaitNumAsync(count, stoppingToken);
+                }
+                catch {}
+                await Task.Delay(times);
+            }
+        }
+    }
+}

+ 1 - 0
src/Hotline.Application/CallCenter/Calls/TrApplication.cs

@@ -1,6 +1,7 @@
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Tels;
+using Hotline.Settings;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.CallCenter;

+ 1 - 0
src/Hotline.Application/Handlers/FlowEngine/WorkflowRecallHandler.cs

@@ -4,6 +4,7 @@ using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Orders;
+using Hotline.Settings;
 using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.FlowEngine;

+ 27 - 11
src/Hotline.Application/Identity/IdentityAppService.cs

@@ -1,18 +1,23 @@
 using System.Security.Claims;
+using Hotline.Caching.Interfaces;
 using Hotline.Identity;
 using Hotline.Identity.Accounts;
 using Hotline.Orders;
 using Hotline.Push;
 using Hotline.Schedulings;
 using Hotline.Settings;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Identity;
+using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Identity;
 using Hotline.Users;
 using IdentityModel;
+using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Identity;
 using Microsoft.Extensions.Options;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
+using XF.Domain.Constants;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Options;
@@ -31,8 +36,9 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
     private readonly IMessageCodeDomainService _messageCodeDomainService;
     private readonly IRepository<Scheduling> _schedulingRepository;
     private readonly IOrderDomainService _orderDomainService;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
-    public IdentityAppService(
+	public IdentityAppService(
         IAccountRepository accountRepository,
         IAccountDomainService accountDomainService,
         IRepository<User> userRepository,
@@ -41,7 +47,8 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         ITypedCache<AudienceTicket> cacheAudience,
         IMessageCodeDomainService messageCodeDomainService,
         IRepository<Scheduling> schedulingRepository,
-         IOrderDomainService orderDomainService)
+        IOrderDomainService orderDomainService,
+        ISystemSettingCacheManager systemSettingCacheManager)
     {
         _accountRepository = accountRepository;
         _accountDomainService = accountDomainService;
@@ -52,7 +59,9 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         _messageCodeDomainService = messageCodeDomainService;
         _schedulingRepository = schedulingRepository;
         _orderDomainService = orderDomainService;
-    }
+        _systemSettingCacheManager = systemSettingCacheManager;
+
+	}
 
     public async Task<string> LoginAsync(LoginDto dto, CancellationToken cancellationToken)
     {
@@ -99,9 +108,12 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
             .FirstAsync(d => d.Id == account.Id);
         if (user == null)
             throw UserFriendlyException.SameMessage("未查询到用户数据");
-        //平均派单
-        await AverageOrderScheduling(account.Id, cancellationToken);
-
+		//平均派单
+		var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+		if (averageSendOrder)
+		{
+			await AverageOrderScheduling(account.Id, cancellationToken);
+		}
         var jwtOptions = _identityOptionsAccessor.Value.Jwt;
         var claims = new List<Claim>
         {
@@ -141,18 +153,22 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         try
         {
             DateTime time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
-
+            
             //&& x.AtWork!.Value != true
             //根据当前时间获取排班信息
-            var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
-                .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && (x.AtWork == true || x.AtWork == null) && x.SchedulingUser.UserId == id)
+            var scheduling = await _schedulingRepository.Queryable()
+                .Includes(x => x.SchedulingUser)
+                .Where(x => x.SchedulingTime == time &&
+                            x.WorkingTime <= DateTime.Now.TimeOfDay && 
+                            x.OffDutyTime >= DateTime.Now.TimeOfDay && 
+                            (x.AtWork == true || x.AtWork == null) && 
+                            x.SchedulingUser.UserId == id)
                 .OrderBy(x => x.SendOrderNum).FirstAsync(cancellationToken);
             if (scheduling != null)
             {
                 scheduling.AtWork = true;
-                await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
                 //执行登录平均派单
-                await _orderDomainService.LogAverageOrder(id, cancellationToken);
+                await _orderDomainService.LogAverageOrder(id, scheduling, cancellationToken);
             }
         }
         catch

+ 1 - 0
src/Hotline.Application/Orders/OrderApplication.cs

@@ -26,6 +26,7 @@ using Novacode;
 using SqlSugar;
 using System.Data;
 using System.Dynamic;
+using Hotline.Settings;
 using XF.Domain.Authentications;
 using XF.Domain.Constants;
 using XF.Domain.Dependency;

+ 1 - 0
src/Hotline.Application/Quality/QualityApplication.cs

@@ -3,6 +3,7 @@ using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
 using Hotline.Orders;
 using Hotline.Quality;
+using Hotline.Settings;
 using Hotline.Share.Dtos.Quality;
 using Hotline.Share.Enums.Quality;
 using MapsterMapper;

+ 9 - 0
src/Hotline.Share/Dtos/FlowEngine/Workflow/ChangeHandlerDto.cs

@@ -0,0 +1,9 @@
+using Hotline.Share.Dtos.FlowEngine;
+
+namespace Hotline.Share.Dtos.FlowEngine.Workflow;
+
+public class ChangeHandlerDto
+{
+    public string StepId { get; set; }
+    public FlowStepHandler Handler { get; set; }
+}

+ 15 - 0
src/Hotline.Share/Dtos/Order/Migration/GetOrderMigrationDto.cs

@@ -0,0 +1,15 @@
+using Hotline.Share.Dtos.FlowEngine;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Order.Migration
+{
+    public class GetOrderMigrationDto
+    {
+        public string StepId { get; set; }
+        public IReadOnlyList<FlowStepHandler> Handlers { get; set; }
+    }
+}

+ 128 - 0
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -35,6 +35,105 @@ namespace Hotline.Share.Dtos.Order
         public EVisitType? VisitType { get; set; }
     }
 
+    public record VisitJudgeQueryReq:PagedKeywordRequest
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string? Title { get; set; }
+        /// <summary>
+        /// 回访人
+        /// </summary>
+        public string? VisitUserName { get; set; }
+        /// <summary>
+        /// 来电号码
+        /// </summary>
+        public string? FromPhone { get; set; }
+
+        /// <summary>
+        /// 受理类型
+        /// </summary>
+        public List<string> AcceptTypes { get; set; } = new();
+
+        /// <summary>
+        /// 热点分类
+        /// </summary>
+        public List<string> HotspotIds { get; set; } = new();
+
+        /// <summary>
+        /// 接办部门
+        /// </summary>
+        public List<string> OrgCodes { get; set; } = new();
+
+        /// <summary>
+        /// 受理坐席名字或工号
+        /// </summary>
+        public string? NameOrNo { get; set; }
+
+        /// <summary>
+        /// 受理时间(工单创建时间)
+        /// </summary>
+        public DateTime? CreationTimeStart { get; set; }
+        public DateTime? CreationTimeEnd { get; set; }
+
+        /// <summary>
+        /// 办结时间
+        /// </summary>
+        public DateTime? ActualHandleTimeStart { get; set; }
+        public DateTime? ActualHandleTimeEnd { get; set; }
+        /// <summary>
+        /// 回访时间
+        /// </summary>
+        public DateTime? VisitTimeStart { get; set; }
+
+        public DateTime? VisitTimeEnd { get; set; }
+
+        /// <summary>
+        /// 评判状态
+        /// </summary>
+        public EJudgeState? JudgeState { get; set; }
+
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+
+        /// <summary>
+        /// 是否待扭转
+        /// </summary>
+        public bool IsIng { get; set; }
+    }
+
+    public class JudgeVisitReq
+    {
+        public List<string> Ids { get; set; }
+
+        /// <summary>
+        /// 是否同意
+        /// </summary>
+        public bool IsAgree { get; set; }
+
+        /// <summary>
+        /// 是否
+        /// </summary>
+        public string? JudgeContent { get; set; }
+    }
+
+    public class JudgeVisitRsp
+    {
+        public int ErrorCount { get; set; }
+
+        public int SuccessCount { get; set; }
+    }
+
     public record VisitDetailListDto : PagedKeywordRequest
     {
         public EVisitStateQuery VisitState { get; set; }
@@ -69,6 +168,15 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool IsAgain { get; set; }
 
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+
         public List<VisitDetailDto> VisitDetails { get; set; }
     }
 
@@ -362,6 +470,26 @@ namespace Hotline.Share.Dtos.Order
         /// 智能回访录音地址
         /// </summary>
         public string? RecordUrl { get; set; }
+
+        /// <summary>
+        /// 部门扭转
+        /// </summary>
+        public bool? OrgJudge { get; set; }
+        /// <summary>
+        /// 坐席扭转
+        /// </summary>
+        public bool? SeatJudge { get; set; }
+        /// <summary>
+        /// 评判状态
+        /// </summary>
+        public EJudgeState? JudgeState { get; set; }
+
+        public string? JudgeStateText => JudgeState?.GetDescription() ?? string.Empty;
+        
+        /// <summary>
+        /// 评判意见
+        /// </summary>
+        public string? JudgeContent { get; set; }
     }
 
     public class OrderVisitDetailDto

+ 19 - 0
src/Hotline.Share/Enums/Order/EVisitState.cs

@@ -39,4 +39,23 @@ namespace Hotline.Share.Enums.Order
         [Description("失效")]
         None = 50,
     }
+
+    public enum EJudgeState
+    {
+        /// <summary>
+        /// 评判中
+        /// </summary>
+        [Description("评判中")]
+        Judging = 0,
+        /// <summary>
+        /// 已同意
+        /// </summary>
+        [Description("已同意")]
+        Agreed = 1,
+        /// <summary>
+        /// 不同意
+        /// </summary>
+        [Description("不同意")]
+        UnAgreed =2,
+    }
 }

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

@@ -214,6 +214,11 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         Task<IReadOnlyList<string>> GetUnhandleStepIdsFromSendPoolAsync(string sendPoolId, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 查询归属某用户的所有流程节点
+        /// </summary>
+        Task<List<WorkflowStep>> GetStepsBelongsToAsync(string userId, CancellationToken cancellationToken);
+
         /// <summary>
         /// 批量改派工单至指定用户
         /// </summary>
@@ -221,6 +226,13 @@ namespace Hotline.FlowEngine.Workflows
             IReadOnlyList<(string userId, string username, string orgId, string orgName, IReadOnlyList<string> stepIds)> handlers,
             CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 批量修改工单办理对象
+        /// </summary>
+        Task ChangeHandlerBatchAsync(
+            IReadOnlyList<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)> handlers,
+            CancellationToken cancellationToken);
+
         /// <summary>
         /// 查询工单办理中的一级部门
         /// </summary>

+ 32 - 0
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -647,6 +647,17 @@ namespace Hotline.FlowEngine.Workflows
                 .ToListAsync(cancellationToken);
         }
 
+        /// <summary>
+        /// 查询归属某用户的所有流程节点
+        /// </summary>
+        public async Task<List<WorkflowStep>> GetStepsBelongsToAsync(string userId, CancellationToken cancellationToken)
+        {
+            return await _workflowStepRepository.Queryable()
+                .Where(d => d.HandlerId == userId)
+                .OrderBy(d=>d.CreationTime)
+                .ToListAsync(cancellationToken);
+        }
+
         /// <summary>
         /// 批量改变办理对象
         /// </summary>
@@ -705,6 +716,27 @@ namespace Hotline.FlowEngine.Workflows
             return steps.Select(d => d.WorkflowId).ToList();
         }
 
+        /// <summary>
+        /// 批量修改工单办理对象
+        /// </summary>
+        public async Task ChangeHandlerBatchAsync(
+            IReadOnlyList<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)> handlers,
+            CancellationToken cancellationToken)
+        {
+            foreach (var handler in handlers)
+            {
+                foreach (var step in handler.steps)
+                {
+                    step.FlowAssignType = EFlowAssignType.User;
+                    step.Assign(handler.userId, handler.username, 
+                        handler.orgId, handler.orgName);
+                }
+            }
+
+            await _workflowStepRepository.UpdateRangeAsync(handlers.SelectMany(d => d.steps).ToList(),
+                cancellationToken);
+        }
+
         /// <summary>
         /// 查询工单办理中的一级部门
         /// </summary>

+ 3 - 2
src/Hotline/Orders/IOrderDomainService.cs

@@ -1,4 +1,5 @@
-using Hotline.Share.Dtos;
+using Hotline.Schedulings;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 
@@ -68,7 +69,7 @@ namespace Hotline.Orders
         /// </summary>
         /// <param name="userId"></param>
         /// <returns></returns>
-        Task LogAverageOrder(string userId, CancellationToken cancellationToken);
+        Task LogAverageOrder(string userId, Scheduling scheduling, CancellationToken cancellationToken);
 
         /// <summary>
         /// 触发平均派单

+ 38 - 76
src/Hotline/Orders/OrderDomainService.cs

@@ -17,6 +17,7 @@ using Hotline.Users;
 using Hotline.Share.Dtos;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos.FlowEngine;
+using Microsoft.AspNetCore.Http;
 
 namespace Hotline.Orders;
 
@@ -190,7 +191,6 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
             .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && x.AtWork == true)
             .OrderBy(x => x.SendOrderNum).FirstAsync(cancellationToken);
         if (scheduling is null)
-            //return new List<Kv> { new(OrderDefaults.SourceChannel.SendPoolId, "待派单池") };
             return new FlowStepHandler
             {
                 Key = OrderDefaults.SourceChannel.SendPoolId,
@@ -198,13 +198,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                 UserId = OrderDefaults.SourceChannel.SendPoolId,
                 Username = "待派单池",
             };
-
-        //var user = await _userRepository.GetAsync(x => x.Id == scheduling.SchedulingUser.UserId, cancellationToken);
-        //if (user is null)
-        //    throw new UserFriendlyException("无效用户编号");
         scheduling.SendOrderNum++;
         await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
-        //return new List<Kv> { new(user.Id, user.Name) };
         var user = scheduling.SchedulingUser;
         return new FlowStepHandler
         {
@@ -222,45 +217,36 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     /// </summary>
     /// <param name="userId"></param>
     /// <returns></returns>
-    public async Task LogAverageOrder(string userId, CancellationToken cancellationToken)
+    public async Task LogAverageOrder(string userId, Scheduling scheduling, CancellationToken cancellationToken)
     {
         //1.获取默认派单员所属的工单
         //2.获取今天上班的人员
         //3.给当前这个用户平均派单
-        var steps = await _workflowDomainService.GetUnhandleStepIdsFromSendPoolAsync(OrderDefaults.SourceChannel.SendPoolId, cancellationToken);
-        var stepsList = steps.ToList();
+
+        var steps = await _workflowDomainService.GetStepsBelongsToAsync(OrderDefaults.SourceChannel.SendPoolId,
+            cancellationToken);
 
         var user = await _userRepository.Queryable()
             .Includes(d => d.Organization)
             .FirstAsync(d => d.Id == userId, cancellationToken);
-        DateTime time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
+        var time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
         var schedulings = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
             .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay).CountAsync(cancellationToken);
-
         if (schedulings > 0)
         {
-            List<string> stepIds = new List<string>();
-            var sendNum = stepsList.Count() / schedulings;
-            for (int i = 0; i < sendNum; i++)
-            {
-                stepIds.Add(stepsList[0]);
-                stepsList.Remove(stepsList[0]);
-            }
-            List<(string, string, string, string, IReadOnlyList<string> stepIds)> handlers = new();
-            ; handlers.Add(new ValueTuple<string, string, string, string, IReadOnlyList<string>>(user.Id, user.Name, user.OrgId, user.Organization.Name, stepIds));
-            var workflowIds = await _workflowDomainService.ChangeHandlerRangeAsync(OrderDefaults.SourceChannel.SendPoolId, handlers, cancellationToken);
-            var orders = await _orderRepository.Queryable().Includes(d => d.Workflow).Where(d => workflowIds.Contains(d.WorkflowId))
-                .ToListAsync(cancellationToken);
-            foreach (var order in orders)
+            var sendNum = steps.Count / schedulings;
+            if (sendNum <= 0) return;
+            var sendSteps = steps.Take(sendNum).ToList();
+            await _workflowDomainService.ChangeHandlerBatchAsync(new List<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)>
             {
-                _mapper.Map(order.Workflow, order);
-            }
-            var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
-                .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && x.SchedulingUser.UserId == userId).FirstAsync(cancellationToken);
+                new(user.Id, user.Name, user.OrgId, user.Organization.Name, sendSteps)
+            }, cancellationToken);
             scheduling.SendOrderNum += sendNum;
-            await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
-            await _orderRepository.UpdateRangeAsync(orders, cancellationToken);
+            await _schedulingRepository.Updateable()
+                .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum, AtWork = scheduling.AtWork } )
+                .Where(s=> s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
         }
+
     }
 
     /// <summary>
@@ -279,48 +265,30 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 
         if (schedulings.Any())
         {
-            var steps = await _workflowDomainService.GetUnhandleStepIdsFromSendPoolAsync(OrderDefaults.SourceChannel.SendPoolId, cancellationToken);
-            var stepsList = steps.ToList();
-
-            var sendNum = steps.Count() / schedulings.Count();
-            List<(string userId, string username, string orgId, string orgName, IReadOnlyList<string> stepIds)> handlers = new();
-            if (sendNum > 0)
-            {
-
-                foreach (var scheduling in schedulings)
-                {
-                    List<string> stepIds = new List<string>();
-                    for (int i = 0; i < sendNum; i++)
-                    {
-                        stepIds.Add(stepsList[0]);
-                        stepsList.Remove(stepsList[0]);
-                    }
-                    handlers.Add(new ValueTuple<string, string, string, string, IReadOnlyList<string>>(scheduling.SchedulingUser.UserId, scheduling.SchedulingUser.UserName, scheduling.SchedulingUser.OrgId, scheduling.SchedulingUser.OrgIdName, stepIds));
-
-                }
-            }
-            sendNum = steps.Count() % schedulings.Count();
-            if (sendNum > 0)
+            var steps = await _workflowDomainService.GetStepsBelongsToAsync(OrderDefaults.SourceChannel.SendPoolId,
+                cancellationToken);
+            if (steps.Any())
             {
-                List<string> stepIds = new List<string>();
-                for (int i = 0; i < sendNum; i++)
+                List<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)> handlers = new();
+                var avg = steps.Count / schedulings.Count;
+                var remaining = steps.Count % schedulings.Count;
+                for (var i = 0; i < schedulings.Count; i++)
                 {
-                    stepIds.Add(stepsList[0]);
-                    stepsList.Remove(stepsList[0]);
-                }
-                handlers.Add(new ValueTuple<string, string, string, string, IReadOnlyList<string>>(schedulings[0].SchedulingUser.UserId, schedulings[0].SchedulingUser.UserName, schedulings[0].SchedulingUser.OrgId, schedulings[0].SchedulingUser.OrgIdName, stepIds));
-            }
-            if (handlers.Any())
-            {
-                var workflowIds = await _workflowDomainService.ChangeHandlerRangeAsync(OrderDefaults.SourceChannel.SendPoolId, handlers, cancellationToken);
-                var orders = await _orderRepository.Queryable().Includes(d => d.Workflow).Where(d => workflowIds.Contains(d.WorkflowId))
-                    .ToListAsync(cancellationToken);
-                foreach (var order in orders)
-                {
-                    _mapper.Map(order.Workflow, order);
-                }
-
-                await _orderRepository.UpdateRangeAsync(orders, cancellationToken);
+                    var scheduling = schedulings[i];
+                    var size = avg + (i < remaining ? 1 : 0);
+                    handlers.Add(new(
+                        scheduling.SchedulingUser.UserId,
+                        scheduling.SchedulingUser.UserName,
+                        scheduling.SchedulingUser.OrgId,
+                        scheduling.SchedulingUser.OrgIdName,
+                        steps.Take(size).ToList()));
+                    scheduling.SendOrderNum += size;
+					await _schedulingRepository.Updateable()
+	                    .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum })
+	                    .Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
+				}
+                if (handlers.Any())
+                    await _workflowDomainService.ChangeHandlerBatchAsync(handlers, cancellationToken);
             }
         }
     }
@@ -403,12 +371,6 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
             valid.Result = "标题或受理内容出现限制词,请检查!";
         return valid;
     }
-    #endregion
-
-    #region SchedulingSendOrder
-
-
-
     #endregion
 
     #region private

+ 31 - 0
src/Hotline/Orders/OrderVisit.cs

@@ -125,6 +125,37 @@ public class OrderVisit : CreationEntity
     /// </summary>
     public string? RecordUrl { get; set; }
 
+    /// <summary>
+    /// 部门扭转
+    /// </summary>
+    public bool? OrgJudge { get; set; }
+    /// <summary>
+    /// 坐席扭转
+    /// </summary>
+    public bool? SeatJudge { get; set; }
+    /// <summary>
+    /// 评判状态
+    /// </summary>
+    public EJudgeState? JudgeState { get; set;}
+    /// <summary>
+    /// 评判意见
+    /// </summary>
+    public string? JudgeContent { get; set;}
+
+    /// <summary>
+    /// 评判人Id
+    /// </summary>
+    public string? JudgeUserId { get; set; }
+
+    /// <summary>
+    /// 评判人名称
+    /// </summary>
+    public string? JudgeUserName { get; set; }
+
+    /// <summary>
+    /// 评判时间
+    /// </summary>
+    public DateTime? JudgeTime { get; set; }
 
     public void AiVisitTime()
     {

+ 1 - 0
src/Hotline/Push/MessageCodeDomainService.cs

@@ -2,6 +2,7 @@
 using Hotline.Caching.Interfaces;
 using Hotline.Identity.Accounts;
 using Hotline.Push.Notifies;
+using Hotline.Settings;
 using Hotline.Share.Dtos.Push;
 using Hotline.Share.Enums.Push;
 using Hotline.Users;

+ 1 - 0
src/Hotline/Quality/QualityDomainService.cs

@@ -2,6 +2,7 @@
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
 using Hotline.Orders;
+using Hotline.Settings;
 using Hotline.Share.Dtos.Quality;
 using Hotline.Share.Enums.Quality;
 using MapsterMapper;

+ 19 - 1
src/Hotline/Realtimes/IRealtimeService.cs

@@ -63,7 +63,25 @@ namespace Hotline.Realtimes
 
         #region 司法大屏
 
-        Task EnforcementOrderHandlingDetailAsync(object obj, CancellationToken cancellationToken); 
+        Task EnforcementOrderHandlingDetailAsync(object obj, CancellationToken cancellationToken);
+        #endregion
+
+        #region 话务排队信息
+        /// <summary>
+        /// 今日排队
+        /// </summary>
+        /// <param name="count"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task TodayWaitNumAsync(int count, CancellationToken cancellationToken);
+        /// <summary>
+        /// 当前等待
+        /// </summary>
+        /// <param name="count"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task CurrentWaitNumAsync(int count, CancellationToken cancellationToken);
+
         #endregion
     }
 }

+ 15 - 7
src/XF.Domain/Constants/SettingConstants.cs → src/Hotline/Settings/SettingConstants.cs

@@ -1,10 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace XF.Domain.Constants
+namespace Hotline.Settings
 {
     public class SettingConstants
     {
@@ -329,5 +323,19 @@ namespace XF.Domain.Constants
         /// 录音文件前缀地址
         /// </summary>
 		public const string ViteRecordPrefix = "ViteRecordPrefix";
+
+        /// <summary>
+        /// 派单员角色
+        /// </summary>
+		public const string RolePaiDan = "RolePaiDan";
+
+        /// <summary>
+        /// 坐席角色
+        /// </summary>
+		public const string RoleZuoXi = "RoleZuoXi";
+        /// <summary>
+        /// 呼入分机组号
+        /// </summary>
+        public const string CallInQueueId = "CallInQueueId";
 	}
 }

+ 7 - 0
src/Tr.Sdk/Tels/ITrClient.Tel.cs

@@ -32,5 +32,12 @@ namespace Tr.Sdk
         Task<List<QueryBlacklistResponse>> QueryBlacklistAsync(QueryBlacklistRequest request, CancellationToken cancellationToken) =>
             ExecuteAsync<QueryBlacklistRequest,List<QueryBlacklistResponse>>(request, cancellationToken);
         #endregion
+
+        #region 队列信息
+
+        Task<QueryQueueWaitNumResponse> QueryQueueWaitNumAsync(QueryQueueWaitNumRequest request, CancellationToken cancellationToken) =>
+            ExecuteAsync<QueryQueueWaitNumRequest, QueryQueueWaitNumResponse>(request, cancellationToken);
+
+        #endregion
     }
 }

+ 28 - 0
src/Tr.Sdk/Tels/QueryQueueWaitNumRequest.cs

@@ -0,0 +1,28 @@
+using RestSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+
+namespace Tr.Sdk.Tels
+{
+    public class QueryQueueWaitNumRequest : TrRequest
+    {
+        public override Method HttpMethod() => Method.Get;
+
+        public override string Path() => $"/api/ola/queues/{QueueId}/get-callers";
+
+        [RequestProperty(Name = "args")]
+        public string QueueId { get; set; }
+    }
+
+
+    public class QueryQueueWaitNumResponse
+    {
+        [JsonPropertyName("count")]
+        public string Count { get; set; }
+    }
+    
+}