Browse Source

新增处理内线拨打业务

dss 2 years ago
parent
commit
8b1e9e1b83

+ 4 - 4
src/Hotline.Api/Controllers/HomeController.cs

@@ -90,10 +90,10 @@ public class HomeController : BaseController
     [HttpPost("get-fastmenu")]
     public async Task<IReadOnlyList<SystemMenu>> GetFastMenuByToken([FromBody] GetFastMenuByTokenDto dto)
     {
-        if (!string.IsNullOrEmpty(_sessionContext.UserId))
+        if (!string.IsNullOrEmpty(_sessionContext.RequiredUserId))
         {
             var roles = _sessionContext.Roles;
-            return await _systemMenuRepository.GetFastMenu(roles, _sessionContext.UserId, dto.name);
+            return await _systemMenuRepository.GetFastMenu(roles, _sessionContext.RequiredUserId, dto.name);
         }
         throw UserFriendlyException.SameMessage("无效登录信息");
     }
@@ -106,9 +106,9 @@ public class HomeController : BaseController
     [HttpPost("set-fastmenu")]
     public async Task SetFastMenu([FromBody] SetFastMenuDto dto)
     {
-        if (!string.IsNullOrEmpty(_sessionContext.UserId))
+        if (!string.IsNullOrEmpty(_sessionContext.RequiredUserId))
         {
-            string userId = _sessionContext.UserId;
+            string userId = _sessionContext.RequiredUserId;
             var model = await _userFastMenuRepository.GetAsync(x => x.UserId == userId);
             if (model is null)
             {

+ 2 - 0
src/Hotline.Api/Controllers/ReportController.cs

@@ -1,5 +1,6 @@
 using Hotline.CallCenter;
 using Hotline.CallCenter.Devices;
+using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 
@@ -18,6 +19,7 @@ public class ReportController : ControllerBase
         _deviceEventHandler = deviceEventHandler;
     }
 
+    [AllowAnonymous]
     [HttpGet]
     public async Task ReceiveEvents()
     {

+ 57 - 0
src/Hotline.Application/Handlers/CallCenter/CallState/AlertExtToExtNotificationHandler.cs

@@ -0,0 +1,57 @@
+using Hotline.Caches;
+using Hotline.CallCenter.Calls;
+using Hotline.Share.Notifications;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Handlers.CallCenter.CallState
+{
+    public class AlertExtToExtNotificationHandler : INotificationHandler<AlertExtToExtNotification>
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly ICallDetailRepository _callDetailRepository;
+        private readonly IUserCacheManager _userCacheManager;
+
+        public AlertExtToExtNotificationHandler(ICallRepository callRepository,ICallDetailRepository callDetailRepository,IUserCacheManager userCacheManager)
+        {
+            _callRepository = callRepository;
+            _callDetailRepository = callDetailRepository;
+            _userCacheManager = userCacheManager;
+        }
+
+        public async Task Handle(AlertExtToExtNotification notification, CancellationToken cancellationToken)
+        {
+            var workModel = _userCacheManager.GetWorkByTel(notification.FromTelNo);
+            if (workModel is not null)
+            {
+                var callModel = new Call()
+                {
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Alert,
+                    CallDirection = Share.Enums.CallCenter.ECallDirection.Out,
+                    CallType = Share.Enums.CallCenter.ECallType.ExtToExt,
+                    FromNo = notification.FromTelNo,
+                    ToNo = notification.ToTelNo,
+                    UserId = workModel.UserId,
+                    UserName = workModel.UserName,
+                    PhoneIsp = Share.Enums.CallCenter.EPhoneISP.NULL,
+                };
+                callModel.Modified();
+                var callId = await _callRepository.AddAsync(callModel, cancellationToken);
+                //写入明细
+                var detail = new CallDetail()
+                {
+                    CallId = callId,
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Alert,
+                    EventName = "Alert",
+                    FromNo = notification.FromTelNo,
+                    ToNo = notification.ToTelNo,
+                };
+                await _callDetailRepository.AddAsync(detail, cancellationToken);
+            }
+        }
+    }
+}

+ 65 - 0
src/Hotline.Application/Handlers/CallCenter/CallState/RingExtToExtNotificationHandler.cs

@@ -0,0 +1,65 @@
+using Hotline.Caches;
+using Hotline.CallCenter.Calls;
+using Hotline.Realtimes;
+using Hotline.Share.Notifications;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Handlers.CallCenter.CallState
+{
+    public class RingExtToExtNotificationHandler : INotificationHandler<RingExtToExtNotification>
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly ICallDetailRepository _callDetailRepository;
+        private readonly IRealtimeService _realtimeService;
+        private readonly IUserCacheManager _userCacheManager;
+
+
+        public RingExtToExtNotificationHandler(ICallRepository callRepository,ICallDetailRepository callDetailRepository,IRealtimeService realtimeService,IUserCacheManager userCacheManager)
+        {
+            _callRepository = callRepository;
+            _callDetailRepository = callDetailRepository;
+            _realtimeService = realtimeService;
+            _userCacheManager = userCacheManager;
+        }
+
+
+        public async Task Handle(RingExtToExtNotification notification, CancellationToken cancellationToken)
+        {
+            var model = await _callRepository.GetAsync(x=>x.FromNo == notification.FromTelNo && x.ToNo== notification.ToTelNo && x.CallStatus == Share.Enums.CallCenter.ECallStatus.Alert && x.CreationTime >= DateTime.Now.AddHours(-1), cancellationToken);
+            if (model!=null)
+            {
+                model.CallStatus = Share.Enums.CallCenter.ECallStatus.Ring;
+                model.RingTime = DateTime.Now;
+                await _callRepository.UpdateAsync(model,cancellationToken);
+                var detail = new CallDetail()
+                {
+                    CallId = model.Id,
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Ring,
+                    EventName = notification.Attribute,
+                    FromNo = notification.FromTelNo,
+                    ToNo = notification.ToTelNo,
+                };
+                await _callDetailRepository.AddAsync(detail,cancellationToken);
+
+                //通知前端主叫
+                //获取主叫工作信息
+                var fromWork = _userCacheManager.GetWorkByTel(notification.FromTelNo);
+                if (fromWork!=null)
+                {
+                    await _realtimeService.RingAsync(fromWork.UserId, new Share.Dtos.Realtime.RingDto() { Id = model.Id, From = notification.FromTelNo, To = notification.ToTelNo, CallType = Share.Enums.CallCenter.ECallType.ExtToExt }, cancellationToken);
+                }
+                //通知前端被叫
+                var toWork = _userCacheManager.GetWorkByTel(notification.ToTelNo);
+                if (toWork!=null)
+                {
+                    await _realtimeService.RingAsync(toWork.UserId, new Share.Dtos.Realtime.RingDto() { Id = model.Id, From = notification.FromTelNo, To = notification.ToTelNo, CallType = Share.Enums.CallCenter.ECallType.ExtToExt }, cancellationToken);
+                }
+            }
+        }
+    }
+}

+ 1 - 1
src/Hotline.Application/Handlers/CallCenter/CallState/RingVisitorToExtNotificationHandler.cs

@@ -52,7 +52,7 @@ namespace Hotline.Application.Handlers.CallCenter.CallState
                 _callCacheManager.RemoveCallCache(model.Id);
 
                 //调用业务弹屏 通知前端
-                await _realtimeService.RingAsync(workModel.UserId, new Share.Dtos.Realtime.RingDto() { From = notification.Visitor.From, Id = model.Id, To= notification.TelNo }, cancellationToken);
+                await _realtimeService.RingAsync(workModel.UserId, new Share.Dtos.Realtime.RingDto() { From = notification.Visitor.From, Id = model.Id, To= notification.TelNo, CallType = ECallType.VisitorCallIn }, cancellationToken);
             }
         }
     }

