TianRunCallApplication.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using DotNetCore.CAP;
  7. using Hotline.Application.CallCenter.Calls;
  8. using Hotline.Application.Tels;
  9. using Hotline.Caching.Interfaces;
  10. using Hotline.CallCenter.BlackLists;
  11. using Hotline.CallCenter.Calls;
  12. using Hotline.CallCenter.Tels;
  13. using Hotline.Orders;
  14. using Hotline.Settings;
  15. using Hotline.Share.Dtos;
  16. using Hotline.Share.Dtos.CallCenter;
  17. using Hotline.Share.Dtos.Order;
  18. using Hotline.Share.Dtos.TrCallCenter;
  19. using Hotline.Share.Enums.CallCenter;
  20. using Hotline.Share.Enums.Order;
  21. using Hotline.Share.Mq;
  22. using MapsterMapper;
  23. using Microsoft.AspNetCore.Http;
  24. using SqlSugar;
  25. using XF.Domain.Authentications;
  26. using XF.Domain.Exceptions;
  27. using XF.Domain.Repository;
  28. namespace Hotline.Application.CallCenter
  29. {
  30. public class TianRunCallApplication : DefaultCallApplication
  31. {
  32. private readonly ISessionContext _sessionContext;
  33. private readonly IRepository<TrCallRecord> _trCallRecordRepository;
  34. private readonly ITrApplication _trApplication;
  35. private readonly ITelApplication _telApplication;
  36. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  37. private readonly IMapper _mapper;
  38. private readonly ICapPublisher _capPublisher;
  39. private readonly IRepository<TrCallEvaluate> _trCallEvaluateRepository;
  40. private readonly IOrderVisitDomainService _orderVisitDomainService;
  41. private readonly IOrderRepository _orderRepository;
  42. public TianRunCallApplication(
  43. ISessionContext sessionContext,
  44. IRepository<TrCallRecord> trCallRecordRepository,
  45. ITrApplication trApplication,
  46. ITelApplication telApplication,
  47. ISystemSettingCacheManager systemSettingCacheManager,
  48. IMapper mapper,
  49. ICapPublisher capPublisher,
  50. IRepository<TrCallEvaluate> trCallEvaluateRepository,
  51. IOrderVisitDomainService orderVisitDomainService,
  52. IOrderRepository orderRepository)
  53. {
  54. _sessionContext = sessionContext;
  55. _trCallRecordRepository = trCallRecordRepository;
  56. _trApplication = trApplication;
  57. _telApplication = telApplication;
  58. _systemSettingCacheManager = systemSettingCacheManager;
  59. _mapper = mapper;
  60. _capPublisher = capPublisher;
  61. _trCallEvaluateRepository = trCallEvaluateRepository;
  62. _orderVisitDomainService = orderVisitDomainService;
  63. _orderRepository = orderRepository;
  64. }
  65. /// <summary>
  66. /// 新增黑名单
  67. /// </summary>
  68. public override async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
  69. {
  70. throw new NotImplementedException();
  71. }
  72. /// <summary>
  73. /// 删除黑名单
  74. /// </summary>
  75. public override async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
  76. {
  77. throw new NotImplementedException();
  78. }
  79. /// <summary>
  80. /// 查询黑名单
  81. /// </summary>
  82. public override async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
  83. {
  84. throw new NotImplementedException();
  85. }
  86. /// <summary>
  87. /// 签入
  88. /// </summary>
  89. public override async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken) =>
  90. await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);
  91. /// <summary>
  92. /// 签出
  93. /// </summary>
  94. public override Task SingOutAsync(CancellationToken cancellationToken) =>
  95. _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);
  96. public override Task SingOutAsync(string telNo, CancellationToken cancellationToken) =>
  97. _telApplication.SignOutByTelNoAsync(telNo, cancellationToken);
  98. public override async Task<string> GetOrSetCallIdAsync(string callNo, CancellationToken cancellationToken)
  99. {
  100. return await Task.FromResult(callNo);
  101. }
  102. public override async Task PublishVisitRelevanceCallIdAsync(OrderRelevanceCallIdDto dto, CancellationToken cancellationToken)
  103. {
  104. return;
  105. }
  106. public override async Task OrderVisitRelevanceCallIdAsync(VisitDto dto, CancellationToken cancellationToken)
  107. {
  108. return;
  109. }
  110. /// <summary>
  111. /// 查询当前用户的分机状态
  112. /// </summary>
  113. /// <param name="cancellationToken"></param>
  114. /// <returns></returns>
  115. public override Task<TrOnDutyResponseDto> GetTelStateAsync(CancellationToken cancellationToken) =>
  116. _trApplication.TelState(_sessionContext.RequiredUserId, cancellationToken);
  117. public override async Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken)
  118. {
  119. if (string.IsNullOrEmpty(callId)) return null;
  120. var callRecord = await _trCallRecordRepository.GetAsync(
  121. x => x.OtherAccept == callId && string.IsNullOrEmpty(x.OtherAccept) == false, cancellationToken);
  122. return callRecord;
  123. }
  124. /// <summary>
  125. /// 根据转写ID获取通话信息
  126. /// </summary>
  127. /// <returns></returns>
  128. public override async Task<TrCallRecord?> GetTianrunCallTransliterationAsync(string transliterationId, CancellationToken cancellationToken)
  129. {
  130. if (string.IsNullOrEmpty(transliterationId)) return null;
  131. var callRecord = await _trCallRecordRepository.GetAsync(
  132. x => x.TransliterationId == transliterationId && string.IsNullOrEmpty(x.OtherAccept) == false, cancellationToken);
  133. return callRecord;
  134. }
  135. /// <summary>
  136. /// 修改转写状态
  137. /// </summary>
  138. /// <returns></returns>
  139. public override async Task EditTransliterationStateAsync(string callId, ECallTransliterationState state, string transliterationId, CancellationToken cancellationToken)
  140. {
  141. await _trCallRecordRepository.Updateable().SetColumns(o => new TrCallRecord { TransliterationState = state, TransliterationId = transliterationId })
  142. .Where(o => o.Id == callId).ExecuteCommandAsync(cancellationToken);
  143. }
  144. /// <summary>
  145. /// 关联通话记录与order(添润)
  146. /// </summary>
  147. public override async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
  148. {
  149. var callRecords = await _trCallRecordRepository.Queryable().Where(p => p.OtherAccept == callId && string.IsNullOrEmpty(p.OtherAccept) == false).ToListAsync(cancellationToken);
  150. if (callRecords.Any())
  151. {
  152. foreach (var callRecord in callRecords)
  153. {
  154. if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
  155. {
  156. callRecord.ExternalId = orderId;
  157. callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
  158. await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
  159. }
  160. }
  161. }
  162. else
  163. {
  164. //如果没查到通话记录就在2分钟后处理
  165. _capPublisher.PublishDelay(DateTime.Now.AddMinutes(2) - DateTime.Now, EventNames.OrderRelateCall, orderId);
  166. }
  167. }
  168. /// <summary>
  169. /// 处理工单和通话记录关联问题
  170. /// </summary>
  171. /// <param name="orderId"></param>
  172. /// <param name="cancellationToken"></param>
  173. /// <returns></returns>
  174. public override async Task<string> OrderRelateCallHandlerAsync(string orderId, CancellationToken cancellationToken)
  175. {
  176. var order = await _orderRepository.GetAsync(orderId, cancellationToken);
  177. if (order != null)
  178. {
  179. var callRecords = await _trCallRecordRepository.Queryable().Where(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false).ToListAsync(cancellationToken);
  180. if (callRecords.Any())
  181. {
  182. foreach (var callRecord in callRecords)
  183. {
  184. if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId))
  185. {
  186. callRecord.ExternalId = orderId;
  187. callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order;
  188. await _trCallRecordRepository.UpdateAsync(callRecord, cancellationToken);
  189. }
  190. }
  191. }
  192. }
  193. return "ok";
  194. }
  195. /// <summary>
  196. /// 查询通话记录
  197. /// </summary>
  198. public override async Task<List<TrCallRecord>> QueryTianrunCallsAsync(
  199. string? phone = null,
  200. ECallDirection? direction = null,
  201. DateTime? callStartTimeStart = null,
  202. DateTime? callStartTimeEnd = null,
  203. CancellationToken cancellationToken = default)
  204. {
  205. return await _trCallRecordRepository.Queryable()
  206. .WhereIF(!string.IsNullOrEmpty(phone), d => d.CPN == phone || d.CDPN == phone)
  207. .WhereIF(direction != null, d => d.CallDirection == direction)
  208. .WhereIF(callStartTimeStart != null, d => d.BeginIvrTime >= callStartTimeStart)
  209. .WhereIF(callStartTimeEnd != null, d => d.BeginIvrTime <= callStartTimeEnd)
  210. .OrderBy(x => x.CreatedTime)
  211. .ToListAsync(cancellationToken);
  212. }
  213. /// <summary>
  214. /// 查询分机操作选项
  215. /// </summary>
  216. /// <returns></returns>
  217. public override List<Kv> GetTelOperationOptions()
  218. {
  219. throw new NotImplementedException();
  220. }
  221. /// <summary>
  222. /// 查询通话记录
  223. /// </summary>
  224. public override async Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
  225. {
  226. var call = await _trCallRecordRepository.Queryable()
  227. .FirstAsync(d => d.OtherAccept == callId, cancellationToken);
  228. return _mapper.Map<CallNative?>(call);
  229. }
  230. /// <summary>
  231. /// 查询通话记录列表
  232. /// </summary>
  233. /// <param name="callId"></param>
  234. /// <param name="cancellationToken"></param>
  235. /// <returns></returns>
  236. public override async Task<List<CallNative>> GetCallListAsync(string callId, CancellationToken cancellationToken)
  237. {
  238. var call = await _trCallRecordRepository.Queryable()
  239. .Where(d => d.OtherAccept == callId).ToListAsync(cancellationToken);
  240. return _mapper.Map<List<CallNative>>(call);
  241. }
  242. /// <summary>
  243. /// 根据 OrderId 返回用户电话评价枚举
  244. /// 默认返回 默认满意
  245. /// </summary>
  246. /// <param name="orderId"></param>
  247. /// <returns></returns>
  248. public override async Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId)
  249. {
  250. throw new NotImplementedException();
  251. }
  252. /// <summary>
  253. /// 根据 OrderId 返回用户电话评价枚举
  254. /// 默认返回 默认满意
  255. /// </summary>
  256. /// <param name="orderId"></param>
  257. /// <returns></returns>
  258. public override async Task<ESeatEvaluate> GetSeatDefaultByOrderIdAsync(string orderId)
  259. {
  260. var callRecord = await _trCallRecordRepository.Queryable().Where(x => x.ExternalId == orderId && x.CallOrderType == ECallOrderType.Order).FirstAsync();
  261. if (callRecord is not null)
  262. {
  263. var callEvaluate = await _trCallEvaluateRepository.Queryable().Where(x => x.CallAccept == callRecord.CallAccept).FirstAsync();
  264. if (callEvaluate is null)
  265. return ESeatEvaluate.DefaultSatisfied;
  266. try
  267. {
  268. return (ESeatEvaluate)(Convert.ToInt32(callEvaluate.Dtmf.Trim()));
  269. }
  270. catch (UserFriendlyException)
  271. {
  272. return ESeatEvaluate.DefaultSatisfied;
  273. }
  274. }
  275. return ESeatEvaluate.DefaultSatisfied;
  276. }
  277. }
  278. }