ソースを参照

order接口重构呼叫中心接口

xf 9 ヶ月 前
コミット
9fc202c5f3

+ 112 - 26
src/Hotline.Api/Controllers/OrderController.cs

@@ -57,6 +57,8 @@ using SqlSugar;
 using StackExchange.Redis;
 using System.Diagnostics.Tracing;
 using Hotline.Application.CallCenter;
+using Hotline.CallCenter.Configs;
+using Microsoft.Extensions.Options;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Constants;
@@ -64,6 +66,7 @@ using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
+using Hotline.Repository.SqlSugar.CallCenter;
 
 namespace Hotline.Api.Controllers;
 
@@ -127,6 +130,7 @@ public class OrderController : BaseController
     private readonly IRepository<ExternalCitizens> _externalCitizensRepository;
     private readonly IRepository<OrderModifyingRecords> _orderModifyingRecordsRepository;
     private readonly ICallApplication _callApplication;
+    private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;
 
     public OrderController(
         IOrderDomainService orderDomainService,
@@ -183,8 +187,8 @@ public class OrderController : BaseController
         IRepository<OrderCopy> orderCopyRepository,
         IRepository<ExternalCitizens> externalCitizensRepository,
         IRepository<OrderModifyingRecords> orderModifyingRecordsRepository,
-        ICallApplication callApplication
-        )
+        ICallApplication callApplication,
+        IOptionsSnapshot<CallCenterConfiguration> callcenterOptions)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -241,6 +245,7 @@ public class OrderController : BaseController
         _externalCitizensRepository = externalCitizensRepository;
         _orderModifyingRecordsRepository = orderModifyingRecordsRepository;
         _callApplication = callApplication;
+        _callcenterOptions = callcenterOptions;
     }
 
     #region 工单发布
@@ -728,15 +733,29 @@ public class OrderController : BaseController
         var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason);
         var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner).Where(x => x.DicDataValue != "-1");
         //var callRecord = await _trCallRecordRepository.GetAsync(x => x.CallAccept == orderVisit.CallId); //由CallAccept改为OtherAccept
-        var callRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == orderVisit.CallId && string.IsNullOrEmpty(x.OtherAccept) == false, HttpContext.RequestAborted);
+        //var callRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == orderVisit.CallId && string.IsNullOrEmpty(x.OtherAccept) == false, HttpContext.RequestAborted);
         var recordingFileUrl = "";
         var recordingBaseAddress = "";
         var recordingAbsolutePath = "";
-        if (callRecord != null)
+        if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
         {
-            recordingFileUrl = callRecord.RecordingFileUrl;
-            recordingBaseAddress = callRecord.RecordingBaseAddress;
-            recordingAbsolutePath = callRecord.RecordingAbsolutePath;
+            var callRecord = await _callApplication.GetTianrunCallAsync(orderVisit.CallId, HttpContext.RequestAborted);
+            if (callRecord != null)
+            {
+                recordingFileUrl = callRecord.RecordingFileUrl;
+                recordingBaseAddress = callRecord.RecordingBaseAddress;
+                recordingAbsolutePath = callRecord.RecordingAbsolutePath;
+            }
+        }
+        else if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.XingTang)
+        {
+            var call = await _callApplication.GetCallAsync(orderVisit.CallId, HttpContext.RequestAborted);
+            if (call is not null)
+            {
+                recordingFileUrl = call.AudioFile;
+                recordingBaseAddress = call.AudioFile;
+                recordingAbsolutePath = call.AudioFile;
+            }
         }
 
         return new
@@ -2529,11 +2548,30 @@ public class OrderController : BaseController
         }
 
         //var call = await _trCallRecordRepository.Queryable().Where(x => x.CallAccept == order.CallId).FirstAsync();//由CallAccept改为OtherAccept
