CallReportApplicationBase.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. using Hotline.Caching.Interfaces;
  2. using Hotline.Repository.SqlSugar.Extensions;
  3. using Hotline.CallCenter.Calls;
  4. using Hotline.Repository.SqlSugar.CallCenter;
  5. using Hotline.Settings;
  6. using Hotline.Share.Dtos.CallCenter;
  7. using Hotline.Share.Dtos.TrCallCenter;
  8. using Hotline.Share.Enums.CallCenter;
  9. using Hotline.Share.Requests;
  10. using SqlSugar;
  11. using XF.Domain.Exceptions;
  12. using Hotline.Orders;
  13. using Hotline.Share.Enums.User;
  14. using Hotline.Users;
  15. using XF.Domain.Repository;
  16. using Hotline.CallCenter.Tels;
  17. using Hotline.Share.Dtos;
  18. using Hotline.Share.Tools;
  19. using JiebaNet.Segmenter.Common;
  20. using XingTang.Sdk;
  21. using Mapster;
  22. using NPOI.SS.Formula.Functions;
  23. using System.Linq;
  24. namespace Hotline.Application.StatisticalReport.CallReport;
  25. public abstract class CallReportApplicationBase : ICallReportApplication
  26. {
  27. private readonly ISystemSettingCacheManager _systemSettingCacheManager;
  28. private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
  29. private readonly ICallNativeRepository _callNativeRepository;
  30. private readonly IRepository<User> _userRepository;
  31. private readonly IRepository<Work> _workRepository;
  32. private readonly IRepository<TelRest> _telRestRepository;
  33. protected CallReportApplicationBase(ISystemSettingCacheManager systemSettingCacheManager, ICallNativeRepository callNativeRepository, IRepository<User> userRepository, IRepository<Work> workRepository, IRepository<TelRest> telRestRepository, ISystemDicDataCacheManager systemDicDataCacheManager)
  34. {
  35. _systemSettingCacheManager = systemSettingCacheManager;
  36. _callNativeRepository = callNativeRepository;
  37. _userRepository = userRepository;
  38. _workRepository = workRepository;
  39. _telRestRepository = telRestRepository;
  40. _systemDicDataCacheManager = systemDicDataCacheManager;
  41. }
  42. public virtual async Task<List<CallHotLineDto>> GetCallHotLineListAsync(BiQueryGateWayDto dto, CancellationToken requestAborted)
  43. {
  44. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  45. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  46. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  47. int ringTimes = _systemSettingCacheManager.RingTimes;
  48. var hotlines = _systemDicDataCacheManager.CallForwardingSource.Select(m => m.DicDataValue).ToList();
  49. return await _callNativeRepository.GetCallHotLineListAsync(dto, noConnectByeTimes, effectiveTimes, connectByeTimes, ringTimes, hotlines);
  50. }
  51. public virtual async Task<List<TrCallHourDto>> GetCallHourListAsync(BiQueryHourCallDto dto, CancellationToken requestAborted)
  52. {
  53. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  54. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  55. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  56. return await _callNativeRepository.GetCallHourList(dto.StartTime, dto.EndTime, noConnectByeTimes, effectiveTimes, connectByeTimes, dto.Source);
  57. }
  58. public virtual async Task<TotalData<BiSeatSwitchDto>> GetCallListAsync(QueryCallListDto dto, CancellationToken requestAborted)
  59. {
  60. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  61. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  62. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  63. return await _callNativeRepository.GetCallList(dto, noConnectByeTimes, effectiveTimes, connectByeTimes);
  64. }
  65. public virtual async Task<List<QueryCallDateStatisticsDetailResp>> QueryCallDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
  66. {
  67. throw new NotImplementedException();
  68. }
  69. public virtual async Task<List<BiCallDto>> QueryCallsAsync(BiQueryCallsDto dto, CancellationToken cancellationToken)
  70. {
  71. return await _callNativeRepository.GetQueryCalls(dto.StartTime.Value, dto.EndTime.Value, dto.Line);
  72. }
  73. /// <summary>
  74. /// 话务日期明细
  75. /// </summary>
  76. /// <param name="dto"></param>
  77. /// <returns></returns>
  78. public virtual async Task<List<QueryCallsDetailDto>> QueryCallsDetailAsync(BiQueryCallsDto dto)
  79. {
  80. //超时接通量
  81. int CallInOverConnRingTime = _systemSettingCacheManager.CallInOverConnRingTime;
  82. //坐席超时挂断时间
  83. int SeatChaoTime = _systemSettingCacheManager.SeatChaoTime;
  84. //未接秒挂时间
  85. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  86. //呼入有效时间
  87. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  88. //接通秒挂时间
  89. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  90. var callData = await _callNativeRepository.Queryable()
  91. .Where(p => p.BeginIvrTime >= dto.StartTime && p.BeginIvrTime <= dto.EndTime && p.CallState != ECallState.Invalid)
  92. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.ToNo == dto.Keyword)
  93. .GroupBy(p => p.BeginIvrTime.Value.ToString("yyyy-MM-dd"))
  94. .Select(p => new QueryCallsDetailDto
  95. {
  96. Date = p.BeginIvrTime.Value.ToString("yyyy-MM-dd"),
  97. InTotal = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In, 1, 0)),//呼入总量
  98. InConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null, 1, 0)),//呼入接通量
  99. NotAcceptedHang = SqlFunc.AggregateSum(SqlFunc.IIF(p.RingDuration <= noConnectByeTimes && p.RingDuration > 0 && p.Direction == ECallDirection.In, 1, 0)), //未接通秒挂
  100. TotalDurationIncomingCalls = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null, p.Duration, 0)), //呼入总时长
  101. InAvailableAnswer = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null && p.Duration >= effectiveTimes, 1, 0)),//有效接通量
  102. InHangupImmediateWhenAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.Duration > 0 && p.Duration <= connectByeTimes, 1, 0)), //呼入接通秒挂
  103. TimeoutConnection = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null && p.RingDuration >= CallInOverConnRingTime, 1, 0)),//超时接通量
  104. TimeoutSuspension = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null && p.Duration >= SeatChaoTime, 1, 0)),//超时挂断量
  105. QueueByeCount = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.CallState == ECallState.NotAcceptedHang, 1, 0)), //队列挂断
  106. IvrByeCount = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.CallState == ECallState.IVRNoAccept, 1, 0)), //IVR挂断
  107. OutTotal = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.Out, 1, 0)),//呼出总量
  108. OutConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.Out && p.AnsweredTime != null, 1, 0))
  109. })
  110. .OrderBy(p => p.Date)
  111. .ToListAsync();
  112. return callData;
  113. }
  114. /// <summary>
  115. /// 话务日期明细-呼入总量/接通总量
  116. /// </summary>
  117. /// <param name="dto"></param>
  118. /// <returns></returns>
  119. public virtual async Task<(int, List<CallRecordOutDto>)> QueryCallsDetailInTotalAsync(BiQueryCallsDto dto, bool isAll)
  120. {
  121. var recordPrefix = _systemSettingCacheManager.RecordPrefix;
  122. var query = _callNativeRepository.Queryable(includeDeleted: true)
  123. .LeftJoin<Order>((p, o) => p.Id == o.CallId)
  124. .Where((p, o) => p.BeginIvrTime >= dto.StartTime && p.BeginIvrTime <= dto.EndTime && p.Direction == ECallDirection.In && p.CallState != ECallState.Invalid)
  125. .WhereIF(dto.TypeCode == "2", (p, o) => p.AnsweredTime != null)
  126. .WhereIF(!string.IsNullOrEmpty(dto.Keyword), (p, o) => p.TelNo == dto.Keyword)
  127. .OrderByDescending((p, o) => p.BeginIvrTime)
  128. .Select((p, o) => new CallRecordOutDto
  129. {
  130. OtherAccept = p.Id,
  131. OrderId = o.Id,
  132. OrderNo = o.No,
  133. OrderTitle = o.Title,
  134. Cdpn = p.ToNo,
  135. Cpn = p.FromNo,
  136. RecordingFileUrl = recordPrefix + p.AudioFile,
  137. RecordingFileName = p.AudioFile,
  138. RecordingBaseAddress = recordPrefix,
  139. RecordingAbsolutePath = p.AudioFile,
  140. CreatedTime = p.CreationTime
  141. }, true);
  142. if (isAll)
  143. {
  144. return (0, await query.ToListAsync());
  145. }
  146. return await query.ToPagedListAsync(dto.PageIndex, dto.PageSize);
  147. }
  148. /// <summary>
  149. /// 话务日期明细-呼入总量/接通总量
  150. /// </summary>
  151. /// <param name="dto"></param>
  152. /// <returns></returns>
  153. public virtual async Task<(int, List<CallRecordOutDto>)> QuerySeatCallsListAsync(BiQueryCallsListDto dto, bool isAll)
  154. {
  155. //超时接通量
  156. int CallInOverConnRingTime = _systemSettingCacheManager.CallInOverConnRingTime;
  157. //坐席超时挂断时间
  158. int SeatChaoTime = _systemSettingCacheManager.SeatChaoTime;
  159. //未接秒挂时间
  160. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  161. //呼入有效时间
  162. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  163. //接通秒挂时间
  164. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  165. var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi).SettingValue;
  166. var recordPrefix = _systemSettingCacheManager.RecordPrefix;
  167. var query = _callNativeRepository.Queryable(includeDeleted: true)
  168. .LeftJoin<Order>((p, o) => p.Id == o.CallId)
  169. .RightJoin<User>((p, o, u) => p.UserId == u.Id && !u.IsDeleted)
  170. .Where((p, o) => p.BeginIvrTime >= dto.StartTime && p.BeginIvrTime <= dto.EndTime && p.CallState != ECallState.Invalid)
  171. .Where((p, o, u) => u.Roles.Any(x => setting.Contains(x.Name)))
  172. .WhereIF(!string.IsNullOrEmpty(dto.UserId), (p, o) => p.UserId == dto.UserId)
  173. .WhereIF(!string.IsNullOrEmpty(dto.UserName), (p, o) => p.UserName == dto.UserName)
  174. .WhereIF(dto.FieldName == "inTotal", (p, o) => p.Direction == ECallDirection.In) //呼入总量
  175. .WhereIF(dto.FieldName == "inAnswered", (p, o) => p.Direction == ECallDirection.In && p.AnsweredTime != null) //接通总量
  176. .WhereIF(dto.FieldName == "inHangupImmediate", (p, o) => p.Direction == ECallDirection.In && p.AnsweredTime == null && p.RingDuration < noConnectByeTimes) //呼入秒挂
  177. .WhereIF(dto.FieldName == "inHanguped", (p, o) => p.Direction == ECallDirection.In && p.AnsweredTime == null && p.RingDuration >= noConnectByeTimes) //呼入超时未接
  178. .WhereIF(dto.FieldName == "inAvailableAnswer", (p, o) => p.Direction == ECallDirection.In && p.AnsweredTime != null && p.Duration >= effectiveTimes) //有效接通量
  179. .WhereIF(dto.FieldName == "inHangupImmediateWhenAnswered", (p, o) => p.Direction == ECallDirection.In && p.AnsweredTime != null && p.Duration < connectByeTimes) //接通秒挂
  180. .WhereIF(dto.FieldName == "outTotal", (p, o) => p.Direction == ECallDirection.Out) //呼出总量
  181. .WhereIF(dto.FieldName == "outAnswered", (p, o) => p.Direction == ECallDirection.Out && p.AnsweredTime != null) //呼出接通量
  182. .OrderByDescending((p, o) => p.BeginIvrTime)
  183. .Select((p, o, u) => new CallRecordOutDto
  184. {
  185. OtherAccept = p.Id,
  186. OrderId = o.Id,
  187. OrderNo = o.No,
  188. OrderTitle = o.Title,
  189. Cdpn = p.ToNo,
  190. Cpn = p.FromNo,
  191. RecordingFileUrl = recordPrefix + p.AudioFile,
  192. RecordingFileName = p.AudioFile,
  193. RecordingBaseAddress = recordPrefix,
  194. RecordingAbsolutePath = p.AudioFile,
  195. CreatedTime = p.CreationTime
  196. }, true);
  197. if (isAll)
  198. {
  199. return (0, await query.ToListAsync());
  200. }
  201. return await query.ToPagedListAsync(dto.PageIndex, dto.PageSize);
  202. }
  203. public virtual async Task<List<QueryCallsDetailStatistics>> QueryCallsDetailStatisticsAsync(StartEndTimeDto dto, CancellationToken cancellationToken)
  204. {
  205. //超时接通量
  206. int CallInOverConnRingTime = _systemSettingCacheManager.CallInOverConnRingTime;
  207. //坐席超时挂断时间
  208. int SeatChaoTime = _systemSettingCacheManager.SeatChaoTime;
  209. //未接秒挂时间
  210. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  211. //呼入有效时间
  212. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  213. //接通秒挂时间
  214. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  215. var callData = await _callNativeRepository.Queryable()
  216. .Where(p => p.BeginIvrTime >= dto.StartTime && p.BeginIvrTime <= dto.EndTime && p.CallState != ECallState.Invalid)
  217. .GroupBy(p => p.BeginIvrTime.Value.ToString("yyyy-MM-dd"))
  218. .Select(p => new QueryCallsDetailStatistics
  219. {
  220. Date = p.BeginIvrTime.Value.ToString("yyyy-MM-dd"),
  221. //InTotal = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In, 1, 0)),//呼入总量
  222. InConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.AnsweredTime != null, 1, 0)),//呼入接通量
  223. NotAcceptedHang = SqlFunc.AggregateSum(SqlFunc.IIF(p.CallState == ECallState.NotAcceptedHang && p.Direction == ECallDirection.In, 1, 0)), //呼入队列挂断
  224. InNotAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.Duration == 0 && p.TelNo != "0" && p.Direction == ECallDirection.In, 1, 0)), // 挂机量
  225. IvrByeCount = SqlFunc.AggregateSum(SqlFunc.IIF(p.Direction == ECallDirection.In && p.CallState == ECallState.IVRNoAccept && p.AnsweredTime == null, 1, 0)), //IVR挂断
  226. OutConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.AnsweredTime != null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出接通量
  227. OutNotAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(p.AnsweredTime == null && p.Direction == ECallDirection.Out, 1, 0)), // 呼出未接量
  228. })
  229. .OrderBy(p => p.Date)
  230. .ToListAsync(cancellationToken);
  231. return callData;
  232. }
  233. public virtual async Task<List<QueryCallsDetailDto>> QueryCallsHourDetailAsync(BiQueryCallsDto dto, CancellationToken cancellationToken)
  234. {
  235. //超时接通量
  236. int CallInOverConnRingTime = _systemSettingCacheManager.CallInOverConnRingTime;
  237. //坐席超时挂断时间
  238. int SeatChaoTime = _systemSettingCacheManager.SeatChaoTime;
  239. //未接秒挂时间
  240. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  241. //呼入有效时间
  242. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  243. //接通秒挂时间
  244. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  245. return await _callNativeRepository.QueryCallsHourDetail(dto.StartTime.Value, dto.EndTime.Value, noConnectByeTimes, effectiveTimes, connectByeTimes, CallInOverConnRingTime, SeatChaoTime, dto.Line);
  246. }
  247. public virtual async Task<(int, List<QueryCallsStatisticsDetailOutDto>)> QueryCallsStatisticsDetailAsync(QueryCallsStatisticsDetailInDto dto, CancellationToken cancellationToken)
  248. {
  249. dto.FieldName ??= string.Empty;
  250. dto.FieldName = dto.FieldName.ToLower();
  251. //超时接通量
  252. int CallInOverConnRingTime = _systemSettingCacheManager.CallInOverConnRingTime;
  253. //坐席超时挂断时间
  254. int SeatChaoTime = _systemSettingCacheManager.SeatChaoTime;
  255. //未接秒挂时间
  256. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  257. //呼入有效时间
  258. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  259. //接通秒挂时间
  260. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  261. var query = _callNativeRepository.Queryable(includeDeleted: true)
  262. .LeftJoin<Order>((c, o) => c.Id == o.CallId)
  263. .Where((c, o) => c.CallState != ECallState.Invalid)
  264. .WhereIF(dto.OrderNo.NotNullOrEmpty(), (c, o) => o.No == dto.OrderNo)
  265. .WhereIF(dto.FromNo.NotNullOrEmpty(), (c, o) => c.FromNo == dto.FromNo)
  266. .WhereIF(dto.ToNo.NotNullOrEmpty(), (c, o) => c.ToNo == dto.ToNo)
  267. .WhereIF(dto.TelNo.NotNullOrEmpty(), (c, o) => c.TelNo == dto.TelNo)
  268. .WhereIF(dto.EndBy.IsNotNull(), (c, o) => c.EndBy == dto.EndBy)
  269. .Where((c, o) => c.BeginIvrTime >= dto.StartTime && c.BeginIvrTime <= dto.EndTime);
  270. if (dto.FieldName == "intotal") // 呼入总量
  271. query = query.Where((c, o) => c.Direction == ECallDirection.In);
  272. if (dto.FieldName == "inconnectionquantity") // 呼入接通
  273. query = query.Where((c, o) => c.Direction == ECallDirection.In && c.AnsweredTime != null);
  274. if (dto.FieldName == "innotanswered") // 挂机量
  275. query = query.Where((c, o) => c.Direction == ECallDirection.In && c.Duration == 0 && c.TelNo != "0");
  276. if (dto.FieldName == "notacceptedhang") // 呼入队列挂断
  277. query = query.Where((c, o) => c.Duration == 0 && c.RingDuration <= noConnectByeTimes && c.RingDuration > 0 && c.Direction == ECallDirection.In);
  278. if (dto.FieldName == "ivrbyecount") // 呼入IVR挂断
  279. query = query.Where((c, o) => c.Direction == ECallDirection.In && c.BeginIvrTime.HasValue && !c.BeginQueueTime.HasValue && !c.BeginRingTime.HasValue && c.AnsweredTime == null);
  280. if (dto.FieldName == "outconnectionquantity") // 呼出接通量
  281. query = query.Where((c, o) => c.AnsweredTime != null && c.Direction == ECallDirection.Out);
  282. if (dto.FieldName == "outnotanswered") // 呼出未接通
  283. query = query.Where((c, o) => c.AnsweredTime == null && c.Direction == ECallDirection.Out);
  284. return await query
  285. .Select<QueryCallsStatisticsDetailOutDto>()
  286. .ToPagedListAsync(dto.PageIndex, dto.PageSize, cancellationToken);
  287. }
  288. public virtual Task<List<QueryEnterpriseCallDateStatisticsDetailResp>> QueryEnterpriseCallDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
  289. {
  290. throw new NotImplementedException();
  291. }
  292. public virtual Task<List<QueryPersonCallDateStatisticsDetailResp>> QueryPersonCallDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
  293. {
  294. throw new NotImplementedException();
  295. }
  296. public virtual Task<List<QueryGaoXiaoCallDateStatisticsDetailResp>> QueryGaoXiaoCallDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
  297. {
  298. throw new NotImplementedException();
  299. }
  300. /// <summary>
  301. /// 呼出话务统计明细
  302. /// </summary>
  303. /// <param name="dto"></param>
  304. /// <returns></returns>
  305. public virtual Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto, List<string> enterpriseTels)
  306. {
  307. throw new NotImplementedException();
  308. }
  309. /// <summary>
  310. /// 坐席话务统计分析
  311. /// </summary>
  312. /// <param name="dto"></param>
  313. /// <returns></returns>
  314. public virtual async Task<List<BiSeatCallsDto>> QuerySeatCallAsync(ReportRequiredPagedRequest dto, CancellationToken cancellationToken)
  315. {
  316. int noConnectByeTimes = _systemSettingCacheManager.NoConnectByeTimes;
  317. int effectiveTimes = _systemSettingCacheManager.EffectiveTimes;
  318. int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
  319. var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi).SettingValue;
  320. var list = await _userRepository.Queryable()
  321. .Includes(u => u.Roles)
  322. .LeftJoin<CallNative>((u, c) => u.Id == c.UserId)
  323. .Where((u, c) => u.Roles.Any(x => setting.Contains(x.Name)))
  324. .Where((u, c) => c.CallState != ECallState.Invalid)
  325. .Where(u => !u.IsDeleted)
  326. .Where((u, c) => c.BeginIvrTime >= dto.StartTime)
  327. .Where((u, c) => c.BeginIvrTime <= dto.EndTime)
  328. .GroupBy((u, c) => new { c.UserName, c.UserId })
  329. .Select((u, c) => new BiSeatCallsDto
  330. {
  331. Name = c.UserName,
  332. UserId = c.UserId,
  333. InTotal = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In, 1, 0)),
  334. OutTotal = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.Out, 1, 0)),
  335. InAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null, 1, 0)), // 呼入接通量
  336. OutAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.Out && c.AnsweredTime != null, 1, 0)), // 呼出接通量
  337. InHangupImmediate = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime == null && c.RingDuration < noConnectByeTimes, 1, 0)), // 呼入秒挂
  338. InHanguped = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime == null && c.RingDuration >= noConnectByeTimes, 1, 0)), //呼入未接
  339. InDurationAvg = SqlFunc.Ceil(SqlFunc.AggregateAvg(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null, c.Duration, 0))), // 呼入平均时长
  340. OutDurationAvg = SqlFunc.Ceil(SqlFunc.AggregateAvg(SqlFunc.IIF(c.Direction == ECallDirection.Out && c.AnsweredTime != null, c.Duration, 0))), // 呼出平均时长
  341. InAvailableAnswer = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null && c.Duration >= effectiveTimes, 1, 0)), // 有效接通量
  342. InHangupImmediateWhenAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null && c.Duration < connectByeTimes, 1, 0)), // 呼入接通秒挂
  343. })
  344. .MergeTable()
  345. .ToListAsync();
  346. list.ForEach(d =>
  347. {
  348. d.LoginDuration = _workRepository.Queryable().Where(q => q.UserId == d.UserId && q.CreationTime >= dto.StartTime && q.CreationTime <= dto.EndTime).Sum(q => q.WorkingDuration);
  349. if (d.LoginDuration != null)
  350. {
  351. d.LoginDuration = Math.Round(d.LoginDuration.Value, digits: 2);
  352. }
  353. d.RestDuration = _telRestRepository.Queryable().Where(q => q.UserId == d.UserId && q.CreationTime >= dto.StartTime && q.CreationTime <= dto.EndTime).Sum(q => q.RestDuration);
  354. d.RestDuration = Math.Round(d.RestDuration, digits: 2);
  355. });
  356. return list;
  357. }
  358. public virtual async Task<(int, List<BiSeatSwitchDto>)> QuerySeatSwitchAsync(QuerySeatSwitchRequest dto, bool isAll, CancellationToken cancellationToken)
  359. {
  360. var query = _callNativeRepository.Queryable()
  361. .Where(x => !string.IsNullOrEmpty(x.AgentTransferNumber) && x.CallState != ECallState.Invalid)
  362. .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.UserName.Contains(dto.UserName))
  363. .WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.ToNo.Contains(dto.CDPN))
  364. .Where(x => x.BeginIvrTime >= dto.StartTime)
  365. .Where(x => x.BeginIvrTime <= dto.EndTime)
  366. .Select(x => new BiSeatSwitchDto
  367. {
  368. UserId = x.UserId,
  369. CPN = x.FromNo,
  370. CDPN = x.ToNo,
  371. CreatedTime = x.CreationTime,
  372. TelNo = x.TelNo,
  373. UserName = x.UserName,
  374. })
  375. .OrderByDescending(x => x.CreatedTime);
  376. if (isAll)
  377. {
  378. return (0, await query.ToListAsync(cancellationToken));
  379. }
  380. return await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, cancellationToken);
  381. }
  382. public virtual Task<List<QuerySeatMonthCallResp>> QuerySeatMonthCall(QuerySeatMonthCallRequest dto)
  383. {
  384. throw new NotImplementedException();
  385. }
  386. public virtual ISugarQueryable<QuerySeatMonthCallDetailResp> QuerySeatMonthCallDetail(QuerySeatMonthCallDetailRequest dto)
  387. {
  388. throw new NotImplementedException();
  389. }
  390. }