Quellcode durchsuchen

Merge branch 'dev' of http://git.12345lm.cn/Fengwo/hotline into dev

tangjiang vor 9 Monaten
Ursprung
Commit
d622a84e33

+ 56 - 22
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -2992,7 +2992,7 @@ namespace Hotline.Api.Controllers.Bi
         {
             var (areaList ,returnList) = await _orderApplication.HotspotAndAreaStatistics(dto);
 
-            return new { AreaList = areaList, Data = returnList };
+            return new { AreaList = areaList, Data =  returnList };
         }
 
         /// <summary>
@@ -3000,13 +3000,13 @@ namespace Hotline.Api.Controllers.Bi
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        [HttpGet("hotspot-area-statistics-export")]
+        [HttpPost("hotspot-area-statistics-export")]
         public async Task<FileStreamResult> HotspotAndAreaStatisticsExport([FromBody]HotspotAndAreaStatisticsReq dto)
         {
-            var (areaList, returnList) = await _orderApplication.HotspotAndAreaStatistics(dto);
-            //var table = InitHotspotTable(returnList, dto.AddColumnName, dto.HotspotLevel);
-
-            return null;
+            var  returnList = await _orderApplication.HotspotAndAreaStatisticsExport(dto);
+            var table = InitHotspotTable(returnList, dto.AddColumnName, dto.HotspotLevel);
+            var stream = ExcelHelper.CreateStream(table);
+            return ExcelStreamResult(stream, "热点区域统计");
         }
 
         private DataTable InitHotspotTable(DataTable dt,List<string> AddColumnName,int HotspotLevel)
@@ -3034,8 +3034,8 @@ namespace Hotline.Api.Controllers.Bi
 
             //增加合计
             DataRow totalRow = dt.NewRow();
