|
@@ -3,13 +3,24 @@ using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Threading.Tasks;
|
|
|
|
+using DotNetCore.CAP;
|
|
using Hotline.Caching.Interfaces;
|
|
using Hotline.Caching.Interfaces;
|
|
|
|
+using Hotline.Caching.Services;
|
|
using Hotline.CallCenter.BlackLists;
|
|
using Hotline.CallCenter.BlackLists;
|
|
|
|
+using Hotline.CallCenter.Calls;
|
|
using Hotline.CallCenter.Tels;
|
|
using Hotline.CallCenter.Tels;
|
|
|
|
+using Hotline.Orders;
|
|
using Hotline.Repository.SqlSugar.CallCenter;
|
|
using Hotline.Repository.SqlSugar.CallCenter;
|
|
|
|
+using Hotline.Repository.SqlSugar.Extensions;
|
|
|
|
+using Hotline.Repository.SqlSugar.Orders;
|
|
|
|
+using Hotline.Settings;
|
|
using Hotline.Share.Dtos.CallCenter;
|
|
using Hotline.Share.Dtos.CallCenter;
|
|
|
|
+using Hotline.Share.Dtos.Order;
|
|
using Hotline.Share.Dtos.TrCallCenter;
|
|
using Hotline.Share.Dtos.TrCallCenter;
|
|
|
|
+using Hotline.Share.Enums.CallCenter;
|
|
using Hotline.Users;
|
|
using Hotline.Users;
|
|
|
|
+using MapsterMapper;
|
|
|
|
+using Microsoft.AspNetCore.Http;
|
|
using XF.Domain.Authentications;
|
|
using XF.Domain.Authentications;
|
|
using XF.Domain.Cache;
|
|
using XF.Domain.Cache;
|
|
using XF.Domain.Exceptions;
|
|
using XF.Domain.Exceptions;
|
|
@@ -23,28 +34,49 @@ namespace Hotline.Application.CallCenter
|
|
private readonly IRepository<TelGroup> _telGroupRepository;
|
|
private readonly IRepository<TelGroup> _telGroupRepository;
|
|
private readonly IWorkRepository _workRepository;
|
|
private readonly IWorkRepository _workRepository;
|
|
private readonly ITelRestRepository _telRestRepository;
|
|
private readonly ITelRestRepository _telRestRepository;
|
|
|
|
+ private readonly IRepository<CallNative> _callNativeRepository;
|
|
|
|
+ private readonly IOrderRepository _orderRepository;
|
|
|
|
+ private readonly IRepository<OrderVisit> _orderVisitRepository;
|
|
private readonly ITypedCache<Work> _cacheWork;
|
|
private readonly ITypedCache<Work> _cacheWork;
|
|
private readonly IUserCacheManager _userCacheManager;
|
|
private readonly IUserCacheManager _userCacheManager;
|
|
|
|
+ private readonly ISystemSettingCacheManager _systemSettingCacheManager;
|
|
|
|
+ private readonly ICapPublisher _capPublisher;
|
|
private readonly ISessionContext _sessionContext;
|
|
private readonly ISessionContext _sessionContext;
|
|
|
|
+ private readonly IMapper _mapper;
|
|
|
|
|
|
public XingTangCallApplication(
|
|
public XingTangCallApplication(
|
|
IRepository<Tel> telRepository,
|
|
IRepository<Tel> telRepository,
|
|
IRepository<TelGroup> telGroupRepository,
|
|
IRepository<TelGroup> telGroupRepository,
|
|
IWorkRepository workRepository,
|
|
IWorkRepository workRepository,
|
|
ITelRestRepository telRestRepository,
|
|
ITelRestRepository telRestRepository,
|
|
|
|
+ IRepository<CallNative> callNativeRepository,
|
|
|
|
+ IOrderRepository orderRepository,
|
|
|
|
+ IRepository<OrderVisit> orderVisitRepository,
|
|
ITypedCache<Work> cacheWork,
|
|
ITypedCache<Work> cacheWork,
|
|
IUserCacheManager userCacheManager,
|
|
IUserCacheManager userCacheManager,
|
|
- ISessionContext sessionContext)
|
|
|
|
|
|
+ ISystemSettingCacheManager systemSettingCacheManager,
|
|
|
|
+ ICapPublisher capPublisher,
|
|
|
|
+ ISessionContext sessionContext,
|
|
|
|
+ IMapper mapper)
|
|
{
|
|
{
|
|
_telRepository = telRepository;
|
|
_telRepository = telRepository;
|
|
_telGroupRepository = telGroupRepository;
|
|
_telGroupRepository = telGroupRepository;
|
|
_workRepository = workRepository;
|
|
_workRepository = workRepository;
|
|
_telRestRepository = telRestRepository;
|
|
_telRestRepository = telRestRepository;
|
|
|
|
+ _callNativeRepository = callNativeRepository;
|
|
|
|
+ _orderRepository = orderRepository;
|
|
|
|
+ _orderVisitRepository = orderVisitRepository;
|
|
_cacheWork = cacheWork;
|
|
_cacheWork = cacheWork;
|
|
_userCacheManager = userCacheManager;
|
|
_userCacheManager = userCacheManager;
|
|
|
|
+ _systemSettingCacheManager = systemSettingCacheManager;
|
|
|
|
+ _capPublisher = capPublisher;
|
|
_sessionContext = sessionContext;
|
|
_sessionContext = sessionContext;
|
|
|
|
+ _mapper = mapper;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 查询分机
|
|
|
|
+ /// </summary>
|
|
public async Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
|
|
public async Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
return await _telRepository.Queryable()
|
|
return await _telRepository.Queryable()
|
|
@@ -52,6 +84,9 @@ namespace Hotline.Application.CallCenter
|
|
.ToListAsync(cancellationToken);
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 查询分机组
|
|
|
|
+ /// </summary>
|
|
public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
|
|
public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
return await _telGroupRepository.Queryable()
|
|
return await _telGroupRepository.Queryable()
|
|
@@ -59,21 +94,24 @@ namespace Hotline.Application.CallCenter
|
|
.ToListAsync(cancellationToken);
|
|
.ToListAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
|
|
- public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
|
|
|
|
|
|
+ public async Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
throw new NotImplementedException();
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
|
|
- public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
|
|
|
|
|
|
+ public async Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
throw new NotImplementedException();
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
|
|
- public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
|
|
|
|
|
|
+ public async Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
throw new NotImplementedException();
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 签入
|
|
|
|
+ /// </summary>
|
|
public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
|
|
public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
if (string.IsNullOrEmpty(dto.TelNo))
|
|
if (string.IsNullOrEmpty(dto.TelNo))
|
|
@@ -107,6 +145,9 @@ namespace Hotline.Application.CallCenter
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 签出
|
|
|
|
+ /// </summary>
|
|
public async Task SingOutAsync(CancellationToken cancellationToken)
|
|
public async Task SingOutAsync(CancellationToken cancellationToken)
|
|
{
|
|
{
|
|
var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
|
|
var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
|
|
@@ -121,8 +162,106 @@ namespace Hotline.Application.CallCenter
|
|
|
|
|
|
work.OffDuty();
|
|
work.OffDuty();
|
|
await _workRepository.UpdateAsync(work, cancellationToken);
|
|
await _workRepository.UpdateAsync(work, cancellationToken);
|
|
- _cacheWork.Remove(work.GetKey(KeyMode.UserId));
|
|
|
|
- _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
|
|
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 查询当前用户的分机状态
|
|
|
|
+ /// </summary>
|
|
|
|
+ /// <param name="cancellationToken"></param>
|
|
|
|
+ /// <returns></returns>
|
|
|
|
+ public async Task<TrOnDutyResponseDto> 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,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 定量查询通话记录
|
|
|
|
+ /// </summary>
|
|
|
|
+ public async Task<IReadOnlyList<CallNativeDto>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
|
|
|
|
+ {
|
|
|
|
+ var count = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount).SettingValue[0]);
|
|
|
|
+ return await _callNativeRepository.Queryable()
|
|
|
|
+ .LeftJoin<Order>((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.FromNo == dto.ToNo)
|
|
|
|
+ .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.FromNo == dto.UserName)
|
|
|
|
+ .WhereIF(!string.IsNullOrEmpty(dto.TelNo), d => d.FromNo == dto.TelNo)
|
|
|
|
+ .WhereIF(dto.HangupBy != null, d => d.HangupBy == dto.HangupBy)
|
|
|
|
+ .WhereIF(dto.CallStartTimeBT != null, d => d.BeginIvrTime >= dto.CallStartTimeBT)
|
|
|
|
+ .WhereIF(dto.CallStartTimeLT != null, d => d.BeginIvrTime <= dto.CallStartTimeLT)
|
|
|
|
+ .WhereIF(dto.IsConnected != null, d => d.AnsweredTime != null)
|
|
|
|
+ .WhereIF(dto.Direction != null, d => d.Direction == dto.Direction)
|
|
|
|
+ .Select((d, o) => new CallNativeDto
|
|
|
|
+ {
|
|
|
|
+ OrderId = o.Id,
|
|
|
|
+ OrderNo = o.No,
|
|
|
|
+ Title = o.Title,
|
|
|
|
+ }, true)
|
|
|
|
+ .ToFixedListAsync(dto, count, cancellationToken);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// 关联通话记录与工单或回访
|
|
|
|
+ /// </summary>
|
|
|
|
+ public async Task RelateCallToOrderAsync(LinkCallRecordDto dto, CancellationToken cancellationToken)
|
|
|
|
+ {
|
|
|
|
+ var call = await _callNativeRepository.GetAsync(d => d.CallNo == dto.CallId, cancellationToken);
|
|
|
|
+ if (call is null) throw UserFriendlyException.SameMessage("无效通话记录编号");
|
|
|
|
+ if (dto.IsOrder)
|
|
|
|
+ {
|
|
|
|
+ //工单
|
|
|
|
+ var order = await _orderRepository.GetAsync(x => x.Id == dto.Id, cancellationToken);
|
|
|
|
+ if (order is null) throw UserFriendlyException.SameMessage("无效工单编号");
|
|
|
|
+ if (!string.IsNullOrEmpty(order.CallId))
|
|
|
|
+ throw UserFriendlyException.SameMessage("通话记录已经关联工单");
|
|
|
|
+
|
|
|
|
+ order.CallId = dto.CallId;
|
|
|
|
+ order.FromPhone = call.FromNo;
|
|
|
|
+ order.TransferPhone = call.ToNo;
|
|
|
|
+ await _orderRepository.UpdateAsync(order, cancellationToken);
|
|
|
|
+
|
|
|
|
+ //推省上
|
|
|
|
+ await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallConnectWithOrder,
|
|
|
|
+ new PublishCallRecrodDto() {
|
|
|
|
+ Order = _mapper.Map<OrderDto>(order),
|
|
|
|
+ TrCallRecordDto = _mapper.Map<TrCallDto>(call) });
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ //回访
|
|
|
|
+ var visit = await _orderVisitRepository.GetAsync(x => x.Id == dto.Id, cancellationToken);
|
|
|
|
+ if (visit is null) throw UserFriendlyException.SameMessage("无效回访记录编号");
|
|
|
|
+ visit.CallId = dto.CallId;
|
|
|
|
+ await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|