|
@@ -45,6 +45,8 @@ using XF.Domain.Cache;
|
|
|
using Hotline.Application.CallCenter;
|
|
|
using Mapster;
|
|
|
using Tr.Sdk;
|
|
|
+using Hotline.Configurations;
|
|
|
+using Hotline.Share.Enums.Order;
|
|
|
|
|
|
namespace Hotline.Api.Controllers
|
|
|
{
|
|
@@ -77,6 +79,7 @@ namespace Hotline.Api.Controllers
|
|
|
private readonly IIPPbxApplication _iPPbxApplication;
|
|
|
private readonly ICallTelClient _callTelClient;
|
|
|
private readonly IRepository<TelOperation> _telOperationRepository;
|
|
|
+ private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
|
|
|
|
|
|
public IPPbxController(IMapper mapper, IUserDomainService userDomainService,
|
|
|
ISessionContext sessionContext, IRepository<TrCallRecord> trCallRecordRepository,
|
|
@@ -88,7 +91,15 @@ namespace Hotline.Api.Controllers
|
|
|
ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
|
|
|
IRepository<QualityTemplate> qualityTemplate,
|
|
|
ISystemSettingCacheManager systemSettingCacheManager, IRepository<TelActionRecord> telActionRecordRepository,
|
|
|
- ISystemMobilAreaApplication systemMobilAreaApplication, IRepository<Work> workRepository, Publisher publisher, ITrCallRecordRepository callRecordRepository, ITypedCache<Work> cacheWork, IIPPbxApplication iPPbxApplication, ICallTelClient callTelClient, IRepository<TelOperation> telOperationRepository)
|
|
|
+ ISystemMobilAreaApplication systemMobilAreaApplication,
|
|
|
+ IRepository<Work> workRepository,
|
|
|
+ Publisher publisher,
|
|
|
+ ITrCallRecordRepository callRecordRepository,
|
|
|
+ ITypedCache<Work> cacheWork,
|
|
|
+ IIPPbxApplication iPPbxApplication,
|
|
|
+ ICallTelClient callTelClient,
|
|
|
+ IRepository<TelOperation> telOperationRepository,
|
|
|
+ IOptionsSnapshot<AppConfiguration> appOptions)
|
|
|
{
|
|
|
_mapper = mapper;
|
|
|
_userDomainService = userDomainService;
|
|
@@ -117,6 +128,7 @@ namespace Hotline.Api.Controllers
|
|
|
_iPPbxApplication = iPPbxApplication;
|
|
|
_callTelClient = callTelClient;
|
|
|
_telOperationRepository = telOperationRepository;
|
|
|
+ _appOptions = appOptions;
|
|
|
}
|
|
|
|
|
|
#region 添添呼
|
|
@@ -131,7 +143,7 @@ namespace Hotline.Api.Controllers
|
|
|
{
|
|
|
var tels = await _callTelClient.QueryTelsAsync(new QueryTelRequest() { }, HttpContext.RequestAborted);
|
|
|
var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
|
|
|
- tels = tels.Where(m => listenTels.Contains(m.TelNo) == false).ToList();
|
|
|
+ tels = tels.Where(m => listenTels.Contains(m.TelNo) == false).ToList();
|
|
|
var returnlist = _mapper.Map<List<TrTelDto>>(tels);
|
|
|
string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
|
|
|
returnlist.ForEach(x =>
|
|
@@ -152,18 +164,18 @@ namespace Hotline.Api.Controllers
|
|
|
{
|
|
|
var tels = await _callTelClient.QueryTelStateAsync(new QueryTelStateRequest() { State = state }, HttpContext.RequestAborted);
|
|
|
var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
|
|
|
- var workList = await _workRepository.Queryable().Where(d=> 1 == 1 && !d.EndTime.HasValue).ToListAsync();
|
|
|
+ var workList = await _workRepository.Queryable().Where(d => 1 == 1 && !d.EndTime.HasValue).ToListAsync();
|
|
|
var query = from tel in tels.AgentList
|
|
|
join works in workList on tel.TelNo equals works.TelNo into workD
|
|
|
from work in workD.DefaultIfEmpty()
|
|
|
select new TrTelStateDto
|
|
|
{
|
|
|
Id = tel.Id,
|
|
|
- TelNo =tel.TelNo,
|
|
|
- ChannelUUid =tel.ChannelUUid,
|
|
|
- TelName =tel.TelName,
|
|
|
+ TelNo = tel.TelNo,
|
|
|
+ ChannelUUid = tel.ChannelUUid,
|
|
|
+ TelName = tel.TelName,
|
|
|
Type = tel.Type,
|
|
|
- Weight =tel.Weight,
|
|
|
+ Weight = tel.Weight,
|
|
|
Queue = tel.Queue,
|
|
|
State = tel.State,
|
|
|
OldState = tel.OldState,
|
|
@@ -177,14 +189,14 @@ namespace Hotline.Api.Controllers
|
|
|
OtherNumber = tel.OtherNumber,
|
|
|
GateWay = tel.GateWay,
|
|
|
AnsweredAt = tel.AnsweredAt,
|
|
|
- WorkUserId = (work != null) ? work.UserId: "",
|
|
|
- WorkUserName = (work != null) ? work.UserName: "",
|
|
|
+ WorkUserId = (work != null) ? work.UserId : "",
|
|
|
+ WorkUserName = (work != null) ? work.UserName : "",
|
|
|
};
|
|
|
//if (hasListen == false)
|
|
|
//{
|
|
|
// query = query.Where(m => listenTels.Contains(m.TelNo) == false);
|
|
|
//}
|
|
|
- var list = query.OrderBy(x=>x.TelNo).OrderByDescending(x=>x.CreatedAt).ToList();
|
|
|
+ var list = query.OrderBy(x => x.TelNo).OrderByDescending(x => x.CreatedAt).ToList();
|
|
|
return list;// _mapper.Map<IReadOnlyList<TrTelStateDto>>(tels.AgentList);
|
|
|
}
|
|
|
|
|
@@ -195,7 +207,7 @@ namespace Hotline.Api.Controllers
|
|
|
/// <returns></returns>
|
|
|
[HttpGet("query-telstatebyno")]
|
|
|
[AllowAnonymous]
|
|
|
- public async Task<TrTelStateDto> TrQueryTelStateByTelNo([FromQuery]string? telno)
|
|
|
+ public async Task<TrTelStateDto> TrQueryTelStateByTelNo([FromQuery] string? telno)
|
|
|
{
|
|
|
var tels = await _callTelClient.QueryTelStateAsync(new QueryTelStateRequest() { TelNo = telno }, HttpContext.RequestAborted);
|
|
|
|
|
@@ -290,7 +302,7 @@ namespace Hotline.Api.Controllers
|
|
|
[HttpPost("on-duty")]
|
|
|
public async Task<TrOnDutyResponseDto> OnDuty([FromBody] TrOnDutyDto dto)
|
|
|
{
|
|
|
- return await _callApplication.SignInAsync(new SignInDto() { TelNo = dto.TelNo, TelModelState = dto.TelModelState}, HttpContext.RequestAborted);
|
|
|
+ return await _callApplication.SignInAsync(new SignInDto() { TelNo = dto.TelNo, TelModelState = dto.TelModelState }, HttpContext.RequestAborted);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -323,7 +335,7 @@ namespace Hotline.Api.Controllers
|
|
|
[HttpPost("change-telmodel")]
|
|
|
public async Task ChangeTelModel([FromBody] ChangeTelModelDto dto)
|
|
|
{
|
|
|
- await _callApplication.ChangeTelModel(dto.isCallOut,HttpContext.RequestAborted);
|
|
|
+ await _callApplication.ChangeTelModel(dto.isCallOut, HttpContext.RequestAborted);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -332,9 +344,9 @@ namespace Hotline.Api.Controllers
|
|
|
/// <param name="telNo"></param>
|
|
|
/// <returns></returns>
|
|
|
[HttpGet("off-duty-manage")]
|
|
|
- public async Task OffDuty([FromQuery]string telNo)
|
|
|
+ public async Task OffDuty([FromQuery] string telNo)
|
|
|
{
|
|
|
- await _telApplication.SignOutByTelNoAsync(telNo, HttpContext.RequestAborted);
|
|
|
+ await _telApplication.SignOutByTelNoAsync(telNo, HttpContext.RequestAborted);
|
|
|
}
|
|
|
|
|
|
//提供关闭浏览器事件触发调用
|
|
@@ -379,7 +391,7 @@ namespace Hotline.Api.Controllers
|
|
|
var isResting = await _telRestRepository.IsRestingAsync(work.TelNo, HttpContext.RequestAborted);
|
|
|
if (isResting)
|
|
|
throw UserFriendlyException.SameMessage("当前坐席正在休息");
|
|
|
-
|
|
|
+
|
|
|
var user = await _userRepository.GetAsync(work.UserId, HttpContext.RequestAborted);
|
|
|
var telRest = new TelRest(work.TelNo, work.TelNo, work.UserId, work.UserName, dto.Reason, false, user.StaffNo);
|
|
|
await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
|
|
@@ -405,7 +417,7 @@ namespace Hotline.Api.Controllers
|
|
|
await _telRestRepository.UpdateAsync(telRest, HttpContext.RequestAborted);
|
|
|
|
|
|
var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, HttpContext.RequestAborted);
|
|
|
- if (telAction!=null)
|
|
|
+ if (telAction != null)
|
|
|
{
|
|
|
telAction.EndAction();
|
|
|
await _telActionRecordRepository.UpdateAsync(telAction);
|
|
@@ -481,7 +493,7 @@ namespace Hotline.Api.Controllers
|
|
|
model.RingTimes = 0;
|
|
|
model.QueueTims = 0;
|
|
|
model.OnState = Share.Enums.CallCenter.EOnState.NoOn;
|
|
|
-
|
|
|
+
|
|
|
//计算通话时长
|
|
|
if (model.AnsweredTime != null)
|
|
|
{
|
|
@@ -527,7 +539,7 @@ namespace Hotline.Api.Controllers
|
|
|
model.OperatorName = areaModel.OperatorName;
|
|
|
}
|
|
|
}
|
|
|
- catch{}
|
|
|
+ catch { }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -542,10 +554,10 @@ namespace Hotline.Api.Controllers
|
|
|
model.OperatorName = areaModel.OperatorName;
|
|
|
}
|
|
|
}
|
|
|
- catch{}
|
|
|
+ catch { }
|
|
|
}
|
|
|
//判断是否是内部通话(目前分机都为4位)
|
|
|
- if (model.CPN.Length==4 && model.CDPN.Length ==4) //是内部通话
|
|
|
+ if (model.CPN.Length == 4 && model.CDPN.Length == 4) //是内部通话
|
|
|
{
|
|
|
model.TelNo = model.CDPN;//如果是内部通话 响应分机为被叫号码
|
|
|
}
|
|
@@ -553,7 +565,7 @@ namespace Hotline.Api.Controllers
|
|
|
{
|
|
|
model.PhoneTypes = (EPhoneTypes)Convert.ToInt32(dto.phoneTypes);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
//获取关联 工单或是回访
|
|
|
//var order = await _orderRepository.GetAsync(x => x.CallId == model.CallAccept, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
|
|
@@ -573,39 +585,39 @@ namespace Hotline.Api.Controllers
|
|
|
if (teAny)
|
|
|
{
|
|
|
var quality = await _qualiteyRepository.Queryable().Where(x => x.OrderId == order.Id && x.Source == Share.Enums.Quality.EQualitySource.Accepted).FirstAsync();
|
|
|
- if (quality !=null)
|
|
|
+ if (quality != null)
|
|
|
{
|
|
|
- var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ViteRecordPrefix);
|
|
|
- //await _aiQualityService.CreateAiOrderQualityTask(quality, model, order, setting?.SettingValue[0], HttpContext.RequestAborted);
|
|
|
-
|
|
|
- try
|
|
|
- {
|
|
|
- //_aiQualityService.CreateAiOrderQualityTask(
|
|
|
- //quality,
|
|
|
- //model.RecordingAbsolutePath,
|
|
|
- //model.CPN,
|
|
|
- //model.CreatedTime,
|
|
|
- //order, setting?.SettingValue[0], HttpContext.RequestAborted);
|
|
|
- var handler = new AiQualityHandler()
|
|
|
- {
|
|
|
- Id = quality.Id,
|
|
|
- Source = quality.Source.ToString(),
|
|
|
- AudioFile = model.RecordingAbsolutePath,
|
|
|
- FromNo = model.CPN,
|
|
|
- CallStartTime = model.CreatedTime,
|
|
|
- ViteRecordPrefix = setting?.SettingValue[0],
|
|
|
- };
|
|
|
- await _publisher.PublishAsync(new AiOrderQualityNotify(handler), PublishStrategy.ParallelNoWait, HttpContext.RequestAborted);
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
|
|
|
- }
|
|
|
-
|
|
|
+ var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ViteRecordPrefix);
|
|
|
+ //await _aiQualityService.CreateAiOrderQualityTask(quality, model, order, setting?.SettingValue[0], HttpContext.RequestAborted);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //_aiQualityService.CreateAiOrderQualityTask(
|
|
|
+ //quality,
|
|
|
+ //model.RecordingAbsolutePath,
|
|
|
+ //model.CPN,
|
|
|
+ //model.CreatedTime,
|
|
|
+ //order, setting?.SettingValue[0], HttpContext.RequestAborted);
|
|
|
+ var handler = new AiQualityHandler()
|
|
|
+ {
|
|
|
+ Id = quality.Id,
|
|
|
+ Source = quality.Source.ToString(),
|
|
|
+ AudioFile = model.RecordingAbsolutePath,
|
|
|
+ FromNo = model.CPN,
|
|
|
+ CallStartTime = model.CreatedTime,
|
|
|
+ ViteRecordPrefix = setting?.SettingValue[0],
|
|
|
+ };
|
|
|
+ await _publisher.PublishAsync(new AiOrderQualityNotify(handler), PublishStrategy.ParallelNoWait, HttpContext.RequestAborted);
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- catch{}
|
|
|
+ catch { }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -632,7 +644,7 @@ namespace Hotline.Api.Controllers
|
|
|
}
|
|
|
await _trCallRecordRepository.AddAsync(model, HttpContext.RequestAborted);
|
|
|
|
|
|
-
|
|
|
+
|
|
|
var publishCallRecordDto = new PublishCallRecrodDto() { };
|
|
|
if (order != null)
|
|
|
{
|
|
@@ -706,7 +718,7 @@ namespace Hotline.Api.Controllers
|
|
|
/// <param name="dto"></param>
|
|
|
/// <returns></returns>
|
|
|
[HttpPost("calls/call-list/export")]
|
|
|
- public async Task<FileStreamResult> GetCallListExport([FromBody]ExportExcelDto<GetCallListDto> dto)
|
|
|
+ public async Task<FileStreamResult> GetCallListExport([FromBody] ExportExcelDto<GetCallListDto> dto)
|
|
|
{
|
|
|
var query = _callRecordRepository.GetCallList(dto.QueryDto);
|
|
|
List<TrCallRecord> data;
|
|
@@ -724,11 +736,11 @@ namespace Hotline.Api.Controllers
|
|
|
|
|
|
dto.ColumnInfos.ForEach(x =>
|
|
|
{
|
|
|
- if (x.Prop=="cpn")
|
|
|
+ if (x.Prop == "cpn")
|
|
|
{
|
|
|
- x.Prop ="CPN";
|
|
|
+ x.Prop = "CPN";
|
|
|
}
|
|
|
- if (x.Prop=="cdpn")
|
|
|
+ if (x.Prop == "cdpn")
|
|
|
{
|
|
|
x.Prop = "CDPN";
|
|
|
}
|
|
@@ -763,16 +775,16 @@ namespace Hotline.Api.Controllers
|
|
|
}
|
|
|
|
|
|
|
|
|
- #endregion
|
|
|
+ #endregion
|
|
|
|
|
|
- #region 关联
|
|
|
+ #region 关联
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// 可关联工单
|
|
|
- /// </summary>
|
|
|
- /// <param name="dto"></param>
|
|
|
- /// <returns></returns>
|
|
|
- [HttpGet("canlink-order")]
|
|
|
+ /// <summary>
|
|
|
+ /// 可关联工单
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="dto"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ [HttpGet("canlink-order")]
|
|
|
public async Task<PagedDto<OrderDto>> CanLinkCallRecordOrder([FromQuery] CanLinkCallRecordOrderDto dto)
|
|
|
{
|
|
|
var (total, items) = await _orderRepository.Queryable()
|
|
@@ -810,7 +822,7 @@ namespace Hotline.Api.Controllers
|
|
|
public async Task LinkCallRecord([FromBody] LinkCallRecordDto dto)
|
|
|
{
|
|
|
//var trRecord = await _trCallRecordRepository.GetAsync(x => x.CallAccept == dto.CallId, HttpContext.RequestAborted);//由CallAccept改为OtherAccept
|
|
|
-
|
|
|
+
|
|
|
if (dto.IsOrder)
|
|
|
{
|
|
|
var trRecords = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == dto.CallId).ToListAsync(HttpContext.RequestAborted);
|
|
@@ -846,7 +858,7 @@ namespace Hotline.Api.Controllers
|
|
|
trRecord.ExternalId = visit.Id;
|
|
|
await _trCallRecordRepository.UpdateAsync(trRecord, HttpContext.RequestAborted);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -863,7 +875,7 @@ namespace Hotline.Api.Controllers
|
|
|
[HttpGet("telaction-list")]
|
|
|
public async Task<PagedDto<TelActionListRep>> TelActionList([FromQuery] TelActionListDto dto)
|
|
|
{
|
|
|
- var (total,items) = await _telActionRecordRepository.Queryable()
|
|
|
+ var (total, items) = await _telActionRecordRepository.Queryable()
|
|
|
.WhereIF(string.IsNullOrEmpty(dto.TelNo) == false, x => x.TelNo.Contains(dto.TelNo))
|
|
|
.WhereIF(dto.ActionTtype != null, x => x.ActionType == dto.ActionTtype)
|
|
|
.WhereIF(string.IsNullOrEmpty(dto.UserName) == false, x => x.UserName.Contains(dto.UserName))
|
|
@@ -881,9 +893,14 @@ namespace Hotline.Api.Controllers
|
|
|
[HttpGet("telaction-basedata")]
|
|
|
public async Task<object> TelActionBaseData()
|
|
|
{
|
|
|
+ var actionType = EnumExts.GetDescriptions<EActionType>();
|
|
|
+ if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
|
|
|
+ {
|
|
|
+ actionType = actionType.Where(m => new int[] { 4, 5 }.Contains(m.Key) == false).ToList();
|
|
|
+ }
|
|
|
return new
|
|
|
{
|
|
|
- ActionType = EnumExts.GetDescriptions<EActionType>(),
|
|
|
+ ActionType = actionType,
|
|
|
};
|
|
|
}
|
|
|
#endregion
|
|
@@ -918,7 +935,7 @@ namespace Hotline.Api.Controllers
|
|
|
try
|
|
|
{
|
|
|
var list = await _workRepository.Queryable().Where(x => 1 == 1 && !x.EndTime.HasValue).ToListAsync();
|
|
|
- var tellist = await _callTelClient.QueryTelStateAsync(new QueryTelStateRequest { },HttpContext.RequestAborted);
|
|
|
+ var tellist = await _callTelClient.QueryTelStateAsync(new QueryTelStateRequest { }, HttpContext.RequestAborted);
|
|
|
foreach (var item in list)
|
|
|
{
|
|
|
var telmodel = tellist.AgentList.First(x => x.TelNo == item.TelNo);
|
|
@@ -926,7 +943,7 @@ namespace Hotline.Api.Controllers
|
|
|
{
|
|
|
if (telmodel.State == "logout")
|
|
|
{
|
|
|
- await _iPPbxApplication.ResetTelStatus(item.Id,null, HttpContext.RequestAborted);
|
|
|
+ await _iPPbxApplication.ResetTelStatus(item.Id, null, HttpContext.RequestAborted);
|
|
|
//var telRest = await _telRestRepository.GetAsync(x => x.TelNo == item.TelNo && !x.EndTime.HasValue, HttpContext.RequestAborted);
|
|
|
//if (telRest is not null)
|
|
|
//{
|