-            if (dt.Columns[0].ColumnName == "日期") totalRow["日期"] = "合计";
-            else totalRow["时间段"] = "合计";
+            if (dt.Columns[0].ColumnName == "HotspotName") totalRow["HotspotName"] = "合计";
+            else totalRow["一级热点"] = "合计";
             for (int i = 1; i < dt.Columns.Count; i++)
             {
                 int sumcount = 0;
@@ -3053,23 +3053,23 @@ namespace Hotline.Api.Controllers.Bi
             //添加表头
             foreach (var item in AddColumnName)
             {
-                if (item.Equals("一级热点"))
+                if (item.Equals("HotspotName") || item.Equals("一级热点"))
                 {
-                    dt2.Columns.Add(item);
+                    dt2.Columns.Add("一级热点");
                     if (HotspotLevel==2)
                     {
-                        dt.Columns.Add("二级热点");
+                        dt2.Columns.Add("二级热点");
                     }
                     else if(HotspotLevel==3)
                     {
-                        dt.Columns.Add("二级热点");
-                        dt.Columns.Add("三级热点");
+                        dt2.Columns.Add("二级热点");
+                        dt2.Columns.Add("三级热点");
                     }
                     else if(HotspotLevel==4)
                     {
-                        dt.Columns.Add("二级热点");
-                        dt.Columns.Add("三级热点");
-                        dt.Columns.Add("四级热点");
+                        dt2.Columns.Add("二级热点");
+                        dt2.Columns.Add("三级热点");
+                        dt2.Columns.Add("四级热点");
                     }
                 }
                 else
@@ -3085,7 +3085,7 @@ namespace Hotline.Api.Controllers.Bi
                 DataRow targetRow = dt2.NewRow();                
                 foreach (var item in AddColumnName)
                 {
-                    if (item.Equals("一级热点"))
+                    if (item.Equals("HotspotName"))
                     {
                         targetRow["一级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[0];
                         if (HotspotLevel==2)
@@ -3094,14 +3094,48 @@ namespace Hotline.Api.Controllers.Bi
                         }
                         else if(HotspotLevel==3)
                         {
-                            targetRow["二级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[1];
-                            targetRow["三级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[2];
+                            try
+                            {
+                                targetRow["二级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[1];
+                            }
+                            catch{
+                                targetRow["二级热点"] = "";
+                            }
+                            try
+                            {
+                                targetRow["三级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[2];
+                            }
+                            catch{
+                                targetRow["三级热点"] = "";
+                            }
                         }
                         else if(HotspotLevel==4)
                         {
-                            targetRow["二级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[1];
-                            targetRow["三级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[2];
-                            targetRow["四级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[3];
+                            try
+                            {
+                                targetRow["二级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[1];
+                            }
+                            catch
+                            {
+                                targetRow["二级热点"] = "";
+                            }
+                            try
+                            {
+                                targetRow["三级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[2];
+                            }
+                            catch
+                            {
+                                targetRow["三级热点"] = "";
+                            }
+                            try
+                            {
+                                targetRow["四级热点"] = sourceRow["一级热点"].ToString()?.Split('-')[3];
+                            }
+                            catch 
+                            {
+                                targetRow["四级热点"] = "";
+                            }
+                            
                         }
                     }
                     else

+ 5 - 15
src/Hotline.Api/Controllers/CallController.cs

@@ -94,22 +94,12 @@ namespace Hotline.Api.Controllers
         }
 
         /// <summary>
-        /// 关联通话记录与工单或回访
+        /// 查询坐席操作记录(固定数据量)
         /// </summary>
+        /// <param name="dto"></param>
         /// <returns></returns>
-        [HttpPost("relate-call-to-order")]
-        public Task RelateCallToOrder([FromBody] LinkCallRecordDto dto) =>
-            _callApplication.RelateCallToOrderAsync(dto, HttpContext.RequestAborted);
-
-        ///// <summary>
-        ///// 查询坐席操作记录(固定数据量)
-        ///// </summary>
-        ///// <param name="dto"></param>
-        ///// <returns></returns>
-        //[HttpGet("tel-operations-fixed")]
-        //public Task<IReadOnlyList<TelOperation>> QueryTelOperationsFixed([FromQuery] QueryTelOperationsFixedDto dto)
-        //{
-
-        //}
+        [HttpGet("tel-operations-fixed")]
+        public Task<IReadOnlyList<TelOperation>> QueryTelOperationsFixed([FromQuery] QueryTelOperationsFixedDto dto) => 
+            _callApplication.QueryTelOperationsAsync(dto, HttpContext.RequestAborted);
     }
 }

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

@@ -2321,10 +2321,8 @@ public class OrderController : BaseController
     [HttpGet("fixed")]
     public async Task<IReadOnlyList<OrderDto>> QueryFixed([FromQuery] QueryOrderFixedDto dto)
     {
-        var count = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)
-            .SettingValue[0]);
         var query = _orderApplication.QueryOrders(dto);
-        var orders = await query.ToFixedListAsync(dto.QueryIndex, count, HttpContext.RequestAborted);
+        var orders = await query.ToFixedListAsync(dto.QueryIndex, cancellationToken: HttpContext.RequestAborted);
         return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
     }
 

+ 1 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -113,7 +113,7 @@ internal static class StartupExtensions
                 break;
             case "TianRun":
                 services
-                    .AddScoped<ICallApplication, TianRunCallApplication>()
+                    //.AddScoped<ICallApplication, TianRunCallApplication>()
                     .AddScoped<ITrApplication, TrApplication>()
                     .AddHostedService<CurrentWaitNumService>()
                     .AddHostedService<TelsStatusRefreshService>()

+ 2 - 2
src/Hotline.Api/StartupHelper.cs

@@ -263,8 +263,8 @@ namespace Hotline.Api
                 switch (callCenterConfiguration.CallCenterType)
                 {
                     case "XingTang":
-                        var getCallsJobKey = new JobKey(nameof(GetXingTangCallsJob));
-                        d.AddJob<GetXingTangCallsJob>(getCallsJobKey);
+                        var getCallsJobKey = new JobKey(nameof(XingTangCallsSyncJob));
+                        d.AddJob<XingTangCallsSyncJob>(getCallsJobKey);
                         d.AddTrigger(d => d
                             .WithIdentity("get-callsxt-trigger")
                             .ForJob(getCallsJobKey)

+ 2 - 1
src/Hotline.Api/config/appsettings.shared.Development.json

@@ -54,7 +54,8 @@
       //  "Name": "File",
       //  "Args": {
       //    "path": "logs/log-.txt",
-      //    "rollingInterval": "Day"
+      //    "rollingInterval": "Day",
+      //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}",
       //  }
       //},
       //{

+ 5 - 3
src/Hotline.Application/CallCenter/ICallApplication.cs

@@ -5,6 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using Hotline.CallCenter.BlackLists;
 using Hotline.CallCenter.Calls;
+using Hotline.CallCenter.Tels;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.TrCallCenter;
 using XingTang.Sdk;
@@ -53,10 +54,11 @@ namespace Hotline.Application.CallCenter
         /// 定量查询通话记录
         /// </summary>
         Task<IReadOnlyList<CallNativeDto>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken);
-
+        
         /// <summary>
-        /// 关联通话记录与工单或回访
+        /// 查询分机操作记录(定量)
         /// </summary>
-        Task RelateCallToOrderAsync(LinkCallRecordDto dto, CancellationToken cancellationToken);
+        Task<IReadOnlyList<TelOperation>> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto,
+            CancellationToken cancellationToken);
     }
 }

+ 113 - 104
src/Hotline.Application/CallCenter/TianRunCallApplication.cs

@@ -1,118 +1,127 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Hotline.Application.CallCenter.Calls;
-using Hotline.Application.Tels;
-using Hotline.Caching.Interfaces;
-using Hotline.CallCenter.BlackLists;
-using Hotline.CallCenter.Calls;
-using Hotline.Settings;
-using Hotline.Share.Dtos.CallCenter;
-using Hotline.Share.Dtos.TrCallCenter;
-using Hotline.Share.Enums.CallCenter;
-using Microsoft.AspNetCore.Http;
-using XF.Domain.Authentications;
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Text;
+//using System.Threading.Tasks;
+//using Hotline.Application.CallCenter.Calls;
+//using Hotline.Application.Tels;
+//using Hotline.Caching.Interfaces;
+//using Hotline.CallCenter.BlackLists;
+//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;
+//using Microsoft.AspNetCore.Http;
+//using XF.Domain.Authentications;
 
-namespace Hotline.Application.CallCenter
-{
-    public class TianRunCallApplication : ICallApplication
-    {
-        private readonly ISessionContext _sessionContext;
-        private readonly ITrApplication _trApplication;
-        private readonly ITelApplication _telApplication;
-        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+//namespace Hotline.Application.CallCenter
+//{
+//    public class TianRunCallApplication : ICallApplication
+//    {
+//        private readonly ISessionContext _sessionContext;
+//        private readonly ITrApplication _trApplication;
+//        private readonly ITelApplication _telApplication;
+//        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
-        public TianRunCallApplication(
-            ISessionContext sessionContext,
-            ITrApplication trApplication,
-            ITelApplication telApplication,
-            ISystemSettingCacheManager systemSettingCacheManager
-            )
-        {
-            _sessionContext = sessionContext;
-            _trApplication = trApplication;
-            _telApplication = telApplication;
-            _systemSettingCacheManager = systemSettingCacheManager;
-        }
+//        public TianRunCallApplication(
+//            ISessionContext sessionContext,
+//            ITrApplication trApplication,
+//            ITelApplication telApplication,
+//            ISystemSettingCacheManager systemSettingCacheManager
+//            )
+//        {
+//            _sessionContext = sessionContext;
+//            _trApplication = trApplication;
+//            _telApplication = telApplication;
+//            _systemSettingCacheManager = systemSettingCacheManager;
+//        }
 
-        /// <summary>
-        /// 查询分机
-        /// </summary>
-        public Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        /// <summary>
+//        /// 查询分机
+//        /// </summary>
+//        public Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        /// <summary>
-        /// 查询分机组
-        /// </summary>
-        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        /// <summary>
+//        /// 查询分机组
+//        /// </summary>
+//        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        /// <summary>
-        /// 签入
-        /// </summary>
-        public Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken) =>
-            _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);
+//        /// <summary>
+//        /// 签入
+//        /// </summary>
+//        public Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken) =>
+//            _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);
 
-        /// <summary>
-        /// 签出
-        /// </summary>
-        public Task SingOutAsync(CancellationToken cancellationToken) =>
-            _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);
+//        /// <summary>
+//        /// 签出
+//        /// </summary>
+//        public Task SingOutAsync(CancellationToken cancellationToken) =>
+//            _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);
 
-        public Task SingOutAsync(string telNo, CancellationToken cancellationToken) =>
-            _telApplication.SignOutByTelNoAsync(telNo, cancellationToken);
+//        public Task SingOutAsync(string telNo, CancellationToken cancellationToken) =>
+//            _telApplication.SignOutByTelNoAsync(telNo, cancellationToken);
 
-        /// <summary>
-        /// 查询当前用户的分机状态
-        /// </summary>
-        /// <param name="cancellationToken"></param>
-        /// <returns></returns>
-        public Task<TrOnDutyResponseDto> GetTelStateAsync(CancellationToken cancellationToken) =>
-            _trApplication.TelState(_sessionContext.RequiredUserId, cancellationToken);
+//        /// <summary>
+//        /// 查询当前用户的分机状态
+//        /// </summary>
+//        /// <param name="cancellationToken"></param>
+//        /// <returns></returns>
+//        public Task<TrOnDutyResponseDto> GetTelStateAsync(CancellationToken cancellationToken) =>
+//            _trApplication.TelState(_sessionContext.RequiredUserId, cancellationToken);
 
-        /// <summary>
-        /// 定量查询通话记录
-        /// </summary>
-        Task<IReadOnlyList<CallNativeDto>> ICallApplication.QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        /// <summary>
+//        /// 定量查询通话记录
+//        /// </summary>
+//        Task<IReadOnlyList<CallNativeDto>> ICallApplication.QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        /// <summary>
-        /// 关联通话记录与工单或回访
-        /// </summary>
-        public Task RelateCallToOrderAsync(LinkCallRecordDto dto, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
+//        /// <summary>
+//        /// 关联通话记录与工单或回访
+//        /// </summary>
+//        public Task RelateCallToOrderAsync(LinkCallRecordDto dto, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
 
-        /// <summary>
-        /// 定量查询通话记录
-        /// </summary>
-        public async Task<IReadOnlyList<CallNative>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}
+//        /// <summary>
+//        /// 查询分机操作记录(定量)
+//        /// </summary>
+//        public async Task<IReadOnlyList<TelOperation>> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
+
+//        /// <summary>
+//        /// 定量查询通话记录
+//        /// </summary>
+//        public async Task<IReadOnlyList<CallNative>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
+//        {
+//            throw new NotImplementedException();
+//        }
+//    }
+//}

+ 16 - 51
src/Hotline.Application/CallCenter/XingTangCallApplication.cs

@@ -35,12 +35,9 @@ namespace Hotline.Application.CallCenter
         private readonly IWorkRepository _workRepository;
         private readonly ITelRestRepository _telRestRepository;
         private readonly IRepository<CallNative> _callNativeRepository;
-        private readonly IOrderRepository _orderRepository;
-        private readonly IRepository<OrderVisit> _orderVisitRepository;
+        private readonly IRepository<TelOperation> _teloperationRepository;
         private readonly ITypedCache<Work> _cacheWork;
         private readonly IUserCacheManager _userCacheManager;
-        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
-        private readonly ICapPublisher _capPublisher;
         private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
 
@@ -50,12 +47,9 @@ namespace Hotline.Application.CallCenter
             IWorkRepository workRepository,
             ITelRestRepository telRestRepository,
             IRepository<CallNative> callNativeRepository,
-            IOrderRepository orderRepository,
-            IRepository<OrderVisit> orderVisitRepository,
+            IRepository<TelOperation> teloperationRepository,
             ITypedCache<Work> cacheWork,
             IUserCacheManager userCacheManager,
-            ISystemSettingCacheManager systemSettingCacheManager,
-            ICapPublisher capPublisher,
             ISessionContext sessionContext,
             IMapper mapper)
         {
@@ -64,12 +58,9 @@ namespace Hotline.Application.CallCenter
             _workRepository = workRepository;
             _telRestRepository = telRestRepository;
             _callNativeRepository = callNativeRepository;
-            _orderRepository = orderRepository;
-            _orderVisitRepository = orderVisitRepository;
+            _teloperationRepository = teloperationRepository;
             _cacheWork = cacheWork;
             _userCacheManager = userCacheManager;
-            _systemSettingCacheManager = systemSettingCacheManager;
-            _capPublisher = capPublisher;
             _sessionContext = sessionContext;
             _mapper = mapper;
         }
@@ -206,14 +197,13 @@ namespace Hotline.Application.CallCenter
         /// </summary>
         public async Task<IReadOnlyList<CallNativeDto>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
         {
-            var count = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount).SettingValue[0]);
-            return await _callNativeRepository.Queryable()
+            return await _callNativeRepository.Queryable(includeDeleted: true)
                 .LeftJoin<Order>((d, o) => d.CallNo == o.CallId)
                 .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.FromNo == dto.ToNo)
-                .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.FromNo == dto.UserName)
-                .WhereIF(!string.IsNullOrEmpty(dto.TelNo), d => d.FromNo == dto.TelNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.ToNo), d => d.ToNo == dto.ToNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName)
+                .WhereIF(!string.IsNullOrEmpty(dto.TelNo), d => d.TelNo == dto.TelNo)
                 .WhereIF(dto.EndBy != null, d => d.EndBy == dto.EndBy)
                 .WhereIF(dto.CallStartTimeBT != null, d => d.BeginIvrTime >= dto.CallStartTimeBT)
                 .WhereIF(dto.CallStartTimeLT != null, d => d.BeginIvrTime <= dto.CallStartTimeLT)