+ 43 - 0
src/Hotline.Application/Handlers/CallCenter/FlowControl/AnswerExtToExtNoificationHandler.cs

@@ -0,0 +1,43 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Share.Notifications;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Handlers.CallCenter.FlowControl
+{
+    public class AnswerExtToExtNoificationHandler : INotificationHandler<AnswerExtToExtNotification>
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly ICallDetailRepository _callDetailRepository;
+
+        public AnswerExtToExtNoificationHandler(ICallRepository callRepository,ICallDetailRepository callDetailRepository)
+        {
+            _callRepository = callRepository;
+            _callDetailRepository = callDetailRepository;
+        }
+
+        public async Task Handle(AnswerExtToExtNotification notification, CancellationToken cancellationToken)
+        {
+            var model = await _callRepository.GetAsync(x=>x.FromNo == notification.FromTelNo && x.ToNo == notification.ToTelNo && x.CallStatus == Share.Enums.CallCenter.ECallStatus.Ring && x.CreationTime >= DateTime.Now.AddHours(-1),cancellationToken);
+
+            if (model!= null)
+            {
+                model.CallStatus = Share.Enums.CallCenter.ECallStatus.Answer;
+                await _callRepository.UpdateAsync(model, cancellationToken);
+                var detail = new CallDetail()
+                {
+                    CallId = model.Id,
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Answer,
+                    EventName = notification.Attribute,
+                    FromNo = notification.FromTelNo, 
+                    ToNo = notification.ToTelNo,
+                };
+                await _callDetailRepository.AddAsync(detail, cancellationToken);
+            }
+        }
+    }
+}

