dss il y a 2 ans
Parent
commit
ad06fde2bc

+ 1 - 1
src/CallCenter.Api/Controllers/TestController.cs

@@ -107,7 +107,7 @@ namespace CallCenter.Api.Controllers
         [HttpGet("ring")]
         public async Task RingTest()
         {
-            await _realtimeService.RingAsync(_sessionContext.RequiredUserId, new RingDto { Id="123", From = "13512341234",To="65123495",CallType = Share.Enums.ECallType.VisitorCallIn }, HttpContext.RequestAborted);
+            await _realtimeService.RingAsync(_sessionContext.RequiredUserId, new RingDto { Id="123", From = "13512341234",To="65123495",CallType = Share.Enums.ECallType.VisitorCallIn, ConversationId="333" }, HttpContext.RequestAborted);
         }
 
         /// <summary>

+ 2 - 0
src/CallCenter.Api/StartupExtensions.cs

@@ -44,7 +44,9 @@ internal static class StartupExtensions
         services.Configure<DeviceConfigs>(d => configuration.GetSection("DeviceConfigs").Bind(d));
         services.Configure<WorkTimeSettings>(d => configuration.GetSection("WorkTimeSettings").Bind(d));
         services.Configure<RecordSettings>(d => configuration.GetSection("RecordSettings").Bind(d));
+        services.Configure<SendCallRecord>(d => configuration.GetSection("SendCallRecord").Bind(d));
         services.Configure<IdentityConfiguration>(d => configuration.GetSection(nameof(IdentityConfiguration)).Bind(d));
+
         // Add services to the container.
         services
             .BatchInjectServices()

+ 4 - 1
src/CallCenter.Api/appsettings.json