@@ -225,45 +215,20 @@ namespace Hotline.Application.CallCenter
                     OrderNo = o.No,
                     Title = o.Title,
                 }, true)
-                .ToFixedListAsync(dto, count, cancellationToken);
+                .ToFixedListAsync(dto, cancellationToken);
         }
 
         /// <summary>
-        /// 关联通话记录与工单或回访
+        /// 查询分机操作记录(定量)
         /// </summary>
-        public async Task RelateCallToOrderAsync(LinkCallRecordDto dto, CancellationToken cancellationToken)
+        public async Task<IReadOnlyList<TelOperation>> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto, CancellationToken cancellationToken)
         {
-            var call = await _callNativeRepository.GetAsync(d => d.CallNo == dto.CallId, cancellationToken);
-            if (call is null) throw UserFriendlyException.SameMessage("无效通话记录编号");
-            if (dto.IsOrder)
-            {
-                //工单
-                var order = await _orderRepository.GetAsync(x => x.Id == dto.Id, cancellationToken);
-                if (order is null) throw UserFriendlyException.SameMessage("无效工单编号");
-                if (!string.IsNullOrEmpty(order.CallId))
-                    throw UserFriendlyException.SameMessage("通话记录已经关联工单");
-
-                order.CallId = dto.CallId;
-                order.FromPhone = call.FromNo;
-                order.TransferPhone = call.ToNo;
-                await _orderRepository.UpdateAsync(order, cancellationToken);
-
-                //推省上
-                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallConnectWithOrder,
-                    new PublishCallRecrodDto()
-                    {
-                        Order = _mapper.Map<OrderDto>(order),
-                        TrCallRecordDto = _mapper.Map<TrCallDto>(call)
-                    });
-            }
-            else
-            {
-                //回访
-                var visit = await _orderVisitRepository.GetAsync(x => x.Id == dto.Id, cancellationToken);
-                if (visit is null) throw UserFriendlyException.SameMessage("无效回访记录编号");
-                visit.CallId = dto.CallId;
-                await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
-            }
+            return await _teloperationRepository.Queryable()
+                .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName)
+                .WhereIF(!string.IsNullOrEmpty(dto.StaffNo), d => d.StaffNo == dto.StaffNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.GroupId), d => d.GroupId == dto.GroupId)
+                .WhereIF(dto.OperateState != null, d => d.OperateState == dto.OperateState)
+                .ToFixedListAsync(dto, cancellationToken);
         }
     }
 }