+ 47 - 0
src/Hotline.Application/Handlers/CallCenter/FlowControl/AnsweredExtToExtNotificationHandler.cs

@@ -0,0 +1,47 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Realtimes;
+using Hotline.Share.Notifications;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Handlers.CallCenter.FlowControl
+{
+    public class AnsweredExtToExtNotificationHandler : INotificationHandler<AnsweredExtToExtNotification>
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly ICallDetailRepository _callDetailRepository;
+        private readonly IRealtimeService _realtimeService;
+
+        public AnsweredExtToExtNotificationHandler(ICallRepository callRepository,ICallDetailRepository callDetailRepository,IRealtimeService realtimeService)
+        {
+            _callRepository = callRepository;
+            _callDetailRepository = callDetailRepository;
+            _realtimeService = realtimeService;
+        }
+
+        public async Task Handle(AnsweredExtToExtNotification notification, CancellationToken cancellationToken)
+        {
+            var model = await _callRepository.GetAsync(x => x.FromNo == notification.FromTelNo && x.ToNo == notification.ToTelNo && x.CreationTime >= DateTime.Now.AddHours(-1), cancellationToken);
+            if (model!=null)
+            {
+                model.CallStatus = Share.Enums.CallCenter.ECallStatus.Answered;
+                model.AnsweredTime = DateTime.Now;
+                await _callRepository.UpdateAsync(model, cancellationToken);
+                var detail = new CallDetail()
+                {
+                    CallId = model.Id,
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Answered,
+                    EventName = notification.Attribute,
+                    AnswerNo = notification.ToTelNo,
+                    FromNo = notification.FromTelNo, 
+                    ToNo = notification.ToTelNo,
+                };
+                await _callDetailRepository.AddAsync(detail, cancellationToken);
+            }
+        }
+    }
+}

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