-        var call = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == order.CallId).FirstAsync();
-        if (call != null)
+        //var call = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == order.CallId).FirstAsync();
+        //if (call != null)
+        //{
+        //    dto.RecordingBaseAddress = call.RecordingBaseAddress;
+        //    dto.RecordingAbsolutePath = call.RecordingAbsolutePath;
+        //}
+
+        if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
+        {
+            var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, HttpContext.RequestAborted);
+            if (callRecord != null)
+            {
+                dto.RecordingBaseAddress = callRecord.RecordingBaseAddress;
+                dto.RecordingAbsolutePath = callRecord.RecordingAbsolutePath;
+            }
+        }
+        else if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.XingTang)
         {
-            dto.RecordingBaseAddress = call.RecordingBaseAddress;
-            dto.RecordingAbsolutePath = call.RecordingAbsolutePath;
+            var call = await _callApplication.GetCallAsync(order.CallId, HttpContext.RequestAborted);
+            if (call is not null)
+            {
+                dto.RecordingBaseAddress = call.AudioFile;
+                dto.RecordingAbsolutePath = call.AudioFile;
+            }
         }
 
         var repeatablesMap = await _repeatableEventDetailRepository.Queryable()
@@ -2598,12 +2636,17 @@ public class OrderController : BaseController
 
         //工单ID跟通话记录相关联
         //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
-        var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false, HttpContext.RequestAborted);
-        if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
+        //var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false, HttpContext.RequestAborted);
+        //if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
+        //{
+        //    callRecord.ExternalId = order.Id;
+        //    callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
+        //    await _trCallRecordRepository.UpdateAsync(callRecord, HttpContext.RequestAborted);
+        //}
+        if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
         {
-            callRecord.ExternalId = order.Id;
-            callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
-            await _trCallRecordRepository.UpdateAsync(callRecord, HttpContext.RequestAborted);
+            if (!string.IsNullOrEmpty(order.CallId))
+                await _callApplication.RelateTianrunCallWithOrderAsync(order.CallId, order.Id, HttpContext.RequestAborted);
         }
 
         //内容分词
@@ -2749,7 +2792,7 @@ public class OrderController : BaseController
         }
 
         _mapper.Map(dto, order);
-        if (order.SourceChannelCode != OrderDefaults.SourceChannel.DianHua)
+        if (order.SourceChannelCode != AppDefaults.SourceChannel.DianHua)
             order.CallId = null;
 
         if (dto.Files.Any())
@@ -4574,10 +4617,29 @@ public class OrderController : BaseController
         var citizen = await _citizenRepository.Queryable()
             .Includes(x => x.labelDetails)
             .FirstAsync(x => x.PhoneNumber == phone);
-        var calls = await _trCallRecordRepository.Queryable().Where(x => x.CallDirection == 0 && x.CPN == phone).OrderBy(x => x.CreatedTime).ToListAsync();
-        var oneCallTime = calls != null && calls.Count() > 0 ? calls[0].CreatedTime : DateTime.Now;
-        var lastNum = calls != null && calls.Count() > 0 ? calls.Count() - 1 : -1;
-        var lastCallTime = lastNum >= 0 ? calls[lastNum].CreatedTime : DateTime.Now;
+        //var calls = await _trCallRecordRepository.Queryable().Where(x => x.CallDirection == 0 && x.CPN == phone).OrderBy(x => x.CreatedTime).ToListAsync();
+        //var oneCallTime = calls != null && calls.Count() > 0 ? calls[0].CreatedTime : DateTime.Now;
+        //var lastNum = calls != null && calls.Count() > 0 ? calls.Count() - 1 : -1;
+        //var lastCallTime = lastNum >= 0 ? calls[lastNum].CreatedTime : DateTime.Now;
+
+        var oneCallTime = DateTime.Now;
+        var lastCallTime = DateTime.Now;
+        if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
+        {
+            var calls = await _callApplication.QueryTianrunCallsAsync(phone, ECallDirection.In, HttpContext.RequestAborted);
+            oneCallTime = calls.FirstOrDefault()?.CreatedTime ?? DateTime.Now;
+            var count = calls.Count;
+            lastCallTime = count > 1 ? calls[count - 2].CreatedTime : oneCallTime;
+        }
+        else if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.XingTang)
+        {
+            var calls = await _callApplication.QueryCallsAsync(phone, ECallDirection.In, HttpContext.RequestAborted);
+            oneCallTime = calls.FirstOrDefault()?.BeginIvrTime ?? DateTime.Now;
+            var count = calls.Count;
+            lastCallTime = count > 1 ? calls[count - 2].CreationTime : oneCallTime;
+        }
+
+
         //工单历史 
         var oders = await _orderRepository.Queryable().Where(x => x.Contact == phone)
             .OrderBy(x => x.CreationTime, OrderByType.Desc).ToListAsync();