+ 7 - 12
src/Hotline.Application/Jobs/GetXingTangCallsJob.cs → src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -13,20 +13,20 @@ namespace Hotline.Application.Jobs
     /// <summary>
     /// 查询兴唐通话记录
     /// </summary>
-    public class GetXingTangCallsJob : IJob, IDisposable
+    public class XingTangCallsSyncJob : IJob, IDisposable
     {
         private readonly IRepository<CallNative> _callRepository;
         private readonly IRepository<User> _userRepository;
         private readonly IMapper _mapper;
-        private readonly ILogger<GetXingTangCallsJob> _logger;
+        private readonly ILogger<XingTangCallsSyncJob> _logger;
         private readonly ISqlSugarClient _db;
 
-        public GetXingTangCallsJob(
+        public XingTangCallsSyncJob(
             ISugarUnitOfWork<XingTangDbContext> uow,
             IRepository<CallNative> callRepository,
             IRepository<User> userRepository,
             IMapper mapper,
-            ILogger<GetXingTangCallsJob> logger)
+            ILogger<XingTangCallsSyncJob> logger)
         {
             _callRepository = callRepository;
             _userRepository = userRepository;
@@ -37,12 +37,12 @@ namespace Hotline.Application.Jobs
 
         public async Task Execute(IJobExecutionContext context)
         {
-            var xingtangCalls = await _db.Queryable<CallXingtang>()
+            var xingtangCalls = await _db.Queryable<XingtangCall>()
                 .Where(d => (d.IsSync == null || !d.IsSync) && (d.Tries == null || d.Tries <= 50))
                 .Take(10)
                 .ToListAsync(context.CancellationToken);
 
-            var occupyCalls = new List<CallXingtang>();
+            var occupyCalls = new List<XingtangCall>();
             foreach (var call in xingtangCalls)
             {
                 call.IsSync = true;
@@ -65,11 +65,6 @@ namespace Hotline.Application.Jobs
 
                 foreach (var call in calls)
                 {
-                    //if (trCall.CallDirection is ECallDirection.Out &&
-                    //    string.IsNullOrEmpty(trCall.RecordingAbsolutePath))
-                    //    continue;
-                    Console.WriteLine();
-
                     var user = users.FirstOrDefault(d => d.StaffNo == call.StaffNo);
                     if (user is not null)
                     {
@@ -98,7 +93,7 @@ namespace Hotline.Application.Jobs
         /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
         public void Dispose()
         {
-            _logger.LogInformation($"{nameof(GetXingTangCallsJob)} disposed");
+            _logger.LogInformation($"{nameof(XingTangCallsSyncJob)} disposed");
         }
     }
 }

+ 32 - 0
src/Hotline.Application/Jobs/XingTangTelOperationSyncJob.cs

@@ -0,0 +1,32 @@
+using Quartz;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Hotline.Application.Jobs
+{
+    public class XingTangTelOperationSyncJob : IJob, IDisposable
+    {
+        private readonly ILogger<XingTangTelOperationSyncJob> _logger;
+
+        public XingTangTelOperationSyncJob(
+            ILogger<XingTangTelOperationSyncJob> logger)
+        {
+            _logger = logger;
+        }
+
+        public async Task Execute(IJobExecutionContext context)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
+        public void Dispose()
+        {
+            _logger.LogInformation($"{nameof(XingTangTelOperationSyncJob)} disposed");
+        }
+    }
+}

+ 5 - 2
src/Hotline.Application/Mappers/CallMapperConfigs.cs

@@ -61,7 +61,7 @@ namespace Hotline.Application.Mappers
                 .Map(d => d.CallAccept, x => x.call_accept)
                 .Map(d => d.Type, x => x.type);
 
-            config.ForType<CallXingtang, CallNative>()
+            config.ForType<XingtangCall, CallNative>()
                 .Map(d => d.CallNo, s => s.CallGuid)
                 .Map(d => d.Direction, s => s.CallType)
                 .Map(d => d.FromNo, s => s.Caller)
@@ -83,7 +83,10 @@ namespace Hotline.Application.Mappers
                 .Map(d => d.AudioFile, s => s.AudioFile)
                 .AfterMapping((s, d) =>
                 {
-                    d.EndBy = EEndBy.From;
+                    //todo 等待兴唐补全Disposition字段
+                    d.EndBy = d.Direction == ECallDirection.In
+                        ? EEndBy.From
+                        : EEndBy.To;
                 });
 
             config.ForType<CallNative, TrCallDto>()

+ 7 - 0
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -154,5 +154,12 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         Task<(List<SystemArea> area, object items)> HotspotAndAreaStatistics(HotspotAndAreaStatisticsReq dto);
 
+
+        /// <summary>
+        /// 热点-区域统计导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<DataTable> HotspotAndAreaStatisticsExport(HotspotAndAreaStatisticsReq dto);
     }
 }

+ 106 - 54
src/Hotline.Application/Orders/OrderApplication.cs

@@ -920,6 +920,11 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(!string.IsNullOrEmpty(dto.LineNum), x => x.OrderVisit.Order.CallRecord.Gateway == dto.LineNum);
 	}
 
+    /// <summary>
+    /// 热点区域统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
     public async Task<(List<SystemArea> area,object items)> HotspotAndAreaStatistics(HotspotAndAreaStatisticsReq dto)
     {
         dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
@@ -937,71 +942,118 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Select(x => new
             {
                 HotspotId= x.HotspotId.Substring(0,int.Parse(endIndex)),
-                AreaCode = x.AreaCode,
+                AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
             }).MergeTable();
 
 
-       var hotListAndOrder = hotspotList.LeftJoin(orderList, (it, o) => it.HotspotId == o.HotspotId)
-            .GroupBy((it, o) => new
-            {
-                it.HotspotId,
-                it.HotspotName,
-                AreaCode = o.AreaCode.Substring(0,6),
-            })
-            .OrderBy((it, o) => it.HotspotId)
-            .Select((it, o) => new
-            {
-                HotspotId=it.HotspotId,
-                HotspotName=it.HotspotName,
-                AreaCode=o.AreaCode,
-                Count = SqlFunc.AggregateCount(it.HotspotId)
+        var hotListAndOrder = hotspotList.LeftJoin(orderList, (it, o) => it.HotspotId == o.HotspotId)
+             .GroupBy((it, o) => new
+             {
+                 it.HotspotId,
+                 it.HotspotName,
+                 AreaCode = o.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+             })
+             .OrderBy((it, o) => it.HotspotId)
+             .Select((it, o) => new
+             {
+                 HotspotId = it.HotspotId,
+                 HotspotName = it.HotspotName,
+                 AreaCode = o.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                 Count = SqlFunc.AggregateCount(it.HotspotId)
+             }).MergeTable();
+
+
+        var returnList = await hotListAndOrder.LeftJoin(areaList, (pp, dd) => pp.AreaCode == dd.Id)
+           .GroupBy((pp, dd) => new
+           {
+               HotspotId = pp.HotspotId,
+               HotspotName = pp.HotspotName,
+               AreaCode = pp.AreaCode,
+               AreaName = dd.AreaName,
+           })
+           .OrderBy((pp, dd) => pp.HotspotId)
+           .Select((pp, dd) => new
+           {
+               HotspotId = pp.HotspotId,
+               HotspotName = pp.HotspotName,
+               AreaCode = pp.AreaCode,
+               AreaName = dd.AreaName,
+               Count = SqlFunc.AggregateSum(pp.Count)
+           }).ToPivotListAsync(q=> q.AreaCode, q=> new { q.HotspotName,q.HotspotId},q=> q.Sum(x=>x.Count));
+        return (await areaList.ToListAsync(), returnList);
+    }
+
+    /// <summary>
+    /// 热点区域统计--导出
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<DataTable> HotspotAndAreaStatisticsExport(HotspotAndAreaStatisticsReq dto)
+    {
+        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
+        var areaList = _systemAreaRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == 6 && x.Id != "510000").OrderBy(x => x.Id).MergeTable();
+
+        var endIndex = (2 * dto.HotspotLevel).ToString();
+        var hotspotList = _hotspotRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == int.Parse(endIndex))
+            .Select(x => new {
+                HotspotId = x.Id,
+                HotspotName = x.HotSpotFullName,
             }).MergeTable();
 
 
-        hotListAndOrder.LeftJoin(areaList, (it, o) => it.AreaCode == o.Id)
-            .GroupBy((it, o) => new
+        var orderList = _orderRepository.Queryable().Where(x => x.CreationTime >= dto.StartTime && x.CreationTime < dto.EndTime)
+            .Select(x => new
             {
+                HotspotId = x.HotspotId.Substring(0, int.Parse(endIndex)),
+                AreaCode = x.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+            }).MergeTable();
 
-            });
 
-        //List<dynamic> returnList =  new List<dynamic>();
-        //var endIndex = (2 * dto.HotspotLevel).ToString();
-        //foreach (var item in areaList)
-        //{
-        //    List<dynamic> list= new List<dynamic>();
-        //    list = await _hotspotRepository.Queryable()
-        //        .LeftJoin<Order>((it, o) => it.Id == o.HotspotId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(endIndex)))
-        //        .Where((it, o) => o.CreationTime >= dto.StartTime && o.CreationTime < dto.EndTime && o.AreaCode.StartsWith(item.Id) && SqlFunc.Length(it.Id) >= int.Parse(endIndex))
-        //        .GroupBy((it, o) => new
-        //        {
-        //            HotspotId = o.HotspotId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(endIndex)),
-        //            it.HotSpotFullName,
-        //            it.OrderBy
-        //        })
-        //        .OrderBy((it, o) => new
-        //        {
-        //            it.OrderBy
-        //        }).Select((it, o) => new
-        //        {Z
-        //            HotspotId = o.HotspotId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(endIndex)),
-        //            Key = item.Id,
-        //            HotSpotNameOne = it.HotSpotFullName,
-        //            Count = SqlFunc.AggregateCount(it.HotSpotFullName)
-        //        }).ToPivotListAsync(x => x.Key, x => new { x.HotspotId, x.HotSpotNameOne }, x => x.Sum(x => x.Count));
-        //    returnList.AddRange(list);
-        //}
-        //return (areaList, returnList );
-        return (null,null);
+        var hotListAndOrder = hotspotList.LeftJoin(orderList, (it, o) => it.HotspotId == o.HotspotId)
+             .GroupBy((it, o) => new
+             {
+                 it.HotspotId,
+                 it.HotspotName,
+                 AreaCode = o.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+             })
+             .OrderBy((it, o) => it.HotspotId)
+             .Select((it, o) => new
+             {
+                 HotspotId = it.HotspotId,
+                 HotspotName = it.HotspotName,
+                 AreaCode = o.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                 Count = SqlFunc.AggregateCount(it.HotspotId)
+             }).MergeTable();
+
+
+        var returnList = await hotListAndOrder.LeftJoin(areaList, (pp, dd) => pp.AreaCode == dd.Id)
+           .GroupBy((pp, dd) => new
+           {
+               HotspotId = pp.HotspotId,
+               HotspotName = pp.HotspotName,
+               AreaCode = pp.AreaCode,
+               AreaName = dd.AreaName,
+           })
+           .OrderBy((pp, dd) => pp.HotspotId)
+           .Select((pp, dd) => new
+           {
+               HotspotId = pp.HotspotId,
+               HotspotName = pp.HotspotName,
+               AreaCode = pp.AreaCode,
+               AreaName = dd.AreaName,
+               Count = SqlFunc.AggregateSum(pp.Count)
+           }).ToPivotTableAsync(q => q.AreaName, q => new { q.HotspotName }, q => q.Sum(x => x.Count));
+        return  returnList;
     }
