Parcourir la source

feature: 改写CallController,抽象ICallApplication

xf il y a 9 mois
Parent
commit
96c51cc84b

+ 7 - 0
Hotline.sln

@@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.YbEnterprise.Sdk",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XingTang.Sdk", "src\XingTang.Sdk\XingTang.Sdk.csproj", "{CF2A8B80-FF4E-4291-B383-D735BB629F32}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotline.XingTang", "src\Hotline.XingTang\Hotline.XingTang.csproj", "{9F99C272-5BC2-452C-9D97-BC756AF04669}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -129,6 +131,10 @@ Global
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -156,6 +162,7 @@ Global
 		{1634234A-379C-44DC-BFEC-7BBDEF50B47B} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{C3F289D5-C50B-46DB-852C-9543EF9B0355} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{CF2A8B80-FF4E-4291-B383-D735BB629F32} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
+		{9F99C272-5BC2-452C-9D97-BC756AF04669} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {4B8EA790-BD13-4422-8D63-D6DBB77B823F}

+ 54 - 0
src/Hotline.Api/Controllers/CallController.cs

@@ -0,0 +1,54 @@
+using Hotline.Application.CallCenter;
+using Hotline.CallCenter.BlackLists;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Hotline.Api.Controllers
+{
+    public class CallController : BaseController
+    {
+        private readonly ICallApplication _callApplication;
+
+        public CallController(ICallApplication callApplication)
+        {
+            _callApplication = callApplication;
+        }
+
+        /// <summary>
+        /// 查询分机
+        /// </summary>
+        [HttpGet("tels")]
+        public Task<IReadOnlyList<TelDto>> QueryTelsAsync()
+            => _callApplication.QueryTelsAsync(HttpContext.RequestAborted);
+
+        /// <summary>
+        /// 查询分机组
+        /// </summary>
+        [HttpGet("groups")]
+        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync()
+            => _callApplication.QueryTelGroupsAsync(HttpContext.RequestAborted);
+
+        #region 黑名单
+
+        //Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken);
+        //Task RemoveBlackListAsync(string id, CancellationToken cancellationToken);
+        //Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken);
+
+        #endregion
+
+        /// <summary>
+        /// 签入
+        /// </summary>
+        [HttpPost("signin")]
+        public Task<TrOnDutyResponseDto> SignInAsync([FromBody] SignInDto dto)
+            => _callApplication.SignInAsync(dto, HttpContext.RequestAborted);
+
+        /// <summary>
+        /// 签出
+        /// </summary>
+        [HttpPost("signout")]
+        public Task SingOutAsync()
+            => _callApplication.QueryTelsAsync(HttpContext.RequestAborted);
+    }
+}

+ 2 - 2
src/Hotline.Api/Controllers/CallController1.cs → src/Hotline.Api/Controllers/CalloldController.cs

@@ -18,7 +18,7 @@ namespace Hotline.Api.Controllers
     /// <summary>
     /// 通话相关接口
     /// </summary>
-    public class CallController1 : BaseController
+    public class CalloldController : BaseController
     {
         private readonly ICallRepository _callRepository;
         private readonly IMapper _mapper;
@@ -34,7 +34,7 @@ namespace Hotline.Api.Controllers
         /// <param name="blacklistDomainService"></param>
         /// <param name="blacklistRepository"></param>
         /// <param name="wexCallRecordRepository"></param>
-        public CallController1(
+        public CalloldController(
             ICallRepository callRepository,
             IMapper mapper,
             IBlacklistDomainService blacklistDomainService,

+ 1 - 1
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -307,7 +307,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);

+ 5 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -24,6 +24,7 @@ using Hotline.YbEnterprise.Sdk;
 using Hotline.Share.Dtos.SendSms;
 using Hotline.Wex;
 using Hotline.Application.CallCenter.Calls;
+using Hotline.Application.CallCenter;
 
 namespace Hotline.Api;
 
@@ -112,6 +113,7 @@ internal static class StartupExtensions
                 break;
             case "TianRun":
                 services
+                    .AddScoped<ICallApplication, TianRunCallApplication>()
                     .AddScoped<ITrApplication, TrApplication>()
                     .AddHostedService<CurrentWaitNumService>()
                     .AddHostedService<TelsStatusRefreshService>()
@@ -120,7 +122,9 @@ internal static class StartupExtensions
                         callCenterConfiguration.TianRun.Password);
                 break;
             case "XingTang":
-                services.AddXingTangDb(callCenterConfiguration.XingTang);
+                services.AddXingTangDb(callCenterConfiguration.XingTang)
+                    .AddScoped<ICallApplication, XingTangCallApplication>()
+                    ;
                 break;
             default:
                 break;

+ 1 - 1
src/Hotline.Application.Contracts/Validators/CallCenter/AddBlacklistDtoValidator.cs

@@ -7,7 +7,7 @@ namespace Hotline.Application.Contracts.Validators.CallCenter
     {
         public AddBlacklistDtoValidator()
         {
-            RuleFor(d => d.PhoneNo).NotEmpty();
+            RuleFor(d => d.Phone).NotEmpty();
             RuleFor(d => d.Duration).NotEmpty();
         }
     }

+ 11 - 0
src/Hotline.Application/CallCenter/ICallApplication.cs

@@ -5,6 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using Hotline.CallCenter.BlackLists;
 using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
 
 namespace Hotline.Application.CallCenter
 {
@@ -27,5 +28,15 @@ namespace Hotline.Application.CallCenter
         Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken);
 
         #endregion
+
+        /// <summary>
+        /// 签入
+        /// </summary>
+        Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 签出
+        /// </summary>
+        Task SingOutAsync(CancellationToken cancellationToken);
     }
 }