@@ -31,7 +31,7 @@ namespace Hotline.Application.Handlers.CallCenter.FlowControl
             if (model != null)
             {
                 model.CallStatus = ECallStatus.Answered;
-                model.ToNo = notification.TelNo;
+                //model.ToNo = notification.TelNo;
                 model.AnsweredTime = DateTime.Now;
                 model.UserId = workModel.UserId;
                 model.UserName = workModel.UserName;

+ 45 - 0
src/Hotline.Application/Handlers/CallCenter/FlowControl/ByeExtAndExtNotificationHandler.cs

@@ -0,0 +1,45 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Share.Notifications;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Handlers.CallCenter.FlowControl
+{
+    public class ByeExtAndExtNotificationHandler : INotificationHandler<ByeExtAndExtNotification>
+    {
+        private readonly ICallRepository _callRepository;
+        private readonly ICallDetailRepository _callDetailRepository;
+
+        public ByeExtAndExtNotificationHandler(ICallRepository callRepository,ICallDetailRepository callDetailRepository)
+        {
+            _callRepository = callRepository;
+            _callDetailRepository = callDetailRepository;
+        }
+
+        public async Task Handle(ByeExtAndExtNotification notification, CancellationToken cancellationToken)
+        {
+            var model = await _callRepository.GetAsync(x => x.FromNo == notification.FromTelNo && x.ToNo == notification.ToTelNo && x.CallStatus == Share.Enums.CallCenter.ECallStatus.Answered && x.CreationTime >= DateTime.Now.AddHours(-1), cancellationToken);
+            if (model!=null)
+            {
+                model.CallStatus = Share.Enums.CallCenter.ECallStatus.Bye;
+                model.EndBy = Share.Enums.CallCenter.EEndBy.From;
+                model.RingOffType = Share.Enums.CallCenter.ERingOffType.Normal;
+                model.ByeTime = DateTime.Now;
+                await _callRepository.UpdateAsync(model,cancellationToken);
+                var detail = new CallDetail()
+                {
+                    CallId = model.Id,
+                    CallStatus = Share.Enums.CallCenter.ECallStatus.Bye,
+                    EventName = notification.Attribute,
+                    FromNo = notification.FromTelNo,
+                    ToNo = notification.ToTelNo,
+                    Recording = notification.Recording,
+                };
+            }
+        }
+    }
+}

+ 68 - 32
src/Hotline.Application/Handlers/CallCenter/FlowControl/CdrNotificationHandler.cs

@@ -23,46 +23,82 @@ namespace Hotline.Application.Handlers.CallCenter.FlowControl
 
         public async Task Handle(CdrNotification notification, CancellationToken cancellationToken)
         {
-            var callDetail = await 
-                _callDetailRepository.GetAsync(x => x.OMCallId == notification.CallId, cancellationToken);
-            
-            if (callDetail!=null)
+            //内部互拨
+            if (notification.Type == "LO")
             {
-                var model = new CallRecord()
+                //获取最后一通内线电话
+                var call = await _callRepository.GetLastLOCall(notification.CPN, notification.CDPN);
+                if (call != null)
                 {
-                    CallId = callDetail.CallId,
-                    CdrId = notification.Id,
-                    CDRCallId = notification.CallId,
-                    TimeStart = notification.TimeStart,
-                    Group = notification.Group,
-                    Type = (ECDRType)Enum.Parse(typeof(ECDRType), notification.Type),
-                    Route = (ECDRRoute)Enum.Parse(typeof(ECDRRoute), notification.Route),
-                    CPN = notification.CPN,
-                    CDPN = notification.CDPN,
-                    TimeEnd = notification.TimeEnd,
-                    Duration = notification.Duration,
-                    TrunkNumber = notification.TrunkNumber,
-                    Recording = notification.Recording,
-                    RecCodec = notification.RecCodec,
-                };
-                if (!string.IsNullOrEmpty(notification.VisitorId))
-                    model.VisitorId = notification.VisitorId;
+                    var model = new CallRecord()
+                    {
+                        CallId = call.Id,
+                        CdrId = notification.Id,
+                        CDRCallId = notification.CallId,
+                        TimeStart = notification.TimeStart,
+                        Group = notification.Group,
+                        Type = (ECDRType)Enum.Parse(typeof(ECDRType),notification.Type),
+                        Route = (ECDRRoute)Enum.Parse(typeof(ECDRRoute),notification.Route),
+                        CPN = notification.CPN,
+                        CDPN= notification.CDPN,
+                        TimeEnd = notification.TimeEnd,
+                        Duration= notification.Duration,
+                        TrunkNumber = notification.TrunkNumber,
+                        Recording = notification.Recording,
+                        RecCodec = notification.RecCodec,
+                    };
+                    await _callRecordRepository.AddAsync(model, cancellationToken);
 
-                if (!string.IsNullOrEmpty(notification.OuterId))
-                    model.OuterId = notification.OuterId;
+                    call.Duration = double.Parse(model.Duration);
+                    await _callRepository.UpdateAsync(call, cancellationToken);
 
-                await _callRecordRepository.AddAsync(model,cancellationToken);
+                    //处理Hold计算
+                    await _telHoldRepository.HandleHoldTime(call.Id, notification.TimeEnd, cancellationToken);
+                }
                 
-                var callModel = await _callRepository.GetAsync(x => x.Id == callDetail.CallId,cancellationToken);
-                if (callModel!=null)
+            }
+            else
+            {
+                var callDetail = await
+                _callDetailRepository.GetAsync(x => x.OMCallId == notification.CallId, cancellationToken);
+
+                if (callDetail != null)
                 {
-                    callModel.Duration = double.Parse(model.Duration);
-                    await _callRepository.UpdateAsync(callModel, cancellationToken);
-                }
+                    var model = new CallRecord()
+                    {
+                        CallId = callDetail.CallId,
+                        CdrId = notification.Id,
+                        CDRCallId = notification.CallId,
+                        TimeStart = notification.TimeStart,
+                        Group = notification.Group,
+                        Type = (ECDRType)Enum.Parse(typeof(ECDRType), notification.Type),
+                        Route = (ECDRRoute)Enum.Parse(typeof(ECDRRoute), notification.Route),
+                        CPN = notification.CPN,
+                        CDPN = notification.CDPN,
+                        TimeEnd = notification.TimeEnd,
+                        Duration = notification.Duration,
+                        TrunkNumber = notification.TrunkNumber,
+                        Recording = notification.Recording,
+                        RecCodec = notification.RecCodec,
+                    };
+                    if (!string.IsNullOrEmpty(notification.VisitorId))
+                        model.VisitorId = notification.VisitorId;
+
+                    if (!string.IsNullOrEmpty(notification.OuterId))
+                        model.OuterId = notification.OuterId;
 
-                //处理Hold计算
-                await _telHoldRepository.HandleHoldTime(callDetail.CallId,notification.TimeEnd, cancellationToken);
+                    await _callRecordRepository.AddAsync(model, cancellationToken);
 
+                    var callModel = await _callRepository.GetAsync(x => x.Id == callDetail.CallId, cancellationToken);
+                    if (callModel != null)
+                    {
+                        callModel.Duration = double.Parse(model.Duration);
+                        await _callRepository.UpdateAsync(callModel, cancellationToken);
+                    }
+
+                    //处理Hold计算
+                    await _telHoldRepository.HandleHoldTime(callDetail.CallId, notification.TimeEnd, cancellationToken);
+                }
             }
         }
     }