-	#region private
+    #region private
 
-	/// <summary>
-	/// 接受外部工单(除省平台)
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <param name="cancellationToken"></param>
-	/// <returns></returns>
-	private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
+    /// <summary>
+    /// 接受外部工单(除省平台)
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
         ISessionContext current, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(dto.ExternalId))

+ 6 - 4
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarRepositoryExtensions.cs

@@ -34,16 +34,18 @@ namespace Hotline.Repository.SqlSugar.Extensions
         /// 分批次查询固定数量
         /// </summary>
         /// <returns></returns>
-        public static Task<List<TEntity>> ToFixedListAsync<TEntity>(this ISugarQueryable<TEntity> query, QueryFixedDto dto, int count, CancellationToken cancellationToken)
+        public static Task<List<TEntity>> ToFixedListAsync<TEntity>(this ISugarQueryable<TEntity> query, QueryFixedDto dto, CancellationToken cancellationToken)
         where TEntity : class, new()
         {
-            return query.Skip(dto.QueryIndex * count).Take(count).ToListAsync(cancellationToken);
+            if (dto.QueryCount == 0) dto.QueryCount = 50;
+            return query.Skip(dto.QueryIndex * dto.QueryCount).Take(dto.QueryCount).ToListAsync(cancellationToken);
         }
 
