XingTangCallApplication.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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.Caching.Interfaces;
  8. using Hotline.Caching.Services;
  9. using Hotline.CallCenter.BlackLists;
  10. using Hotline.CallCenter.Calls;
  11. using Hotline.CallCenter.Tels;
  12. using Hotline.Orders;
  13. using Hotline.Repository.SqlSugar.CallCenter;
  14. using Hotline.Repository.SqlSugar.Extensions;
  15. using Hotline.Repository.SqlSugar.Orders;
  16. using Hotline.Settings;
  17. using Hotline.Share.Dtos;
  18. using Hotline.Share.Dtos.CallCenter;
  19. using Hotline.Share.Dtos.Order;
  20. using Hotline.Share.Dtos.TrCallCenter;
  21. using Hotline.Share.Enums.CallCenter;
  22. using Hotline.Users;
  23. using MapsterMapper;
  24. using Microsoft.AspNetCore.Http;
  25. using Microsoft.Extensions.Logging;
  26. using XF.Domain.Authentications;
  27. using XF.Domain.Cache;
  28. using XF.Domain.Exceptions;
  29. using XF.Domain.Repository;
  30. using XingTang.Sdk;
  31. namespace Hotline.Application.CallCenter
  32. {
  33. //临时方案,后续需重构为:业务内部统一采用CallNative
  34. public class XingTangCallApplication : DefaultCallApplication
  35. {
  36. // private readonly IRepository<Tel> _telRepository;
  37. // private readonly IRepository<TelGroup> _telGroupRepository;
  38. // private readonly IWorkRepository _workRepository;
  39. // private readonly ITelRestRepository _telRestRepository;
  40. // private readonly IRepository<CallNative> _callNativeRepository;
  41. // private readonly IRepository<TelOperation> _teloperationRepository;
  42. // private readonly IRepository<CallidRelation> _callidRelationRepository;
  43. // private readonly ITypedCache<Work> _cacheWork;
  44. // private readonly IUserCacheManager _userCacheManager;
  45. // private readonly ISessionContext _sessionContext;
  46. // private readonly IMapper _mapper;
  47. // private readonly ILogger<XingTangCallApplication> _logger;
  48. public XingTangCallApplication(
  49. IRepository<Tel> telRepository,
  50. IRepository<TelGroup> telGroupRepository,
  51. IWorkRepository workRepository,
  52. ITelRestRepository telRestRepository,
  53. IRepository<CallNative> callNativeRepository,
  54. IRepository<TelOperation> teloperationRepository,
  55. IRepository<CallidRelation> callidRelationRepository,
  56. ITypedCache<Work> cacheWork,
  57. IUserCacheManager userCacheManager,
  58. ISessionContext sessionContext,
  59. IMapper mapper,
  60. ILogger<XingTangCallApplication> logger,
  61. IOrderVisitRepository orderVisitRepository
  62. ) : base(telRepository, telGroupRepository, workRepository, telRestRepository, callNativeRepository,
  63. teloperationRepository, callidRelationRepository, cacheWork, userCacheManager, sessionContext, mapper,
  64. logger, orderVisitRepository)
  65. {
  66. // _telRepository = telRepository;
  67. // _telGroupRepository = telGroupRepository;
  68. // _workRepository = workRepository;
  69. // _telRestRepository = telRestRepository;
  70. // _callNativeRepository = callNativeRepository;
  71. // _teloperationRepository = teloperationRepository;
  72. // _callidRelationRepository = callidRelationRepository;
  73. // _cacheWork = cacheWork;
  74. // _userCacheManager = userCacheManager;
  75. // _sessionContext = sessionContext;
  76. // _mapper = mapper;
  77. // _logger = logger;
  78. }
  79. // /// <summary>
  80. // /// 查询分机
  81. // /// </summary>
  82. // public async Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
  83. // {
  84. // return await _telRepository.Queryable()
  85. // .Select<TelDto>()
  86. // .ToListAsync(cancellationToken);
  87. // }
  88. //
  89. // /// <summary>
  90. // /// 查询分机组
  91. // /// </summary>
  92. // public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
  93. // {
  94. // return await _telGroupRepository.Queryable()
  95. // .Select<TelGroupDto>()
  96. // .ToListAsync(cancellationToken);
  97. // }
  98. // /// <summary>
  99. // /// 新增黑名单
  100. // /// </summary>
  101. // public async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
  102. // {
  103. // throw new NotImplementedException();
  104. // }
  105. //
  106. // /// <summary>
  107. // /// 删除黑名单
  108. // /// </summary>
  109. // public async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
  110. // {
  111. // throw new NotImplementedException();
  112. // }
  113. //
  114. // /// <summary>
  115. // /// 查询黑名单
  116. // /// </summary>
  117. // public async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
  118. // {
  119. // throw new NotImplementedException();
  120. // }
  121. // /// <summary>
  122. // /// 签入
  123. // /// </summary>
  124. // public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
  125. // {
  126. // if (string.IsNullOrEmpty(dto.TelNo))
  127. // throw UserFriendlyException.SameMessage("无效分机号");
  128. // var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId);
  129. // if (work is not null)
  130. // {
  131. // //if (work.TelNo != dto.TelNo)
  132. // //{
  133. // // throw UserFriendlyException.SameMessage("当前用户已签入其他分机");
  134. // //}
  135. // throw UserFriendlyException.SameMessage("当前用户已签入");
  136. // }
  137. //
  138. // var telWork = _userCacheManager.GetWorkByTelNoExp(dto.TelNo);
  139. // if (telWork is not null)
  140. // {
  141. // throw UserFriendlyException.SameMessage("当前分机已被占用");
  142. // }
  143. //
  144. // work = new Work(_sessionContext.RequiredUserId, _sessionContext.UserName,
  145. // dto.TelNo, dto.TelNo, null, null,
  146. // dto.GroupId, _sessionContext.StaffNo, null);
  147. // await _workRepository.AddAsync(work, cancellationToken);
  148. //
  149. // return new TrOnDutyResponseDto
  150. // {
  151. // TelNo = dto.TelNo,
  152. // QueueId = dto.GroupId,
  153. // StartTime = work.StartTime,
  154. // };
  155. // }
  156. //
  157. // /// <summary>
  158. // /// 签出
  159. // /// </summary>
  160. // public async Task SingOutAsync(CancellationToken cancellationToken)
  161. // {
  162. // var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId);
  163. // if (work is null) return;
  164. //
  165. // var telRest = await _telRestRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, cancellationToken);
  166. // if (telRest is not null)
  167. // {
  168. // telRest.EndRest();
  169. // await _telRestRepository.UpdateAsync(telRest, cancellationToken);
  170. // }
  171. //
  172. // work.OffDuty();
  173. // await _workRepository.UpdateAsync(work, cancellationToken);
  174. // await _cacheWork.RemoveAsync(work.GetKey(KeyMode.UserId), cancellationToken);
  175. // await _cacheWork.RemoveAsync(work.GetKey(KeyMode.TelNo), cancellationToken);
  176. // }
  177. //
  178. // public async Task SingOutAsync(string telNo, CancellationToken cancellationToken)
  179. // {
  180. // var work = _userCacheManager.GetWorkByTelNoExp(telNo);
  181. // if (work is null) return;
  182. //
  183. // var telRest = await _telRestRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, cancellationToken);
  184. // if (telRest is not null)
  185. // {
  186. // telRest.EndRest();
  187. // await _telRestRepository.UpdateAsync(telRest, cancellationToken);
  188. // }
  189. //
  190. // work.OffDuty();
  191. // await _workRepository.UpdateAsync(work, cancellationToken);
  192. // await _cacheWork.RemoveAsync(work.GetKey(KeyMode.UserId), cancellationToken);
  193. // await _cacheWork.RemoveAsync(work.GetKey(KeyMode.TelNo), cancellationToken);
  194. // }
  195. //
  196. // /// <summary>
  197. // /// 查询当前用户的分机状态
  198. // /// </summary>
  199. // /// <param name="cancellationToken"></param>
  200. // /// <returns></returns>
  201. // public async Task<TrOnDutyResponseDto> GetTelStateAsync(CancellationToken cancellationToken)
  202. // {
  203. // var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId);
  204. // if (work is null) return null;
  205. // return await Task.FromResult(new TrOnDutyResponseDto
  206. // {
  207. // TelNo = work.TelNo,
  208. // QueueId = work.QueueId,
  209. // StartTime = work.StartTime,
  210. // });
  211. // }
  212. //
  213. // /// <summary>
  214. // /// 定量查询通话记录
  215. // /// </summary>
  216. // public async Task<IReadOnlyList<CallNativeDto>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
  217. // {
  218. // return await _callNativeRepository.Queryable(includeDeleted: true)
  219. // .LeftJoin<Order>((d, o) => d.CallNo == o.CallId)
  220. // .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), (d, o) => o.No == dto.OrderNo)
  221. // .WhereIF(!string.IsNullOrEmpty(dto.FromNo), d => d.FromNo == dto.FromNo)
  222. // .WhereIF(!string.IsNullOrEmpty(dto.ToNo), d => d.ToNo == dto.ToNo)
  223. // .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName)
  224. // .WhereIF(!string.IsNullOrEmpty(dto.TelNo), d => d.TelNo == dto.TelNo)
  225. // .WhereIF(dto.EndBy != null, d => d.EndBy == dto.EndBy)
  226. // .WhereIF(dto.CallStartTimeBT != null, d => d.BeginIvrTime >= dto.CallStartTimeBT)
  227. // .WhereIF(dto.CallStartTimeLT != null, d => d.BeginIvrTime <= dto.CallStartTimeLT)
  228. // .WhereIF(dto.IsConnected != null, d => d.AnsweredTime != null)
  229. // .WhereIF(dto.Direction != null, d => d.Direction == dto.Direction)
  230. // .Select((d, o) => new CallNativeDto
  231. // {
  232. // OrderId = o.Id,
  233. // OrderNo = o.No,
  234. // Title = o.Title,
  235. // }, true)
  236. // .ToFixedListAsync(dto, cancellationToken);
  237. // }
  238. //
  239. // /// <summary>
  240. // /// 查询分机操作记录(定量)
  241. // /// </summary>
  242. // public async Task<IReadOnlyList<TelOperation>> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto, CancellationToken cancellationToken)
  243. // {
  244. // return await _teloperationRepository.Queryable()
  245. // .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName)
  246. // .WhereIF(!string.IsNullOrEmpty(dto.StaffNo), d => d.StaffNo == dto.StaffNo)
  247. // .WhereIF(!string.IsNullOrEmpty(dto.GroupId), d => d.GroupId == dto.GroupId)
  248. // .WhereIF(dto.OperateState != null, d => d.OperateState == dto.OperateState)
  249. // .ToFixedListAsync(dto, cancellationToken);
  250. // }
  251. // /// <summary>
  252. // /// 依据通话记录编号获取映射后的callId
  253. // /// </summary>
  254. // public async Task<string> GetOrSetCallIdAsync(string callNo, CancellationToken cancellationToken)
  255. // {
  256. // var callOrder = await _callidRelationRepository.GetAsync(callNo, cancellationToken);
  257. // if (callOrder == null)
  258. // {
  259. // callOrder = new CallidRelation
  260. // {
  261. // Id = callNo,
  262. // CallId = Ulid.NewUlid().ToString(),
  263. // };
  264. // try
  265. // {
  266. // await _callidRelationRepository.AddAsync(callOrder, cancellationToken);
  267. // }
  268. // catch (Exception e)
  269. // {
  270. // _logger.LogError($"写入callidRelation失败:{e.Message}");
  271. // }
  272. // }
  273. // return callOrder.CallId;
  274. // }
  275. // /// <summary>
  276. // /// 批量获取callId
  277. // /// </summary>
  278. // public async Task<List<(string callNo, string callId)>> GetOrSetCallIdRangeAsync(List<string> callNos, CancellationToken cancellationToken)
  279. // {
  280. // var relations = await _callidRelationRepository.Queryable()
  281. // .Where(d => callNos.Contains(d.Id))
  282. // .ToListAsync(cancellationToken);
  283. //
  284. // var rsp = new List<(string callNo, string callId)>();
  285. // var newRelations = new List<CallidRelation>();
  286. // foreach (var callNo in callNos)
  287. // {
  288. // var relation = relations.FirstOrDefault(d => d.Id == callNo);
  289. // if (relation is null)
  290. // {
  291. // relation = new CallidRelation
  292. // {
  293. // Id = callNo,
  294. // CallId = Ulid.NewUlid().ToString(),
  295. // };
  296. // newRelations.Add(relation);
  297. // rsp.Add(new(relation.Id, relation.CallId));
  298. // }
  299. // else
  300. // {
  301. // rsp.Add(new(relation.Id, relation.CallId));
  302. // }
  303. // }
  304. //
  305. // await _callidRelationRepository.AddRangeAsync(newRelations, cancellationToken);
  306. // return rsp;
  307. // }
  308. //
  309. // /// <summary>
  310. // /// 查询通话记录
  311. // /// </summary>
  312. // public Task<CallNative?> GetCallAsync(string callId, CancellationToken cancellationToken)
  313. // {
  314. // if (string.IsNullOrEmpty(callId)) return null;
  315. // return _callNativeRepository.GetAsync(callId, cancellationToken);
  316. // }
  317. //
  318. // public async Task<List<CallNative>> QueryCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
  319. // {
  320. // if (string.IsNullOrEmpty(phone))
  321. // return new List<CallNative>();
  322. // return await _callNativeRepository.Queryable()
  323. // .WhereIF(direction.HasValue, d=>d.Direction == direction)
  324. // .Where(d=>d.FromNo == phone || d.ToNo == phone)
  325. // .OrderBy(d=>d.CreationTime)
  326. // .ToListAsync(cancellationToken);
  327. // }
  328. // public async Task<TrCallRecord?> GetTianrunCallAsync(string callId, CancellationToken cancellationToken)
  329. // {
  330. // throw new NotImplementedException();
  331. // }
  332. //
  333. // /// <summary>
  334. // /// 关联通话记录与order(添润)
  335. // /// </summary>
  336. // public async Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken)
  337. // {
  338. // throw new NotImplementedException();
  339. // }
  340. //
  341. // /// <summary>
  342. // /// 查询通话记录
  343. // /// </summary>
  344. // public async Task<List<TrCallRecord>> QueryTianrunCallsAsync(string phone, ECallDirection? direction, CancellationToken cancellationToken)
  345. // {
  346. // throw new NotImplementedException();
  347. // }
  348. /// <summary>
  349. /// 新增黑名单
  350. /// </summary>
  351. public override async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
  352. {
  353. throw new NotImplementedException();
  354. }
  355. /// <summary>
  356. /// 删除黑名单
  357. /// </summary>
  358. public override async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
  359. {
  360. throw new NotImplementedException();
  361. }
  362. /// <summary>
  363. /// 查询黑名单
  364. /// </summary>
  365. public override async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
  366. {
  367. throw new NotImplementedException();
  368. }
  369. /// <summary>
  370. /// 查询分机操作选项
  371. /// </summary>
  372. /// <returns></returns>
  373. public override List<Kv> GetTelOperationOptions()
  374. {
  375. var operations = XingtangSeatOperation.OperationDictionary.ToList();
  376. return operations.Select(d => new Kv(d.Key.ToString(), d.Value)).ToList();
  377. }
  378. }
  379. }