@@ -4592,16 +4654,40 @@ public class OrderController : BaseController
                                                                 SqlFunc.JsonField(x.OrgProcessingResults, "Value") == "非常不满意"))
             .Distinct().Select(x => new { x.OrderVisit.OrderId }).CountAsync();
         //来电历史
-        var callsHistory = await _trCallRecordRepository.Queryable().Where(x => x.CPN == phone || x.CDPN == phone).ToListAsync();
+        //var callsHistory = await _trCallRecordRepository.Queryable().Where(x => x.CPN == phone || x.CDPN == phone).ToListAsync();
         var allCallNum = 0;
         var connectNum = 0;
         var callBackNum = 0;
-        if (callsHistory != null && callsHistory.Any())
+        //if (callsHistory != null && callsHistory.Any())
+        //{
+        //    allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In);
+        //    connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0);
+        //    callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out);
+        //}
+
+        if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
+        {
+            var callsHistory =
+                await _callApplication.QueryTianrunCallsAsync(phone, cancellationToken: HttpContext.RequestAborted);
+            if (callsHistory != null && callsHistory.Any())
+            {
+                allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In);
+                connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0);
+                callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out);
+            }
+        }
+        else if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.XingTang)
         {
-            allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In);
-            connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0);
-            callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out);
+            var histories =
+                await _callApplication.QueryCallsAsync(phone, cancellationToken: HttpContext.RequestAborted);
+            if(histories.Any())
+            {
+                allCallNum = histories.Count(x => x.Direction == ECallDirection.In);
+                connectNum = histories.Count(x => x.Direction == ECallDirection.In && x.Duration > 0);
+                callBackNum = histories.Count(x => x.Direction == ECallDirection.Out);
+            }
         }
+
         //关注诉求
         var hotspotNames = string.Join(",", oders.Select(x => x.HotspotName).Distinct().Take(5).ToList());
         var rsp = new

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

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

+ 10 - 1
src/Hotline.Api/StartupHelper.cs

@@ -262,7 +262,7 @@ namespace Hotline.Api
 
                 switch (callCenterConfiguration.CallCenterType)
                 {
-                    case "XingTang":
+                    case AppDefaults.CallCenterType.XingTang:
                         var getCallsJobKey = new JobKey(nameof(XingTangCallsSyncJob));
                         d.AddJob<XingTangCallsSyncJob>(getCallsJobKey);
                         d.AddTrigger(d => d
@@ -271,6 +271,15 @@ namespace Hotline.Api
                             .StartNow()
                             .WithCronSchedule("0/5 * * * * ?")
                         );
+
+                        var getOperationsJobKey = new JobKey(nameof(XingTangTelOperationSyncJob));
+                        d.AddJob<XingTangTelOperationSyncJob>(getOperationsJobKey);
+                        d.AddTrigger(d => d
+                            .WithIdentity("get-operationsxt-trigger")
+                            .ForJob(getOperationsJobKey)
+                            .StartNow()
+                            .WithCronSchedule("0/10 * * * * ?")
+                        );
                         break;
                 }
             });

+ 35 - 0
src/Hotline.Application/CallCenter/ICallApplication.cs