+ 6 - 2
src/Hotline.NewRock/Handlers/DeviceEventHandler.cs

@@ -191,7 +191,7 @@ namespace Hotline.NewRock.Handlers
                     case Event.BYE:
                         var byeRcv = content.DeserializeWithAuthorize<ByeEvent>();
                         //来电和分机的通话结束,来电挂断
-                        if (byeRcv.value?.Ext != null && byeRcv.value?.Visitor != null)
+                        if (byeRcv.value?.Ext.Count==1 && byeRcv.value?.Visitor != null)
                         {
                             await _mediator.Publish(_mapper.Map<ByeVisitorAndExtNotification>(byeRcv.value!),
                                 cancellationToken);
@@ -208,11 +208,15 @@ namespace Hotline.NewRock.Handlers
                             await _mediator.Publish(_mapper.Map<ByeVisitorAndOuterNotification>(byeRcv.value!),
                                 cancellationToken);
                         }
+                        else if(byeRcv.value?.Ext.Count==2)
+                        {
+                            await _mediator.Publish(_mapper.Map<ByeExtAndExtNotification>(byeRcv.value!), cancellationToken);
+                        }
                         //其他条件
                         else if (byeRcv.value?.Outer != null)
                         {
                             //分机和去电的通话结束,分机挂断 类型一
-                            if (byeRcv.value?.Ext != null)
+                            if (byeRcv.value?.Ext.Count == 1)
                             {
                                 await _mediator.Publish(_mapper.Map<ByeExtAndOuterOneNotification>(byeRcv.value!),
                                     cancellationToken);

+ 6 - 2
src/Hotline.NewRock/Mappers/EventConfigs.cs

@@ -101,10 +101,14 @@ namespace Hotline.NewRock.Mappers
             #region 通话结束事件
             //来电和分机的通话结束,来电挂断
             config.NewConfig<ByeEvent, ByeVisitorAndExtNotification>()
-                .Map(d => d.TelNo, x => x.Ext.Id);
+                .Map(d => d.TelNo, x => x.Ext[0].Id);
             //分机和去电的通话结束,分机挂断 类型一
             config.NewConfig<ByeEvent, ByeExtAndOuterOneNotification>()
-                .Map(d => d.TelNo, x => x.Ext.Id);
+                .Map(d => d.TelNo, x => x.Ext[0].Id);
+            //分机和分机的通话结束
+            config.NewConfig<ByeEvent, ByeExtAndExtNotification>()
+                .Map(d => d.FromTelNo, x => x.Ext[0].Id)
+                .Map(d => d.ToTelNo, x => x.Ext[1].Id);
             #endregion
 
             #region 呼叫转移事件

+ 6 - 0
src/Hotline.Repository.SqlSugar/CallCenter/CallRepository.cs

@@ -2,6 +2,7 @@
 using Hotline.Repository.SqlSugar.DataPermissions;
 using Hotline.Share.Enums.CallCenter;
 using SqlSugar;
+using System.Reflection.Metadata.Ecma335;
 using XF.Domain.Dependency;
 
 namespace Hotline.Repository.SqlSugar.CallCenter
@@ -23,5 +24,10 @@ namespace Hotline.Repository.SqlSugar.CallCenter
                 .Take(10)
                 .ToListAsync();
         }
+
+        public async Task<Call> GetLastLOCall(string cpn, string cdpn)
+        {
+            return await Db.Queryable<Call>().OrderByDescending(x => x.CreationTime).Where(x => x.FromNo == cpn && x.ToNo == cdpn).FirstAsync();
+        }
     }
 }