@@ -49,7 +49,7 @@
   },
   "Swagger": true,
   "Cors": {
-    "Origins": [ "http://localhost:8888","http://localhost:8695","http://callcenter-admin.fengwo.com", "http://admin.call.fengwo.com" ]
+    "Origins": [ "http://localhost:8888", "http://localhost:8695", "http://callcenter-admin.fengwo.com", "http://admin.call.fengwo.com" ]
   },
   "WorkTimeSettings": {
     "LineSetting": [
@@ -107,6 +107,9 @@
     "Remote": "http://192.168.100.100/mcc/Recorder/",
     "Local": "http://192.168.100.36:50001/Recorder/"
   },
+  "SendCallRecord": {
+    "FwUrl": "http://192.168.100.84:8066/api/call/insertcalls"
+  },
   "IdentityConfiguration": {
     "Password": {
       "RequiredLength": 8,

+ 10 - 1
src/CallCenter.Application/Handlers/BaseHandler.cs

@@ -8,6 +8,7 @@ using NewRock.Sdk;
 using CallCenter.Devices;
 using Microsoft.Extensions.Options;
 using CallCenter.Caches;
+using CallCenter.Repository.SqlSugar;
 
 namespace CallCenter.Application.Handlers
 {
@@ -16,11 +17,13 @@ namespace CallCenter.Application.Handlers
         private readonly INewRockClient _newRockClient;
         private readonly IOptionsSnapshot<DeviceConfigs> _options;
         private readonly ICallCacheManager _callCacheManager;
-        public BaseHandler(INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager)
+        private readonly ICallRepository _callRepository;
+        public BaseHandler(INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager, ICallRepository callRepository)
         {
             _newRockClient = newRockClient;
             _options = options;
             _callCacheManager = callCacheManager;
+            _callRepository = callRepository;
         }
 
         public async Task HandlerIvr(IvrAnswer? runResult,Call model,CancellationToken cancellationToken)
@@ -97,6 +100,12 @@ namespace CallCenter.Application.Handlers
                         break;
                     case EIvrAnswerType.TelGroup:
                         var groupId = ivrAnswer.Content;
+                        if (model.InIvrTime!=null)
+                        {
+                            model.OutIvrTime = DateTime.Now;
+                        }
+                        model.InGroupTime = DateTime.Now;
+                        await _callRepository.UpdateAsync(model,cancellationToken);
                         await _newRockClient.VisitorToGroupQueue(new VisitorToGroupQueueRequest()
                         {
                             Attribute = "Queue",

+ 2 - 1
src/CallCenter.Application/Handlers/CallState/DtmfNotificationHandler.cs

@@ -3,6 +3,7 @@ using CallCenter.Calls;
 using CallCenter.Devices;
 using CallCenter.Ivrs;
 using CallCenter.Notifications;
+using CallCenter.Settings;
 using CallCenter.Share.Enums;
 using MediatR;
 using Microsoft.Extensions.Options;
@@ -21,7 +22,7 @@ namespace CallCenter.Application.Handlers
         private readonly ICallCacheManager _callCacheManager;
 
 
-        public DtmfNotificationHandler(IIvrDomainService ivrDomainService, ICallDetailRepository callDetailRepository, ICallRepository callRepository, INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager) :base(newRockClient, options,callCacheManager)
+        public DtmfNotificationHandler(IIvrDomainService ivrDomainService, ICallDetailRepository callDetailRepository, ICallRepository callRepository, INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager) :base(newRockClient, options,callCacheManager, callRepository)
         {
             _ivrDomainService = ivrDomainService;
             _callDetailRepository = callDetailRepository;

+ 2 - 0
src/CallCenter.Application/Handlers/CallState/RingVisitorToExtNotificationHandler.cs

@@ -32,6 +32,8 @@ namespace CallCenter.Application.Handlers
             if (model!=null)
             {
                 model.CallStatus = ECallStatus.Ring;
+                model.OutGroupTime = DateTime.Now;
+                model.InSeaTime = DateTime.Now;
                 await _callRepository.UpdateAsync(model, cancellationToken);
                 var detail = new CallDetail()
                 {

+ 1 - 0
src/CallCenter.Application/Handlers/FlowControl/AnsweredVisitorToExtNotificationHandler.cs

@@ -31,6 +31,7 @@ namespace CallCenter.Application.Handlers
             {
                 model.CallStatus = ECallStatus.Answered;
                 model.ToNo = notification.TelNo;
+                model.OutSeaTime = DateTime.Now;
                 await _callRepository.UpdateAsync(model, cancellationToken);
                 var detail = new CallDetail()
                 {

+ 37 - 1
src/CallCenter.Application/Handlers/FlowControl/CdrNotificationHandler.cs

@@ -1,7 +1,9 @@
 using CallCenter.Calls;
 using CallCenter.Notifications;
+using CallCenter.Share.Dtos;
 using CallCenter.Share.Enums;
 using MediatR;
+using Microsoft.Extensions.Options;
 
 namespace CallCenter.Application.Handlers
 {
@@ -10,12 +12,14 @@ namespace CallCenter.Application.Handlers
         private readonly ICallRecordRepository _callRecordRepository;
         private readonly ICallDetailRepository _callDetailRepository;
         private readonly ICallRepository _callRepository;
+        private readonly IOptionsSnapshot<SendCallRecord> _sendCallRecordOptions;
 
-        public CdrNotificationHandler(ICallRecordRepository callRecordRepository, ICallDetailRepository callDetailRepository, ICallRepository callRepository)
+        public CdrNotificationHandler(ICallRecordRepository callRecordRepository, ICallDetailRepository callDetailRepository, ICallRepository callRepository, IOptionsSnapshot<SendCallRecord> sendCallRecordOptions)
         {
             _callRecordRepository = callRecordRepository;
             _callDetailRepository = callDetailRepository;
             _callRepository = callRepository;
+            _sendCallRecordOptions= sendCallRecordOptions;
         }
 
         public async Task Handle(CdrNotification notification, CancellationToken cancellationToken)
@@ -56,7 +60,39 @@ namespace CallCenter.Application.Handlers
                 {
                     callModel.Duration = double.Parse(model.Duration);
                     await _callRepository.UpdateAsync(callModel, cancellationToken);
+
+                    var call = await _callRepository.GetExtAsync(callModel.Id, x => x.Includes(d => d.CallDetails));
+                    //TODO 推送通话报告
+                    OutCallDto callDto = new OutCallDto();
+                    callDto.CallId = callDetail.CallId;
+                    callDto.InfoType = EInfoType.Call;
+                    callDto.Direction = callModel.CallDirection;
+                    callDto.Cpn = callModel.FromNo ?? "";
+                    callDto.Cdpn = callModel.ToNo ?? "";
+                    if (callDto.Direction == ECallDirection.In)
+                    {
+                        callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.AnswerNo ?? "";
+                        callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWER")?.CreationTime;
+                        callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWER") ==true ? EOnState.On : EOnState.NoOn;
+                    }
+                    else
+                    {
+                        callDto.Answered = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.AnswerNo ?? "";
+                        callDto.OnTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "ANSWERED")?.CreationTime;
+                        callDto.OnState = call.CallDetails?.Any(x => x.EventName == "ANSWERED") == true ? EOnState.On : EOnState.NoOn;
+                    }
+                    callDto.BeginTime = call.CreationTime;
+                    callDto.ByeTime = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE").CreationTime;
+                    callDto.TalkTime = call.Duration;
+                    callDto.SoundFileName = call.CallDetails?.FirstOrDefault(x => x.EventName == "BYE")?.Recording ?? "";
+                    callDto.EvaluateResult = "";
+                    callDto.EndBy = call.EndBy;
+
+                //_sendCallRecordOptions.Value.FwUrl
                 }
+
+
+
             }
         }
     }

+ 1 - 1
src/CallCenter.Application/Handlers/FlowControl/EndOfAnnOuterToMenuNotificationHandler.cs

@@ -16,7 +16,7 @@ namespace CallCenter.Application.Handlers
         private readonly ICallDetailRepository _callDetailRepository;
         private readonly IIvrDomainService _ivrDomainService;
         private readonly ICallCacheManager _callCacheManager;
-        public EndOfAnnOuterToMenuNotificationHandler(ICallRepository callRepository, ICallDetailRepository callDetailRepository, IIvrDomainService ivrDomainService, INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager) : base(newRockClient, options,callCacheManager)
+        public EndOfAnnOuterToMenuNotificationHandler(ICallRepository callRepository, ICallDetailRepository callDetailRepository, IIvrDomainService ivrDomainService, INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager) : base(newRockClient, options,callCacheManager, callRepository)
         {
             _callRepository = callRepository;
             _callDetailRepository = callDetailRepository;

+ 1 - 1
src/CallCenter.Application/Handlers/FlowControl/EndOfAnnVisitorToMenuNotificationHandler.cs

@@ -18,7 +18,7 @@ namespace CallCenter.Application.Handlers.FlowControl
         private readonly IIvrDomainService _ivrDomainService;
         private readonly ICallCacheManager _callCacheManager;
 
-        public EndOfAnnVisitorToMenuNotificationHandler(ICallRepository callRepository, ICallDetailRepository callDetailRepository, IIvrDomainService ivrDomainService,INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager):base(newRockClient,options,callCacheManager)
+        public EndOfAnnVisitorToMenuNotificationHandler(ICallRepository callRepository, ICallDetailRepository callDetailRepository, IIvrDomainService ivrDomainService,INewRockClient newRockClient, IOptionsSnapshot<DeviceConfigs> options,ICallCacheManager callCacheManager):base(newRockClient,options,callCacheManager, callRepository)
         {
             _callRepository = callRepository;
             _callDetailRepository = callDetailRepository;

+ 59 - 52
src/CallCenter.Application/Handlers/FlowControl/IncomingNotificationHandler.cs

@@ -69,64 +69,71 @@ namespace CallCenter.Application.Handlers
                     ToNo = notification.Visitor.To,
                 };
                 await _callDetailRepository.AddAsync(detail, cancellationToken);
-            }
-            //TODO IVR处理
-            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IVRConfig);
-            if (bool.Parse(setting.SettingValue))
-            {
-                //TODO 获取工作或休息时间(接听策略)
-                //var ivrList = _ivrCacheManager.GetIvrs();
-                //var ivr = ivrList.First(x => x.IvrCategoryId == "08da9b9f-a35d-4ade-8ea7-55e8abbcdefd" && x.IsRoot);
-
-                //var ivr = GetCorrectIvr();
-                //_logger.LogInformation("transfer to ivr.no: {ivrNo}", ivr.No);
-                //await _newRockClient.VisitorToMenu(
-                //    new VisitorToMenuRequest()
-                //    {
-                //        Attribute = "Connect",
-                //        Menu = new VisitorToMenuMenu() { Id = ivr.No },
-                //        Visitor = new VisitorToMenuVisitor() { Id = notification.Visitor.Id }
-                //    },
-                //    _options.Value.ReceiveKey, _options.Value.Expired, cancellationToken);
 
                 var correct = GetCorrectIvr(notification.Visitor.To);
-                switch (correct.eCorrectIvr)
+
+                //TODO IVR处理
+                var setting = _systemSettingCacheManager.GetSetting(SettingConstants.IVRConfig);
+                if (bool.Parse(setting.SettingValue))
                 {
-                    //跳转IVR
-                    case ECorrectIvr.Ivr:
-                        _logger.LogInformation("transfer to ivr.no: {ivrNo}", correct.ReturnValue );
-                        await _newRockClient.VisitorToMenu(new VisitorToMenuRequest()
-                        {
-                            Attribute = "Connect",
-                            Menu = new VisitorToMenuMenu() { Id = correct.ReturnValue },
-                            Visitor = new VisitorToMenuVisitor() { Id = notification.Visitor.Id}
-                        },
-                        _options.Value.ReceiveKey,_options.Value.Expired,cancellationToken);
-                        break;
-                    //直接转分机组
-                    case ECorrectIvr.Group:
-                        _logger.LogInformation("transfer to group.no:{groupNo}", correct.ReturnValue);
-                        await _newRockClient.VisitorToGroupQueue(new VisitorToGroupQueueRequest()
-                        {
-                            Attribute= "Queue",
-                            Visitor = new VisitorToGroupQueueVisitor() { Id = notification.Visitor.Id },
-                            Group= new VisitorToGroupQueueGroup() { Id = correct.ReturnValue }
-                        },
-                        _options.Value.ReceiveKey,_options.Value.Expired,cancellationToken);
+                    //TODO 获取工作或休息时间(接听策略)
+                    //var ivrList = _ivrCacheManager.GetIvrs();
+                    //var ivr = ivrList.First(x => x.IvrCategoryId == "08da9b9f-a35d-4ade-8ea7-55e8abbcdefd" && x.IsRoot);
+
+                    //var ivr = GetCorrectIvr();
+                    //_logger.LogInformation("transfer to ivr.no: {ivrNo}", ivr.No);
+                    //await _newRockClient.VisitorToMenu(
+                    //    new VisitorToMenuRequest()
+                    //    {
+                    //        Attribute = "Connect",
+                    //        Menu = new VisitorToMenuMenu() { Id = ivr.No },
+                    //        Visitor = new VisitorToMenuVisitor() { Id = notification.Visitor.Id }
+                    //    },
+                    //    _options.Value.ReceiveKey, _options.Value.Expired, cancellationToken);
 
-                        //处理队列记录
-                        var list = _callCacheManager.GetCallQueueList().ToList();
-                        list.Add(model);
-                        _callCacheManager.AddOrUpdateCallCache(list);
-                        break;
-                    default:
-                        break;
+                    
+                    switch (correct.eCorrectIvr)
+                    {
+                        //跳转IVR
+                        case ECorrectIvr.Ivr:
+                            _logger.LogInformation("transfer to ivr.no: {ivrNo}", correct.ReturnValue);
+                            await _newRockClient.VisitorToMenu(new VisitorToMenuRequest()
+                            {
+                                Attribute = "Connect",
+                                Menu = new VisitorToMenuMenu() { Id = correct.ReturnValue },
+                                Visitor = new VisitorToMenuVisitor() { Id = notification.Visitor.Id }
+                            },
+                            _options.Value.ReceiveKey, _options.Value.Expired, cancellationToken);
+                            model.InIvrTime = DateTime.Now;
+                            await _callRepository.UpdateAsync(model, cancellationToken);
+                            break;
+                        //直接转分机组
+                        case ECorrectIvr.Group:
+                            _logger.LogInformation("transfer to group.no:{groupNo}", correct.ReturnValue);
+                            await _newRockClient.VisitorToGroupQueue(new VisitorToGroupQueueRequest()
+                            {
+                                Attribute = "Queue",
+                                Visitor = new VisitorToGroupQueueVisitor() { Id = notification.Visitor.Id },
+                                Group = new VisitorToGroupQueueGroup() { Id = correct.ReturnValue }
+                            },
+                            _options.Value.ReceiveKey, _options.Value.Expired, cancellationToken);
+                            model.InGroupTime = DateTime.Now;
+                            await _callRepository.UpdateAsync(model, cancellationToken);
+                            //处理队列记录
+                            var list = _callCacheManager.GetCallQueueList().ToList();
+                            list.Add(model);
+                            _callCacheManager.AddOrUpdateCallCache(list);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                else
+                {
+                    //TODO 跳转默认分机组
                 }
             }
-            else
-            {
-                //TODO 跳转默认分机组
-            }
+            
         }
 
         private Ivr GetCorrectIvr()

+ 30 - 0
src/CallCenter/Calls/Call.cs

@@ -115,5 +115,35 @@ namespace CallCenter.Calls
         /// </summary>
         [SugarColumn(IsNullable = true, ColumnDescription = "归属地")]
         public string? Attribution { get; set; }
+
+        /// <summary>
+        /// 进入IVR时间
+        /// </summary>
+        public DateTime? InIvrTime { get; set; }
+
+        /// <summary>
+        /// 离开IVR时间(进入队列时间)
+        /// </summary>
+        public DateTime? OutIvrTime { get; set; }
+
+        /// <summary>
+        /// 进入队列时间
+        /// </summary>
+        public DateTime? InGroupTime { get; set; }
+
+        /// <summary>
+        /// 离开队列时间(振铃时间)
+        /// </summary>
+        public DateTime? OutGroupTime { get; set; }
+
+        /// <summary>
+        /// 进入坐席时间(振铃时间)
+        /// </summary>
+        public DateTime? InSeaTime { get; set; }
+
+        /// <summary>
+        /// 离开坐席时间(应答时间)
+        /// </summary>
+        public DateTime? OutSeaTime { get; set; }
     }
 }

+ 13 - 0
src/CallCenter/Calls/SendCallRecord.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CallCenter.Calls
+{
+    public class SendCallRecord
+    {
+        public string FwUrl { get; set; }
+    }
+}

+ 3 - 1
src/XF.Domain.Repository/IRepositoryWithTKey.cs

@@ -1,4 +1,5 @@
-using System.Linq.Expressions;
+using SqlSugar;
+using System.Linq.Expressions;
 
 namespace XF.Domain.Repository
 {
@@ -22,6 +23,7 @@ namespace XF.Domain.Repository
         Task UpdateRangeAsync(List<TEntity> entities, CancellationToken cancellationToken = default);
         Task<TEntity?> GetAsync(TKey id, CancellationToken cancellationToken = default);
         Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
+
         Task<List<TEntity>> QueryAsync(
             Expression<Func<TEntity, bool>>? predicate = null,
             params (bool isWhere, Expression<Func<TEntity, bool>> expression)[] whereIfs);