@@ -9,6 +9,7 @@ using Hotline.CallCenter.Tels;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.CallCenter;
 using XingTang.Sdk;
 
 namespace Hotline.Application.CallCenter
@@ -27,8 +28,19 @@ namespace Hotline.Application.CallCenter
 
         #region 黑名单
 
+        /// <summary>
+        /// 新增黑名单
+        /// </summary>
         Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 删除黑名单
+        /// </summary>
         Task RemoveBlackListAsync(string id, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询黑名单
+        /// </summary>
         Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken);
 
         #endregion
@@ -71,5 +83,28 @@ namespace Hotline.Application.CallCenter
         /// 批量获取callId
         /// </summary>
         Task<List<(string callNo, string callId)>> GetOrSetCallIdRangeAsync(List<string> callNos, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken);
+
+        Task<List<CallNative>> QueryCallsAsync(string phone, ECallDirection? direction = null, CancellationToken cancellationToken = default);
+
+        #region tianrun
+
+        Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 关联通话记录与order(添润)
+        /// </summary>
+        Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        Task<List<TrCallRecord>> QueryTianrunCallsAsync(string phone, ECallDirection? direction = null, CancellationToken cancellationToken = default);
+
+        #endregion
     }
 }

+ 203 - 127
src/Hotline.Application/CallCenter/TianRunCallApplication.cs