+ 1 - 0
src/Hotline.Share/Dtos/Realtime/RingDto.cs

@@ -5,6 +5,7 @@ public record RingDto
     public string Id { get; set; }
     public string From { get; set; }
     public string To { get; set; }
+    public Enums.CallCenter.ECallType CallType { get; set; }
 }
 
 public record AnsweredDto

+ 12 - 0
src/Hotline.Share/Notifications/ByeExtAndExtNotification.cs

@@ -0,0 +1,12 @@
+using Hotline.Share.Notifications.Base;
+using MediatR;
+
+namespace Hotline.Share.Notifications
+{
+    public class ByeExtAndExtNotification: BaseEvent, INotification
+    {
+        public string FromTelNo { get; set; }
+        public string ToTelNo { get; set; }
+        public string Recording { get; set; }
+    }
+}

+ 2 - 2
src/Hotline/CallCenter/Calls/CallRecord.cs

@@ -15,7 +15,7 @@ namespace Hotline.CallCenter.Calls
         /// <summary>
         /// 通话记录ID
         /// </summary>
-        [SugarColumn(ColumnDescription = "通话记录ID")]
+        [SugarColumn(IsNullable = true,ColumnDescription = "通话记录ID")]
         public string CallId { get; set; }
 
         /// <summary>
@@ -91,7 +91,7 @@ namespace Hotline.CallCenter.Calls
         /// <summary>
         /// 该路通话所经过的中继号码
         /// </summary>
-        [SugarColumn(ColumnDescription = "该路通话所经过的中继号码")]
+        [SugarColumn(IsNullable = true,ColumnDescription = "该路通话所经过的中继号码")]
         public string TrunkNumber { get; set; }
         /// <summary>
         /// 录音文件的相对保存路径

+ 2 - 0
src/Hotline/CallCenter/Calls/ICallRepository.cs

@@ -10,5 +10,7 @@ namespace Hotline.CallCenter.Calls
         /// </summary>
         /// <returns></returns>
         Task<IReadOnlyList<Call>> QueryPartAsync(DateTime datetime);
+
+        Task<Call> GetLastLOCall(string cpn, string cdpn);
     }
 }

+ 1 - 1
src/NewRock.Sdk/Events/ByeEvent.cs

@@ -9,7 +9,7 @@ namespace NewRock.Sdk.Events
     public class ByeEvent: NewRockEvent
     {
         [XmlElement("ext")]
-        public Ext Ext { get; set; }
+        public List<Ext> Ext { get; set; }
 
         [XmlElement("visitor")]
         public BaseVisitor Visitor { get; set; }