-        public static Task<List<TEntity>> ToFixedListAsync<TEntity>(this ISugarQueryable<TEntity> query, int queryIndex, int count, CancellationToken cancellationToken)
+        public static Task<List<TEntity>> ToFixedListAsync<TEntity>(this ISugarQueryable<TEntity> query, int queryIndex, int? queryCount = null, CancellationToken cancellationToken = default)
             where TEntity : class, new()
         {
-            return query.Skip(queryIndex * count).Take(count).ToListAsync(cancellationToken);
+            if (queryCount is null or 0) queryCount = 50;
+            return query.Skip(queryIndex * queryCount.Value).Take(queryCount.Value).ToListAsync(cancellationToken);
         }
     }
 }

+ 31 - 0
src/Hotline.Share/Dtos/CallCenter/QueryTelOperationsFixedDto.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.CallCenter
+{
+    public class QueryTelOperationsFixedDto : QueryFixedDto
+    {
+        /// <summary>
+        /// 姓名
+        /// </summary>
+        public string? UserName { get; set; }
+
+        /// <summary>
+        /// 工号
+        /// </summary>
+        public string? StaffNo { get; set; }
+
+        /// <summary>
+        /// 工作组
+        /// </summary>
+        public string? GroupId { get; set; }
+
+        /// <summary>
+        /// 操作类型
+        /// </summary>
+        public int? OperateState { get; set; }
+    }
+}