@@ -1,127 +1,203 @@
-//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;
-
-//        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<TelGroupDto>> QueryTelGroupsAsync(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<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 SingOutAsync(CancellationToken cancellationToken) =>
-//            _telApplication.SignOutAsync(_sessionContext.RequiredUserId, 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>
-//        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 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();
-//        }
-//    }
-//}
+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;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.CallCenter
+{
+    public class TianRunCallApplication : ICallApplication
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IRepository<TrCallRecord> _trCallRecordRepository;
+        private readonly ITrApplication _trApplication;
+        private readonly ITelApplication _telApplication;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+
+        public TianRunCallApplication(
+            ISessionContext sessionContext,
+            IRepository<TrCallRecord> trCallRecordRepository,
+            ITrApplication trApplication,
+            ITelApplication telApplication,
+            ISystemSettingCacheManager systemSettingCacheManager
+            )
+        {
+            _sessionContext = sessionContext;
+            _trCallRecordRepository = trCallRecordRepository;
+            _trApplication = trApplication;
+            _telApplication = telApplication;
+            _systemSettingCacheManager = systemSettingCacheManager;
+        }
+
+        /// <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 async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 删除黑名单
+        /// </summary>
+        public async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 查询黑名单
+        /// </summary>
+        public async 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 SingOutAsync(CancellationToken cancellationToken) =>
+            _telApplication.SignOutAsync(_sessionContext.RequiredUserId, 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>
+        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 async Task<IReadOnlyList<TelOperation>> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 依据通话记录编号获取映射后的callId
+        /// </summary>
+        public async Task<string> GetOrSetCallIdAsync(string callNo, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 批量获取callId
+        /// </summary>
+        public async Task<List<(string callNo, string callId)>> GetOrSetCallIdRangeAsync(List<string> callNos, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        public async Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<List<CallNative>> QueryCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrEmpty(callId)) return null;
+            var callRecord = await _trCallRecordRepository.GetAsync(
+                x => x.OtherAccept == callId && string.IsNullOrEmpty(x.OtherAccept) == false, cancellationToken);
+            return callRecord;
+        }
+
+        /// <summary>
+        /// 关联通话记录与order(添润)
+        /// </summary>
+        public async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
+        {
+            var callRecord = await _trCallRecordRepository.GetAsync(
+                p => p.OtherAccept == callId && string.IsNullOrEmpty(p.OtherAccept) == false, cancellationToken);
+            if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
+            {
+                callRecord.ExternalId = orderId;
+                callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
+                await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
+            }
+        }
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        public async Task<List<TrCallRecord>> QueryTianrunCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
+        {
+            return await _trCallRecordRepository.Queryable()
+                .Where(x => x.CallDirection == 0 && x.CPN == phone)
+                .OrderBy(x => x.CreatedTime).ToListAsync(cancellationToken);
+        }
+
+        /// <summary>
+        /// 定量查询通话记录
+        /// </summary>
+        public async Task<IReadOnlyList<CallNative>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 68 - 1
src/Hotline.Application/CallCenter/XingTangCallApplication.cs

@@ -93,21 +93,31 @@ namespace Hotline.Application.CallCenter
                 .ToListAsync(cancellationToken);
         }
 
+        /// <summary>
+        /// 新增黑名单
+        /// </summary>
         public async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
         {
             throw new NotImplementedException();
         }
 
+        /// <summary>
+        /// 删除黑名单
+        /// </summary>
         public async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
         {
             throw new NotImplementedException();
         }
 
+        /// <summary>
+        /// 查询黑名单
+        /// </summary>
         public async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
         {
             throw new NotImplementedException();
         }
 
+
         /// <summary>
         /// 签入
         /// </summary>
@@ -274,12 +284,69 @@ namespace Hotline.Application.CallCenter
                 .ToListAsync(cancellationToken);
 
             var rsp = new List<(string callNo, string callId)>();
+            var newRelations = new List<CallidRelation>();
             foreach (var callNo in callNos)
             {
                 var relation = relations.FirstOrDefault(d => d.Id == callNo);
                 if (relation is null)
-                    rsp.Add(new ());
+                {
+                    relation = new CallidRelation
+                    {
+                        Id = callNo,
+                        CallId = Ulid.NewUlid().ToString(),
+                    };
+                    newRelations.Add(relation);
+                    rsp.Add(new(relation.Id, relation.CallId));
+                }
+                else
+                {
+                    rsp.Add(new(relation.Id, relation.CallId));
+                }
             }
+
+            await _callidRelationRepository.AddRangeAsync(newRelations, cancellationToken);
+            return rsp;
+        }
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        public Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrEmpty(callId)) return null;
+            return _callNativeRepository.GetAsync(callId, cancellationToken);
+        }
+
+        public async Task<List<CallNative>> QueryCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
+        {
+            if (string.IsNullOrEmpty(phone))
+                return new List<CallNative>();
+            return await _callNativeRepository.Queryable()
+                .WhereIF(direction.HasValue, d=>d.Direction == direction)
+                .Where(d=>d.FromNo == phone || d.ToNo == phone)
+                .OrderBy(d=>d.CreationTime)
+                .ToListAsync(cancellationToken);
+        }
+
+        public async Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 关联通话记录与order(添润)
+        /// </summary>
+        public async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// 查询通话记录
+        /// </summary>
+        public async Task<List<TrCallRecord>> QueryTianrunCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
         }
     }
 

+ 2 - 2
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -67,13 +67,13 @@ namespace Hotline.Application.Jobs
                     .Where(d => staffNos.Contains(d.StaffNo))
                     .ToListAsync(context.CancellationToken);
 