+ 68 - 0
src/Hotline.Application/CallCenter/TianRunCallApplication.cs

@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Application.CallCenter.Calls;
+using Hotline.Application.Tels;
+using Hotline.CallCenter.BlackLists;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.CallCenter;
+using Microsoft.AspNetCore.Http;
+using XF.Domain.Authentications;
+
+namespace Hotline.Application.CallCenter
+{
+    public class TianRunCallApplication : ICallApplication
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly ITrApplication _trApplication;
+        private readonly ITelApplication _telApplication;
+
+        public TianRunCallApplication(
+            ISessionContext sessionContext,
+            ITrApplication trApplication,
+            ITelApplication telApplication)
+        {
+            _sessionContext = sessionContext;
+            _trApplication = trApplication;
+            _telApplication = telApplication;
+        }
+
+        public Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<TrOnDutyResponseDto> SignInAsync(SignInDto dto, CancellationToken cancellationToken)
+        {
+            return await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, (ETelModel)dto.TelModelState, cancellationToken);
+        }
+
+        public async Task SingOutAsync(CancellationToken cancellationToken)
+        {
+            await _telApplication.SignOutAsync(_sessionContext.RequiredUserId, cancellationToken);
+        }
+    }
+}

+ 128 - 0
src/Hotline.Application/CallCenter/XingTangCallApplication.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.BlackLists;
+using Hotline.CallCenter.Tels;
+using Hotline.Repository.SqlSugar.CallCenter;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Users;
+using XF.Domain.Authentications;
+using XF.Domain.Cache;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.CallCenter
+{
+    public class XingTangCallApplication : ICallApplication
+    {
+        private readonly IRepository<Tel> _telRepository;
+        private readonly IRepository<TelGroup> _telGroupRepository;
+        private readonly IWorkRepository _workRepository;
+        private readonly ITelRestRepository _telRestRepository;
+        private readonly ITypedCache<Work> _cacheWork;
+        private readonly IUserCacheManager _userCacheManager;
+        private readonly ISessionContext _sessionContext;
+
+        public XingTangCallApplication(
+            IRepository<Tel> telRepository,
+            IRepository<TelGroup> telGroupRepository,
+            IWorkRepository workRepository,
+            ITelRestRepository telRestRepository,
+            ITypedCache<Work> cacheWork,
+            IUserCacheManager userCacheManager,
+            ISessionContext sessionContext)
+        {
+            _telRepository = telRepository;
+            _telGroupRepository = telGroupRepository;
+            _workRepository = workRepository;
+            _telRestRepository = telRestRepository;
+            _cacheWork = cacheWork;
+            _userCacheManager = userCacheManager;
+            _sessionContext = sessionContext;
+        }
+
+        public async Task<IReadOnlyList<TelDto>> QueryTelsAsync(CancellationToken cancellationToken)
+        {
+            return await _telRepository.Queryable()
+                .Select<TelDto>()
+                .ToListAsync(cancellationToken);
+        }
+
+        public async Task<IReadOnlyList<TelGroupDto>> QueryTelGroupsAsync(CancellationToken cancellationToken)
+        {
+            return await _telGroupRepository.Queryable()
+                .Select<TelGroupDto>()
+                .ToListAsync(cancellationToken);
+        }
+
+        public Task<string> AddBlackListAsync(AddBlacklistDto dto, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task RemoveBlackListAsync(string id, CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Task<List<Blacklist>> QueryBlackListsAsync(CancellationToken cancellationToken)
+        {
+            throw new NotImplementedException();
+        }
+
+        public async Task<TrOnDutyResponseDto> 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.GetWorkByUser(_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);
+            _cacheWork.Remove(work.GetKey(KeyMode.UserId));
+            _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
+        }
+    }
+}

+ 3 - 1
src/Hotline.Repository.SqlSugar/Extensions/XingTangDbExtensions.cs

@@ -7,7 +7,7 @@ namespace Hotline.Repository.SqlSugar.Extensions;
 
 public static class XingTangDbExtensions
 {
-    public static void AddXingTangDb(this IServiceCollection services, XingTangConfiguration xingTangConfiguration)
+    public static IServiceCollection AddXingTangDb(this IServiceCollection services, XingTangConfiguration xingTangConfiguration)
     {
         SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
         {
@@ -20,5 +20,7 @@ public static class XingTangDbExtensions
 
         ISugarUnitOfWork<XingTangDbContext> context = new SugarUnitOfWork<XingTangDbContext>(sqlSugar);
         services.AddSingleton(context);
+
+        return services;
     }
 }

+ 1 - 1
src/Hotline.Share/Dtos/CallCenter/AddBlacklistDto.cs

@@ -1,4 +1,4 @@
 namespace Hotline.Share.Dtos.CallCenter
 {
-    public record AddBlacklistDto(string PhoneNo, double Duration);
+    public record AddBlacklistDto(string Phone, double Duration, int? SpecialFlag);
 }

+ 29 - 0
src/Hotline.Share/Dtos/CallCenter/SignInDto.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.CallCenter
+{
+    /// <summary>
+    /// 签入
+    /// </summary>
+    public class SignInDto
+    {
+        /// <summary>
+        /// 分机号
+        /// </summary>
+        public string? TelNo { get; set; }
+
+        /// <summary>
+        /// 分机组id
+        /// </summary>
+        public string? GroupId { get; set; }
+
+        /// <summary>
+        /// 兼容添润签入参数
+        /// </summary>
+        public int TelModelState { get; set; }
+    }
+}

+ 17 - 0
src/Hotline.Share/Dtos/CallCenter/TelDto.cs

@@ -63,6 +63,23 @@ namespace Hotline.Share.Dtos.CallCenter
         public string GroupNames => string.Join(",", Groups?.Select(x => x.Name) ?? new List<string>());
 
         public List<TelGroupDto> Groups { get; set; }
+
+        #region 兼容添润字段
+        
+        public string Name { get; set; }
+
+        public string TelNo { get; set; }
+
+        public string Description { get; set; }
+
+        public string QueueId { get; set; }
+
+        /// <summary>
+        /// 外呼分机组(由内部系统提供)
+        /// </summary>
+        public string? CallOutQueue { get; set; }
+
+        #endregion
     }
 
    

+ 14 - 0
src/Hotline.XingTang/Hotline.XingTang.csproj

@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net7.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Hotline\Hotline.csproj" />
+    <ProjectReference Include="..\XingTang.Sdk\XingTang.Sdk.csproj" />
+  </ItemGroup>
+
+</Project>

+ 2 - 2
src/Hotline/CallCenter/BlackLists/BlacklistDomainService.cs

@@ -32,8 +32,8 @@ public class BlacklistDomainService : IBlacklistDomainService, IScopeDependency
     public async Task AddAsync(AddBlacklistDto dto, CancellationToken cancellationToken = default)
     {
         var cache = await _blackCache.GetOrSetAsync(
-            Blacklist.GetKey(dto.PhoneNo),
-            k => _blacklistRepository.Queryable().FirstAsync(d => d.PhoneNo == dto.PhoneNo).GetAwaiter().GetResult(),
+            Blacklist.GetKey(dto.Phone),
+            k => _blacklistRepository.Queryable().FirstAsync(d => d.PhoneNo == dto.Phone).GetAwaiter().GetResult(),
             TimeSpan.FromSeconds(dto.Duration),
             cancellationToken);
         if (cache != null) return;

+ 2 - 2
src/Hotline/CallCenter/Calls/CallNative.cs

@@ -69,9 +69,9 @@ namespace Hotline.CallCenter.Calls
         public DateTime EndTime { get; set; }
 
         /// <summary>
-        /// 队列ID
+        /// 分机组id(技能组Id)
         /// </summary>
-        public string? QueueId { get; set; }
+        public string? GroupId { get; set; }
 
         /// <summary>
         /// 工号

+ 0 - 1
src/Hotline/CallCenter/Calls/ICallDomainService.cs

@@ -96,7 +96,6 @@ namespace Hotline.CallCenter.Calls
         Task MonitorExtToListen(MonitorExtToListenRequest request, CancellationToken cancellationToken);
         #endregion
 
-
         #region 强插
 
         /// <summary>

+ 1 - 1
src/Hotline/Users/Work.cs

@@ -63,7 +63,7 @@ public class Work : CreationModificationEntity
 
     }
 
-    public Work(string userId, string name, string telId, string telNo, string? telPwd, string? description, string? queueId,string? staffNo, ETelModel telModel)
+    public Work(string userId, string name, string telId, string telNo, string? telPwd, string? description, string? queueId,string? staffNo, ETelModel? telModel)
     {
         StartTime = DateTime.Now;
         UserId = userId;