+ 5 - 0
src/Hotline.Share/QueryFixedDto.cs

@@ -12,5 +12,10 @@ namespace Hotline.Share
         /// 查询批次
         /// </summary>
         public int QueryIndex { get; set; }
+
+        /// <summary>
+        /// 单次总数据量
+        /// </summary>
+        public int QueryCount { get; set; } = 50;
     }
 }

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

@@ -345,11 +345,6 @@ namespace Hotline.Settings
         /// </summary>
         public const string CanUpdateOrderSender = "CanUpdateOrderSender";
 
-        /// <summary>
-        /// 定量查询数据条数上限
-        /// </summary>
-        public const string FixedQueryCount = "FixedQueryCount";
-
         /// <summary>
         /// 是否开启重复工单
         /// </summary>

+ 1 - 1
src/XingTang.Sdk/CallXingtang.cs → src/XingTang.Sdk/XingtangCall.cs

@@ -3,7 +3,7 @@
 namespace XingTang.Sdk;
 
 [SugarTable("call_cti_trafficlist")]
-public class CallXingtang
+public class XingtangCall
 {
     [SugarColumn(ColumnName = "ID", IsPrimaryKey = true)]
     public int Id { get; set; }

+ 1 - 1
src/XingTang.Sdk/SeatOperation.cs → src/XingTang.Sdk/XingtangSeatOperation.cs

@@ -11,7 +11,7 @@ namespace XingTang.Sdk
     /// 坐席操作记录
     /// </summary>
     [SugarTable("call_cti_seatingoperation")]
-    public class SeatOperation
+    public class XingtangSeatOperation
     {
         [SugarColumn(ColumnName = "ID", IsPrimaryKey = true)]
         public int Id { get; set; }