-                var callids = await _callApplication.GetOrSetCallIdRangeAsync(
+                var relations = await _callApplication.GetOrSetCallIdRangeAsync(
                     calls.Select(d => d.CallNo).ToList(),
                     context.CancellationToken);
 
                 foreach (var call in calls)
                 {
-                    call.Id = await _callApplication.GetOrSetCallIdAsync(call.CallNo, context.CancellationToken);
+                    call.Id = relations.First(d => d.callNo == call.CallNo).callId;
                     var user = users.FirstOrDefault(d => d.StaffNo == call.StaffNo);
                     if (user is not null)
                     {

+ 31 - 0
src/Hotline/AppDefaults.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline
+{
+    public class AppDefaults
+    {
+        /// <summary>
+        /// 派单池id(用作派单池的用户id)
+        /// </summary>
+        public const string SendPoolId = "08dc592a-ecce-4d32-88d0-03eeae3c41c6";
+
+        public const string TrafficTrunkNum = "12328";
+
+        public class SourceChannel
+        {
+            public const string DianHua = "RGDH";
+        }
+
+        public class CallCenterType
+        {
+            public const string XunShi = "XunShi";
+            public const string WeiErXin = "WeiErXin";
+            public const string TianRun = "TianRun";
+            public const string XingTang = "XingTang";
+        }
+    }
+}

+ 2 - 2
src/Hotline/CallCenter/Tels/TelDomainService.cs

@@ -129,7 +129,7 @@ public class TelDomainService : ITelDomainService, IScopeDependency
 
         //await _deviceManager.TelRestAsync(telRest.TelNo, cancellationToken);
 
-        if (_options.Value.CallCenterType!= "WeiErXin")
+        if (_options.Value.CallCenterType == AppDefaults.CallCenterType.XunShi)
         {
             telRest.StartTime = DateTime.Now;
             telRest.ApplyStatus = ETelRestApplyStatus.Resting;
@@ -183,7 +183,7 @@ public class TelDomainService : ITelDomainService, IScopeDependency
             throw new UserFriendlyException("未查询到分机休息信息");
         restingTel.EndRest();
         await _telRestRepository.UpdateAsync(restingTel, cancellationToken);
-        if (_options.Value.CallCenterType != "WeiErXin")
+        if (_options.Value.CallCenterType == AppDefaults.CallCenterType.XunShi)
         {
             #region 处理设备
             var telCache = _telCacheManager.GetTel(tel.No);

+ 0 - 25
src/Hotline/Orders/OrderDefaults.cs

@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Hotline.Orders
-{
-    public class OrderDefaults
-    {
-        public class SourceChannel
-        {
-            public const string DianHua = "RGDH";
-
-            /// <summary>
-            /// 派单池id(用作派单池的用户id)
-            /// </summary>
-            public const string SendPoolId = "08dc592a-ecce-4d32-88d0-03eeae3c41c6";
-
-            public const string TrafficTrunkNum = "12328";
-
-
-		}
-	}
-}

+ 5 - 5
src/Hotline/Orders/OrderDomainService.cs

@@ -197,9 +197,9 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         if (scheduling is null)
             return new FlowStepHandler
             {
-                Key = OrderDefaults.SourceChannel.SendPoolId,
+                Key = AppDefaults.SendPoolId,
                 Value = "待派单池",
-                UserId = OrderDefaults.SourceChannel.SendPoolId,
+                UserId = AppDefaults.SendPoolId,
                 Username = "待派单池",
                 OrgId = OrgSeedData.CenterId,
                 OrgName = "市民热线服务中心"
@@ -229,7 +229,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         //2.获取今天上班的人员
         //3.给当前这个用户平均派单
 
-        var steps = await _workflowDomainService.GetStepsBelongsToAsync(OrderDefaults.SourceChannel.SendPoolId,
+        var steps = await _workflowDomainService.GetStepsBelongsToAsync(AppDefaults.SendPoolId,
             cancellationToken);
 
         var user = await _userRepository.Queryable()
@@ -271,7 +271,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 
         if (schedulings.Any())
         {
-            var steps = await _workflowDomainService.GetStepsBelongsToAsync(OrderDefaults.SourceChannel.SendPoolId,
+            var steps = await _workflowDomainService.GetStepsBelongsToAsync(AppDefaults.SendPoolId,
                 cancellationToken);
             if (steps.Any())
             {
@@ -309,7 +309,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     {
         var valid = new OrderValidation { Validation = false, Result = "" };
         var hotspot = await _hotspotRepository.GetAsync(dto.HotspotId, cancellationToken);
-        if (hotspot.TrunkNum.Equals(OrderDefaults.SourceChannel.TrafficTrunkNum))
+        if (hotspot.TrunkNum.Equals(AppDefaults.TrafficTrunkNum))
         {
             switch (dto.AcceptTypeCode)
             {