using Hotline.Caching.Interfaces; using Hotline.CallCenter.BlackLists; using Hotline.CallCenter.Calls; using Hotline.CallCenter.Tels; using Hotline.Orders; using Hotline.Repository.SqlSugar.Extensions; using Hotline.Share.Dtos.CallCenter; using Hotline.Share.Dtos.TrCallCenter; using Hotline.Share.Enums.CallCenter; using Hotline.Users; using MapsterMapper; using Microsoft.Extensions.Logging; using XF.Domain.Authentications; using XF.Domain.Cache; using XF.Domain.Exceptions; using XF.Domain.Repository; namespace Hotline.Application.CallCenter; public abstract class DefaultCallApplication : ICallApplication { private readonly IRepository _telRepository; private readonly IRepository _telGroupRepository; private readonly IWorkRepository _workRepository; private readonly ITelRestRepository _telRestRepository; private readonly IRepository _callNativeRepository; private readonly IRepository _telOperationRepository; private readonly IRepository _callIdRelationRepository; private readonly ITypedCache _cacheWork; private readonly IUserCacheManager _userCacheManager; private readonly ISessionContext _sessionContext; private readonly IMapper _mapper; private readonly ILogger _logger; public DefaultCallApplication( IRepository telRepository, IRepository telGroupRepository, IWorkRepository workRepository, ITelRestRepository telRestRepository, IRepository callNativeRepository, IRepository telOperationRepository, IRepository callIdRelationRepository, ITypedCache cacheWork, IUserCacheManager userCacheManager, ISessionContext sessionContext, IMapper mapper, ILogger logger) { _telRepository = telRepository; _telGroupRepository = telGroupRepository; _workRepository = workRepository; _telRestRepository = telRestRepository; _callNativeRepository = callNativeRepository; _telOperationRepository = telOperationRepository; _callIdRelationRepository = callIdRelationRepository; _cacheWork = cacheWork; _userCacheManager = userCacheManager; _sessionContext = sessionContext; _mapper = mapper; _logger = logger; } public DefaultCallApplication() { } /// /// 查询分机 /// public async Task> QueryTelsAsync(CancellationToken cancellationToken) { return await _telRepository.Queryable() .Select() .ToListAsync(cancellationToken); } /// /// 查询分机组 /// public async Task> QueryTelGroupsAsync(CancellationToken cancellationToken) { return await _telGroupRepository.Queryable() .Select() .ToListAsync(cancellationToken); } /// /// 新增黑名单 /// public abstract Task AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken); /// /// 删除黑名单 /// public abstract Task RemoveBlackListAsync(string id, CancellationToken cancellationToken); /// /// 查询黑名单 /// public abstract Task> QueryBlackListsAsync(CancellationToken cancellationToken); /// /// 签入 /// public async Task SignInAsync(SignInDto dto, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(dto.TelNo)) throw UserFriendlyException.SameMessage("无效分机号"); var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId); if (work is not null) { //if (work.TelNo != dto.TelNo) //{ // throw UserFriendlyException.SameMessage("当前用户已签入其他分机"); //} throw UserFriendlyException.SameMessage("当前用户已签入"); } var telWork = _userCacheManager.GetWorkByTelNoExp(dto.TelNo); if (telWork is not null) { throw UserFriendlyException.SameMessage("当前分机已被占用"); } work = new Work(_sessionContext.RequiredUserId, _sessionContext.UserName, dto.TelNo, dto.TelNo, null, null, dto.GroupId, _sessionContext.StaffNo, null); await _workRepository.AddAsync(work, cancellationToken); return new TrOnDutyResponseDto { TelNo = dto.TelNo, QueueId = dto.GroupId, StartTime = work.StartTime, }; } /// /// 签出 /// public async Task SingOutAsync(CancellationToken cancellationToken) { var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId); if (work is null) return; var telRest = await _telRestRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, cancellationToken); if (telRest is not null) { telRest.EndRest(); await _telRestRepository.UpdateAsync(telRest, cancellationToken); } work.OffDuty(); await _workRepository.UpdateAsync(work, cancellationToken); await _cacheWork.RemoveAsync(work.GetKey(KeyMode.UserId), cancellationToken); await _cacheWork.RemoveAsync(work.GetKey(KeyMode.TelNo), cancellationToken); } /// /// 签出 /// public async Task SingOutAsync(string telNo, CancellationToken cancellationToken) { var work = _userCacheManager.GetWorkByTelNoExp(telNo); if (work is null) return; var telRest = await _telRestRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, cancellationToken); if (telRest is not null) { telRest.EndRest(); await _telRestRepository.UpdateAsync(telRest, cancellationToken); } work.OffDuty(); await _workRepository.UpdateAsync(work, cancellationToken); await _cacheWork.RemoveAsync(work.GetKey(KeyMode.UserId), cancellationToken); await _cacheWork.RemoveAsync(work.GetKey(KeyMode.TelNo), cancellationToken); } /// /// 查询当前用户的分机状态 /// /// /// public async Task GetTelStateAsync(CancellationToken cancellationToken) { var work = _userCacheManager.GetWorkByUserNoExp(_sessionContext.RequiredUserId); if (work is null) return null; return await Task.FromResult(new TrOnDutyResponseDto { TelNo = work.TelNo, QueueId = work.QueueId, StartTime = work.StartTime, StaffNo = work.StaffNo }); } /// /// 定量查询通话记录 /// public async Task> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken) { return await _callNativeRepository.Queryable(includeDeleted: true) .LeftJoin((d, o) => d.CallNo == o.CallId) .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), (d, o) => o.No == dto.OrderNo) .WhereIF(!string.IsNullOrEmpty(dto.FromNo), d => d.FromNo == dto.FromNo) .WhereIF(!string.IsNullOrEmpty(dto.ToNo), d => d.ToNo == dto.ToNo) .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName) .WhereIF(!string.IsNullOrEmpty(dto.TelNo), d => d.TelNo == dto.TelNo) .WhereIF(dto.EndBy != null, d => d.EndBy == dto.EndBy) .WhereIF(dto.CallStartTimeStart != null, d => d.BeginIvrTime >= dto.CallStartTimeStart) .WhereIF(dto.CallStartTimeEnd != null, d => d.BeginIvrTime <= dto.CallStartTimeEnd) .WhereIF(dto.IsConnected != null, d => d.AnsweredTime != null) .WhereIF(dto.Direction != null, d => d.Direction == dto.Direction) .WhereIF(dto.WaitDurationStart != null && dto.WaitDurationStart > 0, d => d.WaitDuration >= dto.WaitDurationStart) .WhereIF(dto.WaitDurationEnd != null && dto.WaitDurationEnd > 0, d => d.WaitDuration <= dto.WaitDurationEnd) .Select((d, o) => new CallNativeDto { OrderId = o.Id, OrderNo = o.No, Title = o.Title, }, true) .ToFixedListAsync(dto, cancellationToken); } /// /// 查询分机操作记录(定量) /// public async Task> QueryTelOperationsAsync(QueryTelOperationsFixedDto dto, CancellationToken cancellationToken) { return await _telOperationRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName) .WhereIF(!string.IsNullOrEmpty(dto.StaffNo), d => d.StaffNo == dto.StaffNo) .WhereIF(!string.IsNullOrEmpty(dto.GroupId), d => d.GroupId == dto.GroupId) .WhereIF(dto.OperateState != null, d => d.OperateState == dto.OperateState) .ToFixedListAsync(dto, cancellationToken); } /// /// 依据通话记录编号获取映射后的callId /// public async Task GetOrSetCallIdAsync(string callNo, CancellationToken cancellationToken) { var callOrder = await _callIdRelationRepository.GetAsync(callNo, cancellationToken); if (callOrder == null) { callOrder = new CallidRelation { Id = callNo, CallId = Ulid.NewUlid().ToString(), }; try { await _callIdRelationRepository.AddAsync(callOrder, cancellationToken); } catch (Exception e) { _logger.LogError($"写入callidRelation失败:{e.Message}"); } } return callOrder.CallId; } /// /// 批量获取callId /// public async Task> GetOrSetCallIdRangeAsync(List callNos, CancellationToken cancellationToken) { var relations = await _callIdRelationRepository.Queryable() .Where(d => callNos.Contains(d.Id)) .ToListAsync(cancellationToken); var rsp = new List<(string callNo, string callId)>(); var newRelations = new List(); foreach (var callNo in callNos) { var relation = relations.FirstOrDefault(d => d.Id == callNo); if (relation is null) { 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; } /// /// 查询通话记录 /// public Task GetCallAsync(string callId, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(callId)) return null; return _callNativeRepository.GetAsync(callId, cancellationToken); } /// /// 查询通话记录 /// public async Task> QueryCallsAsync( string? phone, ECallDirection? direction, DateTime? callStartTimeStart, DateTime? callStartTimeEnd, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(phone)) return new List(); return await _callNativeRepository.Queryable() .WhereIF(direction.HasValue, d => d.Direction == direction) .WhereIF(callStartTimeStart != null, d => d.BeginIvrTime >= callStartTimeStart) .WhereIF(callStartTimeEnd != null, d => d.BeginIvrTime <= callStartTimeEnd) .Where(d => d.FromNo == phone || d.ToNo == phone) .OrderBy(d => d.CreationTime) .ToListAsync(cancellationToken); } #region tianrun 临时方案 public Task GetTianrunCallAsync(string callId, CancellationToken cancellationToken) { throw new NotImplementedException(); } /// /// 关联通话记录与order(添润) /// public Task RelateTianrunCallWithOrderAsync(string callId, string orderId, CancellationToken cancellationToken) { throw new NotImplementedException(); } /// /// 查询通话记录 /// public Task> QueryTianrunCallsAsync( string? phone = null, ECallDirection? direction = null, DateTime? callStartTimeStart = null, DateTime? callStartTimeEnd = null, CancellationToken cancellationToken = default) { throw new NotImplementedException(); } #endregion }