1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- using Hotline.Application.FlowEngine;
- using Hotline.Caching.Interfaces;
- using Hotline.CallCenter.Calls;
- using Hotline.CallCenter.Devices;
- using Hotline.CallCenter.Ivrs;
- using Hotline.CallCenter.Tels;
- using Hotline.FlowEngine.WfModules;
- using Hotline.Permissions;
- using Hotline.Settings;
- using Hotline.Share.Dtos.CallCenter;
- using Hotline.Share.Dtos.FlowEngine;
- using Hotline.Share.Dtos.Trunk;
- using Hotline.Share.Enums.CallCenter;
- using Hotline.Share.Requests;
- using Hotline.Users;
- using MapsterMapper;
- using Microsoft.AspNetCore.Mvc;
- using SqlSugar;
- using Wex.Sdk;
- using Wex.Sdk.Tel;
- using XF.Domain.Authentications;
- using XF.Domain.Cache;
- using XF.Domain.Constants;
- using XF.Domain.Exceptions;
- using XF.Utility.EnumExtensions;
- using System.Linq;
- using Hotline.Share.Dtos;
- using Microsoft.AspNetCore.Authorization;
- namespace Hotline.Api.Controllers
- {
- /// <summary>
- /// 话机设备管理
- /// </summary>
- public class PbxController : BaseController
- {
- private readonly ITelRepository _telRepository;
- private readonly ITelRestRepository _telRestRepository;
- private readonly ITelDomainService _telDomainService;
- private readonly ITypedCache<Tel> _cacheTel;
- private readonly ITypedCache<TelGroup> _cacheTelGroup;
- private readonly ITelGroupRepository _telGroupRepository;
- private readonly IMapper _mapper;
- private readonly IWorkRepository _workRepository;
- private readonly IDeviceManager _deviceManager;
- private readonly IUserCacheManager _userCacheManager;
- private readonly ISessionContext _sessionContext;
- private readonly ICallRepository _callRepository;
- private readonly ITrunkIvrManagerRepository _trunkIvrManagerRepository;
- private readonly IIvrCategoryRepository _ivrCategoryRepository;
- private readonly IWorkflowApplication _workflowApplication;
- private readonly ISystemSettingCacheManager _systemSettingCacheManager;
- private readonly IIvrDomainService _ivrDomainService;
- private readonly IIvrCacheManager _ivrCacheManager;
- private readonly ILogger<TelController> _logger;
- private readonly ICallDetailRepository _callDetailRepository;
- private readonly IUserRepository _userRepository;
- private readonly IWexClient _wexClient;
- private readonly IWexTelGroupRepository _wexTelGroupRepository;
- public PbxController(
- ITelRepository telRepository,
- ITelRestRepository telRestRepository,
- ITelDomainService telDomainService,
- ITypedCache<Tel> cacheTel,
- ITypedCache<TelGroup> cacheTelGroup,
- ITelGroupRepository telGroupRepository,
- IMapper mapper,
- IWorkRepository workRepository,
- IDeviceManager deviceManager,
- IUserCacheManager userCacheManager,
- ISessionContext sessionContext,
- ICallRepository callRepository,
- ITrunkIvrManagerRepository trunkIvrManagerRepository,
- IIvrCategoryRepository ivrCategoryRepository,
- IWorkflowApplication workflowApplication,
- ISystemSettingCacheManager systemSettingCacheManager,
- IIvrDomainService ivrDomainService,
- IIvrCacheManager ivrCacheManager,
- ILogger<TelController> logger,
- ICallDetailRepository callDetailRepository,
- IUserRepository userRepository,
- IWexClient wexClient,
- IWexTelGroupRepository wexTelGroupRepository)
- {
- _telRepository = telRepository;
- _telRestRepository = telRestRepository;
- _telDomainService = telDomainService;
- _cacheTel = cacheTel;
- _cacheTelGroup = cacheTelGroup;
- _telGroupRepository = telGroupRepository;
- _mapper = mapper;
- _workRepository = workRepository;
- _deviceManager = deviceManager;
- _userCacheManager = userCacheManager;
- _sessionContext = sessionContext;
- _callRepository = callRepository;
- _trunkIvrManagerRepository = trunkIvrManagerRepository;
- _ivrCategoryRepository = ivrCategoryRepository;
- _workflowApplication = workflowApplication;
- _systemSettingCacheManager = systemSettingCacheManager;
- _ivrDomainService = ivrDomainService;
- _ivrCacheManager = ivrCacheManager;
- _logger = logger;
- _callDetailRepository = callDetailRepository;
- _userRepository = userRepository;
- _wexClient = wexClient;
- _wexTelGroupRepository = wexTelGroupRepository;
- }
- #region 话机
- /// <summary>
- /// 根据设备自动同步分机数据到数据库
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.SyncTelsAsync)]
- [HttpPut("sync-tels")]
- public async Task SyncTelsAsync()
- {
- var dbTels = await _telRepository.QueryAsync();
- foreach (var dbTel in dbTels)
- {
- _cacheTel.Remove(dbTel.No);
- }
- //await _telRepository.RemoveRangeAsync(dbTels);
- var tels = await _telDomainService.QueryTelsAsync(HttpContext.RequestAborted);
- var list = tels.ExceptBy(dbTels.Select(e => e.No), x => x.No).ToList();
- var delList = dbTels.ExceptBy(tels.Select(e => e.No), x => x.No).ToList();
- for (int i = 0; i < delList.Count; i++)
- {
- delList[i].SoftDelete();
- }
- await _telRepository.UpdateRangeAsync(delList);
- await _telRepository.AddRangeAsync(list);
- }
- /// <summary>
- /// 查询所有分机
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.QueryTels)]
- [HttpGet("query-tels")]
- public async Task<IReadOnlyList<TelDto>> QueryTels()
- {
- var tels = await _telRepository.QueryExtAsync(d => true, d => d.Includes(x => x.Groups));
- return _mapper.Map<IReadOnlyList<TelDto>>(tels);
- }
- #endregion
- #region 分机组
- /// <summary>
- /// 页面基础信息
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.GetBaseInfoGroup)]
- [HttpGet("base-info-group")]
- public async Task<dynamic> GetBaseInfoGroup()
- {
- return new
- {
- Distributions = EnumExts.GetDescriptions<EDistribution>()
- };
- }
- /// <summary>
- /// 查询所有分机组
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.QueryTelGroups)]
- [HttpGet("query-telgroups")]
- public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroups()
- {
- var groups = await _telGroupRepository.QueryExtAsync(d => true, d => d.Includes(x => x.Tels));
- return _mapper.Map<IReadOnlyList<TelGroupDto>>(groups);
- }
- /// <summary>
- /// 新增分机组
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.AddTelGroup)]
- [HttpPost("add-telgroup")]
- public async Task AddTelGroup([FromBody] AddTelGroupDto dto)
- {
- var works = await _workRepository.QueryAsync(d => dto.TelNos.Contains(d.TelNo) && !d.EndTime.HasValue);
- await _deviceManager.AssginConfigGroupAsync(
- dto.No,
- dto.Distribution,
- ext: works.Select(d => d.TelNo).ToList(),
- voiceFile: dto.Voice ?? null,
- cancellationToken: HttpContext.RequestAborted);
- var group = _mapper.Map<TelGroup>(dto);
- var tels = await _telRepository.QueryAsync(d => dto.TelNos.Contains(d.No));
- group.Tels = tels;
- await _telGroupRepository.AddNavTelsAsync(group, HttpContext.RequestAborted);
- _cacheTelGroup.Remove(dto.No);
- }
- /// <summary>
- /// 更新分机组
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.UpdateTelGroup)]
- [HttpPut("update-telgroup")]
- public async Task UpdateTelGroup([FromBody] UpdateTelGroupDto dto)
- {
- var works = await _workRepository.QueryAsync(d => dto.TelNos.Contains(d.TelNo) && !d.EndTime.HasValue);
- await _deviceManager.AssginConfigGroupAsync(
- dto.No,
- dto.Distribution,
- ext: works.Select(d => d.TelNo).ToList(),
- voiceFile: dto.Voice ?? null,
- cancellationToken: HttpContext.RequestAborted);
- var group = _mapper.Map<TelGroup>(dto);
- var tels = await _telRepository.QueryAsync(d => dto.TelNos.Contains(d.No));
- group.Tels = tels;
- await _telGroupRepository.UpdateNavTelsAsync(group, HttpContext.RequestAborted);
- _cacheTelGroup.Remove(dto.No);
- }
- #endregion
- #region 话机设备操作
- /// <summary>
- /// 查询小修流程开启参数
- /// </summary>
- /// <returns></returns>
- [HttpGet("flow-start")]
- public async Task<DefinedNextStepsDto> GetFlowStartOptionsAsync()
- {
- return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.TelRestApply,
- HttpContext.RequestAborted);
- }
- /// <summary>
- /// 分机休息
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.Rest)]
- [HttpPost("rest")]
- public async Task Rest([FromBody] StartRestDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- bool isCanApply = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.RestApproval).SettingValue[0]);
- if (isCanApply)
- {
- var isApply = await _telRepository.IsApplyingAsync(work.TelNo, HttpContext.RequestAborted);
- if (isApply)
- throw new UserFriendlyException("分机休息申请正在审核阶段");
- }
- var isResting = await _telRepository.IsRestingAsync(work.TelNo, HttpContext.RequestAborted);
- if (isResting)
- throw new UserFriendlyException("当前坐席正在休息");
- var user = _userRepository.Get(work.UserId);
- var telRest = new TelRest(work.TelId, work.TelNo, work.UserId, work.UserName, dto.Reason, isCanApply,user.StaffNo);
- await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
- if (!isCanApply)
- {
- await _telDomainService.TelRestApplyPassAsync(telRest.Id, HttpContext.RequestAborted);
- }
- else
- {
- var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
- startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
- startWorkflowDto.Title = dto.Reason;
- await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, HttpContext.RequestAborted);
- }
- }
- #region 威尔信
- /// <summary>
- /// 分机休息流程开始
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.Rest)]
- [HttpPost("rest-flow")]
- public async Task RestFlow([FromBody] StartRestDto dto)
- {
- var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo },HttpContext.RequestAborted);
- if (tel.Data == null || tel.Data.Count == 0)
- throw UserFriendlyException.SameMessage("未找到分机信息");
- if (tel.Data[0].Sigin == 0)
- throw UserFriendlyException.SameMessage("分机未签入,不能休息");
- var isApply = await _telRepository.IsApplyingAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
- if (isApply)
- throw UserFriendlyException.SameMessage("分机休息申请正在审核阶段");
- var isResting = await _telRepository.IsRestingAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
- if (isResting)
- throw new UserFriendlyException("当前坐席正在休息");
- var telRest = new TelRest(tel.Data[0].TelNo, tel.Data[0].TelNo, _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, true, _sessionContext.StaffNo);
- await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
- var startWorkflowDto = _mapper.Map<StartWorkflowDto>(dto);
- startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
- startWorkflowDto.Title = dto.Reason;
- await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 开始分机休息
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- [Permission(EPermission.Rest)]
- [HttpGet("begin-rest")]
- public async Task BeginRest()
- {
- var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
- if (tel.Data == null || tel.Data.Count == 0)
- throw UserFriendlyException.SameMessage("未找到分机信息");
- if (tel.Data[0].Sigin == 0)
- throw UserFriendlyException.SameMessage("分机未签入,不能休息");
- var telRest = await _telRestRepository.GetAsync(x => !x.EndTime.HasValue && !x.StartTime.HasValue && x.TelNo == tel.Data[0].TelNo, HttpContext.RequestAborted);
- if (telRest == null)
- throw new UserFriendlyException($"错误");
- //if (string.IsNullOrEmpty(id))
- // throw UserFriendlyException.SameMessage("无效分机休息编号");
- //var telRest = await _telRestRepository.GetAsync(id, HttpContext.RequestAborted);
- //if (telRest == null)
- // throw new UserFriendlyException($"无效分机休息编号, telRestId: {id}", "无效分机休息编号");
- telRest.ApplyStatus = ETelRestApplyStatus.Resting;
- telRest.StartTime = DateTime.Now;
- await _telRestRepository.UpdateAsync(telRest, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 分机休息
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.Rest)]
- [HttpPost("rest-add")]
- public async Task Rest([FromBody] ResstDto dto)
- {
- var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
- if (tel.Data == null || tel.Data.Count == 0)
- throw UserFriendlyException.SameMessage("未找到分机信息");
- if (tel.Data[0].Sigin == 0)
- throw UserFriendlyException.SameMessage("分机未签入,不能休息");
- var telRest = new TelRest(tel.Data[0].TelNo, tel.Data[0].TelNo, _sessionContext.RequiredUserId, _sessionContext.UserName, dto.Reason, false, _sessionContext.StaffNo);
- await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 删除分机休息
- /// </summary>
- /// <returns></returns>
- /// <exception cref="UserFriendlyException"></exception>
- [Permission(EPermission.Rest)]
- [HttpGet("rest-del")]
- public async Task DelRest()
- {
- var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
- if (tel.Data == null || tel.Data.Count == 0)
- throw UserFriendlyException.SameMessage("未找到分机信息");
- if (tel.Data[0].Sigin == 0)
- throw UserFriendlyException.SameMessage("分机未签入,不能休息");
- var restingTel = await _telRestRepository.GetAsync(d => d.TelId == tel.Data[0].TelNo && !d.EndTime.HasValue, HttpContext.RequestAborted);
- if (restingTel is null)
- throw new UserFriendlyException("未查询到分机休息信息");
- await _telRestRepository.RemoveAsync(restingTel.Id, false, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 分机结束休息(威尔信)
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.UnRest)]
- [HttpGet("un-rest-wex")]
- public async Task<TelRestDto> UnRestWEX()
- {
- var tel = await _wexClient.QueryTelsAsync(new QueryTelRequest() { StaffNo = _sessionContext.StaffNo }, HttpContext.RequestAborted);
- if (tel.Data == null || tel.Data.Count == 0)
- throw UserFriendlyException.SameMessage("未找到分机信息");
- if (tel.Data[0].Sigin == 0)
- throw UserFriendlyException.SameMessage("分机未签入,不能休息");
- var telRest = await _telDomainService.UnRestWexAsync(tel.Data[0].TelNo, HttpContext.RequestAborted);
- return _mapper.Map<TelRestDto>(telRest);
- }
- #endregion
- /// <summary>
- /// 分机结束休息
- /// </summary>
- [Permission(EPermission.UnRest)]
- [HttpPut("un-rest")]
- public async Task<TelRestDto> UnRest()
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var telRest = await _telDomainService.UnRestAsync(work.TelId, HttpContext.RequestAborted);
- return _mapper.Map<TelRestDto>(telRest);
- }
- /// <summary>
- /// 保持通话
- /// </summary>
- [Permission(EPermission.Hold)]
- [HttpPut("hold")]
- public async Task Hold(string callId)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- await _telDomainService.HoldAsync(work.TelId, _sessionContext.RequiredUserId, _sessionContext.UserName, callId, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 恢复通话(解除hold状态)
- /// </summary>
- [Permission(EPermission.UnHold)]
- [HttpPut("un-hold")]
- public async Task UnHold(string callId)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- await _telDomainService.UnHoldAsync(work.TelId, _sessionContext.RequiredUserId, callId, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 分机呼分机
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.TelToTel)]
- [HttpPost("tel-to-tel")]
- public async Task TelToTel([FromBody] TelToTelDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- //获取对方是否在工作
- var toWork = _userCacheManager.GetWorkByTel(dto.TelNo);
- if (toWork is null)
- throw UserFriendlyException.SameMessage("转接分机未进行工作");
- //判断分机状态
- var telState =await _deviceManager.QueryTelState(dto.TelNo,HttpContext.RequestAborted);
- if (telState != ETelStatus.Ready)
- throw UserFriendlyException.SameMessage("被叫分机不在线或正在通话中");
- bool isRest = await _telRepository.IsRestingAsync(dto.TelNo, HttpContext.RequestAborted);
- if (isRest)
- throw new UserFriendlyException("被叫分机正在休息不能转接");
- await _deviceManager.ExtToExtAsync(work.TelNo, dto.TelNo, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 分机拨打外部电话
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.TelToOuter)]
- [HttpPost("tel-to-outer")]
- public async Task TelToOuter([FromBody] TelToOuterDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- await _deviceManager.ExtToOuterAsync(work.TelNo, dto.OuterNo, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 指定模拟外线外呼(分机拨打外部电话)
- /// OM设备多个外线时调用此接口
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.TelToOuterByLine)]
- [HttpPost("tel-to-outer-line")]
- public async Task TelToOuterByLine([FromBody] TelToOuterByLineDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- string newOuter = dto.LineId + "," + dto.OuterNo;
- await _deviceManager.ExtToOuterAsync(work.TelNo, newOuter, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 来电转分机
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.VisitorToTel)]
- [HttpPost("visitor-to-tel")]
- public async Task VisitorToTel([FromBody] VisitorToTelDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var toWork = _userCacheManager.GetWorkByTel(dto.TelNo);
- if (toWork is null)
- throw UserFriendlyException.SameMessage("转接分机未进行工作");
- var totelState = await _deviceManager.QueryTelState(dto.TelNo, HttpContext.RequestAborted);
- if (totelState != ETelStatus.Ready)
- throw UserFriendlyException.SameMessage("被叫分机不在线或正在通话中");
- bool isRest = await _telRepository.IsRestingAsync(dto.TelNo, HttpContext.RequestAborted);
- if (isRest)
- throw new UserFriendlyException("被叫分机正在休息不能转接");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.VisitorToExtAsync(tel.ConversationId, dto.TelNo, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- /// <summary>
- /// 来电转外部电话
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.VisitorToOuter)]
- [HttpPost("visitor-to-outer")]
- public async Task VisitorToOuter([FromBody] VisitorToOuterDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.VisitorToOuterAsync(tel.ConversationId, dto.OuterNo, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- /// <summary>
- /// 来电转分机组队列
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.VisitorToGroup)]
- [HttpPost("visitor-to-group")]
- public async Task VisitorToGroup([FromBody] VisitorToGroupDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.VisitorToGroupAsync(tel.ConversationId, dto.groupid, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- /// <summary>
- /// 去电转外部电话
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- /// <exception cref="UserFriendlyException"></exception>
- [Permission(EPermission.OuterToOuter)]
- [HttpPost("outer-to-outer")]
- public async Task OuterToOuter([FromBody] OuterToOuterDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.OuterToOuterAsync(tel.ConversationId, dto.OuterNo, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- /// <summary>
- /// 去电转分机
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- /// <exception cref="UserFriendlyException"></exception>
- [Permission(EPermission.OuterToTel)]
- [HttpPost("outer-to-tel")]
- public async Task OuterToTel([FromBody] OuterToTelDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var toWork = _userCacheManager.GetWorkByTel(dto.TelNo);
- if (toWork is null)
- throw UserFriendlyException.SameMessage("转接分机未进行工作");
- var totelState = await _deviceManager.QueryTelState(dto.TelNo, HttpContext.RequestAborted);
- if (totelState != ETelStatus.Ready)
- throw UserFriendlyException.SameMessage("被叫分机不在线或正在通话中");
- bool isRest = await _telRepository.IsRestingAsync(dto.TelNo, HttpContext.RequestAborted);
- if (isRest)
- throw new UserFriendlyException("被叫分机正在休息不能转接");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.OuterToExtAsync(tel.ConversationId, dto.TelNo, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- /// <summary>
- /// 三方会议
- /// 先建立两方通话,然后调用保持通话接口,拨通第三方分机,然后再调用三方会议接口
- /// 1. 分机 A 正在和 B 通话;
- /// 2. 分机 A 把原通话呼叫保持;
- /// 3. 分机 A 向 C 发起新的呼叫,并建立通话;
- /// 4. 此时,使用该 API 能够实现以分机 A 为主持方建立 A、B、C 的三方会议。
- /// </summary>
- /// <param name="dto">TelNo:会议发起方分机号</param>
- /// <returns></returns>
- /// <exception cref="UserFriendlyException"></exception>
- [Permission(EPermission.Conference)]
- [HttpPost("meeting")]
- public async Task Conference([FromBody] ConferenceDto dto)
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- var tel = await _deviceManager.QueryTelAsync(work.TelNo, HttpContext.RequestAborted);
- if (!string.IsNullOrEmpty(tel.ConversationId))
- await _deviceManager.ConferenceMeetingAsync(dto.TelNo, HttpContext.RequestAborted);
- else
- throw UserFriendlyException.SameMessage("当前分机没有通话");
- }
- #region 监听和强插
- /// <summary>
- /// 监听分机
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.MonitorExt)]
- [HttpPost("monitor-ext")]
- public async Task MonitorExt([FromBody] MonitorExtRequest request)
- {
- await _deviceManager.MonitorExtAsync(request.firstTelNo, request.secondTelNo, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 从监听到插播状态变换
- /// 1. 已知:分机 A 在监听分机 B 与其通话方的通话;
- /// 2. 执行分机 A 的从监听到插播状态变换的 API;
- /// 3. 执行成功时,分机 A 与分机 B 建立通话,分机 B 的原通话方听保持音。
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.MonitorExtToTalk)]
- [HttpPost("monitor-ext-to-talk")]
- public async Task MonitorExtToTalk([FromBody] MonitorExtToTalkRequest request)
- {
- await _deviceManager.MonitorExtToTalkAsync(request.telNo, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 从插播到监听状态变换
- /// 1. 已知:分机 A 在插播分机 B 的通话;
- /// 2. 执行分机 A 的从插播到监听状态变换的 API;
- /// 3. 执行成功时,分机 A 监听分机 B 及其原通话方的通话。
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.MonitorExtToListen)]
- [HttpPost("monitor-ext-to-listen")]
- public async Task MonitorExtToListen([FromBody] MonitorExtToListenRequest request)
- {
- await _deviceManager.MonitorExtToListenAsync(request.telNo, HttpContext.RequestAborted);
- }
- #endregion
- #region 强插
- /// <summary>
- /// 强插
- /// 1. 已知:分机 A 当前空闲,分机 B 正在通话中;
- /// 2. 执行分机 A 强插分机 B 的 API;
- /// 3. 执行成功时,分机 A 振铃,摘机后即可形成三方通话。
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.BargeinExt)]
- [HttpPost("bargein-ext")]
- public async Task BargeinExt([FromBody] BargeinExtRequest request)
- {
- await _deviceManager.BargeinExtAsync(request.firstTelNo, request.secondTelNo, HttpContext.RequestAborted);
- }
- #endregion
- #region 强拆
- /// <summary>
- /// 强拆分机
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.ClearExt)]
- [HttpPost("clear-ext")]
- public async Task ClearExt([FromBody] ClearExtRequest request)
- {
- //查询当前通话记录
- //var call = await _callRepository.GetAsync(request.CallId, HttpContext.RequestAborted);
- //if (call is null)
- // throw UserFriendlyException.SameMessage("无效通话,无法挂断");
- //if (call.CallStatus == ECallStatus.Bye)
- // throw UserFriendlyException.SameMessage("通话已结束");
- await _deviceManager.ClearExtAsync(request.CallId, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 强拆来电
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.ClearVisitor)]
- [HttpPost("clear-visitor")]
- public async Task ClearVisitor([FromBody] ClearVisitorRequest request)
- {
- //查询当前通话记录
- var call = await _callRepository.GetAsync(request.CallId, HttpContext.RequestAborted);
- if (call is null)
- throw UserFriendlyException.SameMessage("无效通话,无法挂断");
- if (call.CallStatus == ECallStatus.Bye)
- throw UserFriendlyException.SameMessage("通话已结束");
- await _deviceManager.ClearVisitorAsync(call.ConversationId, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 强拆去电
- /// </summary>
- /// <param name="request"></param>
- /// <returns></returns>
- [Permission(EPermission.ClearOuter)]
- [HttpPost("clear-outer")]
- public async Task ClearOuter([FromBody] ClearOuterRequest request)
- {
- //查询当前通话记录
- var call = await _callRepository.GetAsync(request.CallId, HttpContext.RequestAborted);
- if (call is null)
- throw UserFriendlyException.SameMessage("无效通话,无法挂断");
- if (call.CallStatus == ECallStatus.Bye)
- throw UserFriendlyException.SameMessage("通话已结束");
- await _deviceManager.ClearOuterAsync(call.ConversationId, HttpContext.RequestAborted);
- }
- #endregion
- #region 静音和取消静音
- /// <summary>
- /// 静音
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.Mute)]
- [HttpGet("mute")]
- public async Task Mute()
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- await _deviceManager.MuteAsync(work.TelNo, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 取消静音
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.UnMute)]
- [HttpGet("unmute")]
- public async Task UnMute()
- {
- var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
- if (work is null)
- throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
- await _deviceManager.UnMuteAsync(work.TelNo, HttpContext.RequestAborted);
- }
- #endregion
- #endregion
- #region 线路管理
- /// <summary>
- /// 获取线路列表
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.GetTrunkList)]
- [HttpGet("trunk-list")]
- public async Task<IReadOnlyList<TrunkIvrManager>> GetTrunkList()
- {
- return await _trunkIvrManagerRepository.Queryable()
- .Includes(d => d.WorkCategoryModel)
- .Includes(d => d.RestCategoryModel)
- .Includes(d => d.WorkToGroupModel.MappingField(z => z.No, () => d.WorkToGroup))
- .Includes(d => d.RestToGroupModel.MappingField(z => z.No, () => d.RestToGroup))
- .ToListAsync();
- }
- /// <summary>
- /// 获取线路对象
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- [Permission(EPermission.GetTrunk)]
- [HttpGet("trunk/{id}")]
- public async Task<TrunkIvrManager> GetTrunk(string id)
- {
- var trunk = await _trunkIvrManagerRepository.GetAsync(id, HttpContext.RequestAborted);
- if (trunk is null)
- throw UserFriendlyException.SameMessage("无效线路");
- return trunk;
- }
- /// <summary>
- /// 新增线路
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.AddTrunk)]
- [HttpPost("addtrunk")]
- public async Task AddTrunk([FromBody] AddTrunkDto dto)
- {
- var trunk = _mapper.Map<TrunkIvrManager>(dto);
- await _trunkIvrManagerRepository.AddAsync(trunk, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 修改线路
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.UpdateTrunk)]
- [HttpPost("updatetrunk")]
- public async Task UpdateTrunk([FromBody] UpdateTrunkDto dto)
- {
- var trunk = await _trunkIvrManagerRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
- if (trunk is null)
- throw UserFriendlyException.SameMessage("无效线路");
- _mapper.Map(dto, trunk);
- await _trunkIvrManagerRepository.UpdateAsync(trunk, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 删除线路
- /// </summary>
- /// <param name="id"></param>
- /// <returns></returns>
- [Permission(EPermission.RemoveTrunk)]
- [HttpGet("removetrunk/{id}")]
- public async Task RemoveTrunk(string id)
- {
- var trunk = await _trunkIvrManagerRepository.GetAsync(id, HttpContext.RequestAborted);
- if (trunk is null)
- throw UserFriendlyException.SameMessage("无效线路");
- await _trunkIvrManagerRepository.RemoveAsync(id, false, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 线路页面基础信息
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.TrunkPageInfo)]
- [HttpGet("trunk-page-info")]
- public async Task<object> TrunkPageInfo()
- {
- var ivr = await _ivrCategoryRepository.QueryAsync();
- var group = await _telGroupRepository.QueryAsync();
- var workDay = new List<WorkDayModel>();
- workDay.Add(new WorkDayModel() { weekName = "星期日", weekValue = "0" });
- workDay.Add(new WorkDayModel() { weekName = "星期一", weekValue = "1" });
- workDay.Add(new WorkDayModel() { weekName = "星期二", weekValue = "2" });
- workDay.Add(new WorkDayModel() { weekName = "星期三", weekValue = "3" });
- workDay.Add(new WorkDayModel() { weekName = "星期四", weekValue = "4" });
- workDay.Add(new WorkDayModel() { weekName = "星期五", weekValue = "5" });
- workDay.Add(new WorkDayModel() { weekName = "星期六", weekValue = "6" });
- return new { WorkCategorys = ivr, RestCategory = ivr, WorkToGroup = group, RestToGroup = group, WorkDay = workDay };
- }
- #endregion
- #region 话机业务
- /// <summary>
- /// 语音评价
- /// </summary>
- /// <param name="callId"></param>
- /// <returns></returns>
- [Permission(EPermission.Evaluate)]
- [HttpGet("evaluate/{callId}")]
- public async Task Evaluate(string callId)
- {
- //检查通话是否存在
- var call = await _callRepository.GetAsync(callId, HttpContext.RequestAborted);
- if (call is null)
- {
- throw new UserFriendlyException("未找到当前通话");
- }
- if (call.CallDirection != ECallDirection.In)
- {
- throw new UserFriendlyException("当前通话不是来电,不能发送评价邀请");
- }
- if (call.CallStatus == ECallStatus.Bye)
- {
- throw new UserFriendlyException("当前通话已结束");
- }
- if (call.CallStatus != ECallStatus.Answered && call.CallStatus != ECallStatus.Answer)
- {
- throw new UserFriendlyException("当前未进行通话,不能发送评价邀请");
- }
- //获取配置
- var correct = _ivrDomainService.GetCorrectIvr(call.ToNo, true);
- if (correct is null)
- throw new UserFriendlyException("系统未配置评价,请联系管理员");
- //检查是否有评价录音配置
- var ivrList = await _ivrCacheManager.GetIvrsAsync(HttpContext.RequestAborted);
- if (!ivrList.Any())
- throw new UserFriendlyException("未查到任何ivr配置");
- var ivr = ivrList.First(x => x.IvrCategoryId == correct.ReturnValue && x.IsRoot);
- _logger.LogInformation("transfer to ivr.no:{ivrNo}", ivr.No);
- //写入子表
- var detail = new CallDetail()
- {
- CallId = call.Id,
- CallStatus = ECallStatus.Evaluate,
- ConversationId = call.ConversationId,
- EventName = "EVALUATE",
- FromNo = call.FromNo,
- ToNo = call.ToNo,
- };
- await _callDetailRepository.AddAsync(detail, HttpContext.RequestAborted);
- await _deviceManager.VisitorToMenuAsync(call.ConversationId, ivr.No, HttpContext.RequestAborted);
- }
- #endregion
- #region 威尔信分机和分机组操作
- /// <summary>
- /// 查询分机
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.QueryTels)]
- [HttpGet("query-tel-list")]
- public async Task<PagedDto<TelListPageDto>> QueryTelList([FromQuery]QueryTelListDto dto)
- {
- var rsp = await _wexClient.QueryTelsPageAsync(new QueryTelPageRequest() { PageIndex = dto.PageIndex, PageSize = dto.PageSize}, HttpContext.RequestAborted);
- var telList = rsp?.Data;
- var count = rsp.Count;
- if (telList!=null)
- {
- var telGroup = _wexTelGroupRepository.Queryable().ToList();
- var list = (from a in telList
- join b in telGroup on a.TelNo equals b.TelNo into output
- from j in output.DefaultIfEmpty()
- select new TelListPageDto
- {
- Id = (j==null ? "": j.Id),
- TelNo = a.TelNo,
- GroupName = (j==null ? "": j.GroupName)
- }).ToList();
- return new PagedDto<TelListPageDto>(count, list);
- }
- return new PagedDto<TelListPageDto>(0, null);
- }
- /// <summary>
- /// 新增分机关联分机组
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [AllowAnonymous]
- [Permission(EPermission.AddTelGroup)]
- [HttpGet("add-wextelgroup")]
- public async Task AddWexTelGroup([FromBody]AddWexTelGroupDto dto)
- {
- var telGroup = new WexTelGroup();
- telGroup.TelNo = dto.TelNo;
- telGroup.GroupId = dto.GroupId;
- telGroup.GroupName = dto.GroupName;
- telGroup.ZuoGroupName = dto.ZuoGroupName;
- await _wexTelGroupRepository.AddAsync(telGroup, HttpContext.RequestAborted);
- }
- /// <summary>
- /// 修改分机关联分机组
- /// </summary>
- /// <param name="dto"></param>
- /// <returns></returns>
- [Permission(EPermission.UpdateTelGroup)]
- [HttpGet("update-wextelgroup")]
- public async Task UpdateWexTelGroup([FromBody]UpdateWexTelGroupDto dto)
- {
- var telGroup =await _wexTelGroupRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
- if (telGroup is null)
- {
- throw UserFriendlyException.SameMessage("未找到对应数据,无法修改");
- }
- if (dto.GroupId == 0)
- {
- await _wexTelGroupRepository.RemoveAsync(dto.Id, false, HttpContext.RequestAborted);
- }
- else
- {
- telGroup.GroupId = dto.GroupId;
- telGroup.GroupName = dto.GroupName;
- telGroup.ZuoGroupName = dto.ZuoGroupName;
- await _wexTelGroupRepository.UpdateAsync(telGroup);
- }
- }
- /// <summary>
- /// 分机组列表
- /// </summary>
- /// <returns></returns>
- [Permission(EPermission.QueryTelGroups)]
- [HttpGet("telgroup-list")]
- public async Task<List<WexTelGroupDto>> TelGroupList()
- {
- var rsp = await _wexClient.QueryGroupAsync(new QueryGroupRequest() { }, HttpContext.RequestAborted);
- var groupList = rsp.Data;
- var list = _mapper.Map<List<WexTelGroupDto>>(groupList);
- return list;
- }
- /// <summary>
- /// 根据分机号查询分机关联坐席组
- /// </summary>
- /// <param name="telno"></param>
- /// <returns></returns>
- [Permission(EPermission.QueryTelGroups)]
- [HttpGet("telgroup/{telno}")]
- public async Task<WexTelGroup> TelGroup(string telno)
- {
- var telGroup = await _wexTelGroupRepository.GetAsync(x => x.TelNo == telno, HttpContext.RequestAborted);
- if (telGroup is null)
- {
- return new WexTelGroup() { TelNo = telno };
- }
- return telGroup;
- }
- #endregion
- }
- }
|