Jelajahi Sumber

本地处理

TANG JIANG 2 tahun lalu
induk
melakukan
7f7a9f9ef4

+ 1 - 0
src/Hotline.Api/Controllers/BaseController.cs

@@ -3,6 +3,7 @@
 namespace Hotline.Api.Controllers;
 
 [ApiController]
+[Produces("application/json")]
 [Route("api/v1/[controller]")]
 public class BaseController : ControllerBase
 {

+ 15 - 1
src/Hotline.Api/Controllers/OrderController.cs

@@ -17,6 +17,9 @@ using XF.Utility.EnumExtensions;
 
 namespace Hotline.Api.Controllers;
 
+/// <summary>
+/// 工单
+/// </summary>
 public class OrderController : BaseController
 {
     private readonly IOrderDomainService _orderDomainService;
@@ -105,6 +108,11 @@ public class OrderController : BaseController
         return _mapper.Map<OrderDto>(order);
     }
 
+    /// <summary>
+    /// 新增工单
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
     [HttpPost]
     public async Task<string> Add([FromBody] AddOrderDto dto)
     {
@@ -133,6 +141,12 @@ public class OrderController : BaseController
         await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
     }
 
+    /// <summary>
+    /// 开始流程
+    /// </summary>
+    /// <param name="id">工单id</param>
+    /// <param name="dto">流程开启参数</param>
+    /// <returns></returns>
     [HttpPost("{id}/startflow")]
     public async Task StartFlow(string id, [FromBody] StartWorkflowDto dto)
     {
@@ -190,7 +204,7 @@ public class OrderController : BaseController
     }
 
     /// <summary>
-    /// 新增页面
+    /// 扩展信息新增页面
     /// </summary>
     /// <returns></returns>
     [HttpGet("base-data-ext")]

+ 20 - 5
src/Hotline.Api/Controllers/PbxController.cs

@@ -1,4 +1,6 @@
-using Hotline.Caches;
+using Hotline.Application.FlowEngine;
+using Hotline.CacheManager;
+using Hotline.Caches;
 using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Devices;
 using Hotline.CallCenter.Ivrs;
@@ -8,6 +10,7 @@ using Hotline.Permissions;
 using Hotline.Repository.SqlSugar.CallCenter;
 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;
@@ -18,6 +21,7 @@ using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
+using XF.Domain.Constants;
 using XF.Domain.Exceptions;
 using XF.Utility.EnumExtensions;
 
@@ -41,6 +45,8 @@ namespace Hotline.Api.Controllers
         private readonly ICallRepository _callRepository;
         private readonly ITrunkIvrManagerRepository _trunkIvrManagerRepository;
         private readonly IIvrCategoryRepository _ivrCategoryRepository;
+        private readonly IWorkflowApplication _workflowApplication;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
         public PbxController(
             ITelRepository telRepository,
@@ -55,7 +61,9 @@ namespace Hotline.Api.Controllers
             ISessionContext sessionContext,
             ICallRepository callRepository,
             ITrunkIvrManagerRepository trunkIvrManagerRepository,
-            IIvrCategoryRepository ivrCategoryRepository)
+            IIvrCategoryRepository ivrCategoryRepository,
+            IWorkflowApplication workflowApplication,
+            ISystemSettingCacheManager systemSettingCacheManager)
         {
             _telRepository = telRepository;
             _telDomainService = telDomainService;
@@ -70,6 +78,8 @@ namespace Hotline.Api.Controllers
             _callRepository = callRepository;
             _trunkIvrManagerRepository = trunkIvrManagerRepository;
             _ivrCategoryRepository = ivrCategoryRepository;
+            _workflowApplication = workflowApplication;
+            _systemSettingCacheManager = systemSettingCacheManager;
         }
 
         #region 话机
@@ -204,13 +214,18 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [Permission(EPermission.Rest)]
-        [HttpPut("rest")]
-        public async Task Rest()
+        [HttpPost("rest")]
+        public async Task Rest([FromBody] StartRestDto dto)
         {
             var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
             if (work is null)
                 throw UserFriendlyException.SameMessage("当前坐席暂未进行工作");
-            await _telDomainService.RestAsync(work, HttpContext.RequestAborted);
+            bool isApply = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.RestApproval).SettingValue);
+            string id = await _telDomainService.RestAsync(work,dto.Reason,isApply, HttpContext.RequestAborted);
+            
+            var startworkflow = _mapper.Map<StartWorkflowDto>(dto);
+            if (isApply)
+                await _workflowApplication.StartWorkflowAsync(dto, id, HttpContext.RequestAborted);
         }
 
         /// <summary>

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

@@ -276,7 +276,7 @@ namespace Hotline.Api.Controllers
         [HttpGet("dictdata-type")]
         public async Task<List<SysDicData>> GetSysDicData([FromQuery] GetSysDicDataDto dto)
         {
-            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).WhereIF(!string.IsNullOrEmpty(dto.datavalue),x=>x.DicDataValue.Contains(dto.datavalue)).ToTreeAsync(x=>x.children,x=>x.ParentId,"");
+            return await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.typeid).WhereIF(!string.IsNullOrEmpty(dto.datavalue),x=>x.DicDataValue.Contains(dto.datavalue)).ToTreeAsync(x=>x.Children,x=>x.ParentId,"");
         }
 
         /// <summary>

+ 2 - 4
src/Hotline.Api/Hotline.Api.csproj

@@ -5,7 +5,7 @@
     <Nullable>enable</Nullable>
     <ImplicitUsings>enable</ImplicitUsings>
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
-    <DocumentationFile>document.xml</DocumentationFile>
+    <NoWarn>$(NoWarn);1591</NoWarn>
   </PropertyGroup>
 
   <ItemGroup>
@@ -18,13 +18,11 @@
     <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="6.0.8" />
     <PackageReference Include="Serilog.Sinks.Exceptionless" Version="3.1.5" />
     <PackageReference Include="Serilog.Sinks.MongoDB" Version="5.3.1" />
-    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
+    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
   </ItemGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\Hotline.Application\Hotline.Application.csproj" />
   </ItemGroup>
 
-  <ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
-
 </Project>

+ 1 - 0
src/Hotline.Api/Realtimes/RealtimeMethods.cs

@@ -5,6 +5,7 @@
         public static string Ring = "Ring";
         public static string Answered = "Answered";
         public static string Bye= "Bye";
+        public static string RestApplyPass = "RestApplyPass";
     }
 }
     

+ 15 - 0
src/Hotline.Api/Realtimes/RealtimeService.cs

@@ -65,4 +65,19 @@ public class RealtimeService : IRealtimeService, IScopeDependency
         await _hubContext.Clients.Client(work.SignalRId).SendAsync(RealtimeMethods.Bye, dto, cancellationToken);
     }
 
+    /// <summary>
+    /// 小休审核通过后通知前端
+    /// </summary>
+    /// <param name="userId"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    /// <exception cref="UserFriendlyException"></exception>
+    public async Task RestApplyPassAsync(string userId,CancellationToken cancellationToken)
+    {
+        var work = _userCacheManager.GetWorkByUser(userId);
+        if (string.IsNullOrEmpty(work.SignalRId))
+            throw new UserFriendlyException("无效signalr.connectionId");
+        await _hubContext.Clients.Client(work.SignalRId).SendAsync(RealtimeMethods.RestApplyPass, cancellationToken);
+    }
+
 }

+ 8 - 8
src/Hotline.Api/StartupHelper.cs

@@ -1,4 +1,5 @@
 using System.IdentityModel.Tokens.Jwt;
+using System.Reflection;
 using System.Text;
 using Mapster;
 using MapsterMapper;
@@ -72,12 +73,12 @@ namespace Hotline.Api
                         {
                             var accessToken = context.Request.Query["access_token"];
 
-                                    // If the request is for our hub...
+                            // If the request is for our hub...
                             var path = context.HttpContext.Request.Path;
                             if (!string.IsNullOrEmpty(accessToken) &&
                                 (path.StartsWithSegments("/hubs/callcenter")))
                             {
-                                        // Read the token out of the query string
+                                // Read the token out of the query string
                                 context.Token = accessToken;
                             }
                             return Task.CompletedTask;
@@ -100,12 +101,11 @@ namespace Hotline.Api
             {
                 //添加文档
                 c.SwaggerDoc("v1", new OpenApiInfo() { Title = "Hotline Api", Version = "v1.0", Description = "城市热线api" });
-                //使用反射获取xml文件,并构造出文件的路径
-                var xmlFile = "document.xml";
-                //var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
-                var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
-                // 启用xml注释. 该方法第二个参数启用控制器的注释,默认为false.
-                c.IncludeXmlComments(xmlPath, true);
+                var files = Directory.GetFiles(AppContext.BaseDirectory).Where(d => d.EndsWith(".xml"));
+                foreach (var file in files)
+                {
+                    c.IncludeXmlComments(file, true);
+                }
 
                 var scheme = new OpenApiSecurityScheme()
                 {

+ 8 - 9
src/Hotline.Application/Handlers/FlowEngine/EndWorkflowHandler.cs

@@ -1,17 +1,16 @@
 using Hotline.FlowEngine.Notifies;
-using Hotline.KnowledgeBase;
 using Hotline.Settings;
+using Hotline.Share.Enums.Order;
 using MediatR;
 
 namespace Hotline.Application.Handlers.FlowEngine;
 
 public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
 {
-    private readonly IKnowledgeDomainService _knowledgeDomainService;
 
-    public EndWorkflowHandler(IKnowledgeDomainService knowledgeDomainService)
+    public EndWorkflowHandler()
     {
-        _knowledgeDomainService = knowledgeDomainService;
+
     }
 
     /// <summary>Handles a notification</summary>
@@ -19,15 +18,15 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
     /// <param name="cancellationToken">Cancellation token</param>
     public async Task Handle(EndWorkflowNotify notification, CancellationToken cancellationToken)
     {
-        //知识审批收到此消息表示审批通过
         var workflow = notification.Workflow;
+
         switch (workflow.ModuleCode)
         {
-            case WorkflowModuleConsts.KnowledgeAdd://新增
-            case WorkflowModuleConsts.KnowledgeUpdate://修改
-            case WorkflowModuleConsts.KnowledgeDelete://删除
-                await _knowledgeDomainService.EndWorkKnowledge(workflow, cancellationToken);
+            case WorkflowModuleConsts.TelRestApply:
+                //TODO 审核通过
+                //notification.Workflow.ExternalId;
                 break;
+
         }
     }
 }

+ 32 - 0
src/Hotline.CacheManager/SysDicDataCacheManager.cs

@@ -0,0 +1,32 @@
+using Hotline.Caches;
+using Hotline.Settings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Cache;
+
+namespace Hotline.CacheManager
+{
+    public class SysDicDataCacheManager : ISysDicDataCacheManager
+    {
+        private readonly ISysDicDataRepository _sysDicDataRepository;
+        private readonly ITypedCache<IReadOnlyList<SysDicData>> _cacheSysDicData;
+
+        public SysDicDataCacheManager(ISysDicDataRepository sysDicDataRepository,ITypedCache<IReadOnlyList<SysDicData>> cacheSysDicData)
+        {
+            _sysDicDataRepository = sysDicDataRepository;
+            _cacheSysDicData = cacheSysDicData;
+        }
+
+        public IReadOnlyList<SysDicData> GetSysDicDataCache(string code)
+        {
+            var sysDicDataList = _cacheSysDicData.GetOrAdd(code, k =>
+            {
+                return _sysDicDataRepository.Queryable().Where(x => x.DicTypeCode == code).ToTreeAsync(x => x.Children, it => it.ParentId, "").GetAwaiter().GetResult();
+            });
+            return sysDicDataList;
+        }
+    }
+}

+ 11 - 1
src/Hotline.Share/Dtos/CallCenter/TelRestDto.cs

@@ -1,5 +1,15 @@
-namespace Hotline.Share.Dtos.CallCenter
+using Hotline.Share.Dtos.FlowEngine;
+
+namespace Hotline.Share.Dtos.CallCenter
 {
+    public class StartRestDto: StartWorkflowDto
+    {
+        /// <summary>
+        /// 小休原因
+        /// </summary>
+        public string Reason { get; set; }
+    }
+
     public record TelRestDto
     {
         /// <summary>

+ 7 - 0
src/Hotline.Share/Dtos/FlowEngine/StartWorkflowDto.cs

@@ -2,8 +2,15 @@
 {
     public class StartWorkflowDto : BasicWorkflowDto
     {
+        /// <summary>
+        /// 模板编码
+        /// </summary>
         public string DefinitionCode { get; set; }
 
+        /// <summary>
+        /// 流程title
+        /// </summary>
+
         public string Title { get; set; }
     }
 }

+ 7 - 0
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -228,7 +228,14 @@ namespace Hotline.Share.Dtos.Order
 
         #endregion
 
+        /// <summary>
+        /// 投诉
+        /// </summary>
         public OrderComplainDto OrderComplain { get; set; }
+
+        /// <summary>
+        /// 举报
+        /// </summary>
         public OrderReportDto OrderReport { get; set; }
     }
 }

+ 23 - 0
src/Hotline.Share/Enums/Order/ERestApplyStatus.cs

@@ -0,0 +1,23 @@
+
+namespace Hotline.Share.Enums.Order
+{
+    public enum ERestApplyStatus
+    {
+        /// <summary>
+        /// 待审核
+        /// </summary>
+        NoAudit = 0,
+        /// <summary>
+        /// 休息中
+        /// </summary>
+        Resting = 1,
+        /// <summary>
+        /// 已终止
+        /// </summary>
+        Shoping = 2,
+        /// <summary>
+        /// 已结束
+        /// </summary>
+        Ending = 3,
+    }
+}

+ 2 - 0
src/Hotline.Share/Hotline.Share.csproj

@@ -4,6 +4,8 @@
     <TargetFramework>net6.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
+    <GenerateDocumentationFile>True</GenerateDocumentationFile>
+    <NoWarn>$(NoWarn);1591</NoWarn>
   </PropertyGroup>
 
   <ItemGroup>

+ 14 - 0
src/Hotline/Caches/ISysDicDataCacheManager.cs

@@ -0,0 +1,14 @@
+using Hotline.Settings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Caches
+{
+    public interface ISysDicDataCacheManager
+    {
+        IReadOnlyList<SysDicData> GetSysDicDataCache(string code);
+    }
+}

+ 9 - 1
src/Hotline/CallCenter/Tels/ITelDomainService.cs

@@ -44,7 +44,15 @@ namespace Hotline.CallCenter.Tels
         /// <param name="currentWork"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        Task RestAsync(Work currentWork, CancellationToken cancellationToken);
+        Task<string> RestAsync(Work currentWork,string reason,bool isApply, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 分机小休审批通过
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task RestApplyPass(string id, CancellationToken cancellationToken);
 
         /// <summary>
         /// 分机结束休息

+ 32 - 4
src/Hotline/CallCenter/Tels/TelDomainService.cs

@@ -1,5 +1,9 @@
-using Hotline.CallCenter.Devices;
+using Hotline.Caches;
+using Hotline.CallCenter.Devices;
+using Hotline.Realtimes;
 using Hotline.Users;
+using System.Reflection;
+using XF.Domain.Constants;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 
@@ -11,17 +15,20 @@ public class TelDomainService : ITelDomainService, IScopeDependency
     private readonly ITelRepository _telRepository;
     private readonly ITelRestRepository _telRestRepository;
     private readonly ITelHoldRepository _telHoldRepository;
+    private readonly IRealtimeService _realtimeService;
 
     public TelDomainService(
         IDeviceManager deviceManager,
         ITelRepository telRepository,
         ITelRestRepository telRestRepository,
-        ITelHoldRepository telHoldRepository)
+        ITelHoldRepository telHoldRepository,
+        IRealtimeService realtimeService)
     {
         _deviceManager = deviceManager;
         _telRepository = telRepository;
         _telRestRepository = telRestRepository;
         _telHoldRepository = telHoldRepository;
+        _realtimeService = realtimeService;
     }
 
 
@@ -47,15 +54,36 @@ public class TelDomainService : ITelDomainService, IScopeDependency
     /// <param name="currentWork"></param>
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
-    public async Task RestAsync(Work currentWork, CancellationToken cancellationToken)
+    public async Task<string> RestAsync(Work currentWork,string reason,bool isApply, CancellationToken cancellationToken)
     {
         var isResting = await _telRepository.IsRestingAsync(currentWork.TelNo, cancellationToken);
         if (!isResting)
         {
             await _deviceManager.TelRestAsync(currentWork.TelNo, cancellationToken);
-            await _telRestRepository.AddAsync(new TelRest(currentWork.TelId, currentWork.TelNo, currentWork.UserId, currentWork.UserName),
+            
+            return await _telRestRepository.AddAsync(new TelRest(currentWork.TelId, currentWork.TelNo, currentWork.UserId, currentWork.UserName,reason, isApply),
                 cancellationToken);
         }
+        throw new UserFriendlyException("当前坐席正在休息");
+    }
+
+    /// <summary>
+    /// 分机审批通过
+    /// </summary>
+    /// <param name="id"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    public async Task RestApplyPass(string id, CancellationToken cancellationToken)
+    {
+        var telrest = await _telRestRepository.GetAsync(id, cancellationToken);
+        if(telrest!=null)
+        {
+            telrest.ApplyStatus = Share.Enums.Order.ERestApplyStatus.Resting;
+            telrest.StartTime = DateTime.Now;
+            await _telRestRepository.UpdateAsync(telrest, cancellationToken);
+            //通知前端休息通过
+            await _realtimeService.RestApplyPassAsync(telrest.UserId, cancellationToken);
+        }
     }
 
     /// <summary>

+ 26 - 5
src/Hotline/CallCenter/Tels/TelRest.cs

@@ -1,4 +1,5 @@
 using System.ComponentModel;
+using Hotline.Share.Enums.Order;
 using SqlSugar;
 using XF.Domain.Entities;
 using XF.Domain.Repository;
@@ -6,7 +7,7 @@ using XF.Domain.Repository;
 namespace Hotline.CallCenter.Tels
 {
     [Description("分机休息记录")]
-    public class TelRest : CreationModificationEntity
+    public class TelRest : WorkflowEntity//, CreationModificationEntity
     {
         /// <summary>
         /// 分机id
@@ -33,7 +34,7 @@ namespace Hotline.CallCenter.Tels
         /// 开始休息时间
         /// </summary>
         [SugarColumn(ColumnDescription = "开始休息时间")]
-        public DateTime StartTime { get; init; } = DateTime.Now;
+        public DateTime? StartTime { get; set; }
 
         /// <summary>
         /// 结束休息时间
@@ -47,20 +48,40 @@ namespace Hotline.CallCenter.Tels
         [SugarColumn(ColumnDescription = "休息时长(单位:秒)")]
         public double RestDuration { get; private set; }
 
+        public string Reason { get; set; }
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public ERestApplyStatus ApplyStatus { get; set; }
+
         public TelRest()
         {
 
         }
 
-        public TelRest(string telId, string telNo, string userId, string userName)
+        public TelRest(string telId, string telNo, string userId, string userName,string reason,bool isApply)
         {
-            TelId = telId; TelNo = telNo; UserId = userId; UserName = userName;
+            TelId = telId; TelNo = telNo; UserId = userId; UserName = userName; Reason = reason;
+
+            if(isApply)
+            {
+                ApplyStatus = ERestApplyStatus.NoAudit;
+            }
+            else
+            {
+                ApplyStatus = ERestApplyStatus.Resting;
+                StartTime = DateTime.Now;
+            }
         }
 
+
+        
+
+
         public void EndRest()
         {
             EndTime = DateTime.Now;
-            RestDuration = (EndTime.Value - StartTime).TotalSeconds;
+            RestDuration = (EndTime.Value - StartTime.Value).TotalSeconds;
         }
     }
 }

+ 0 - 1
src/Hotline/CallCenter/Tels/TelRestApply.cs

@@ -9,6 +9,5 @@ namespace Hotline.CallCenter.Tels
 {
     public class TelRestApply: PositionWorkflowEntity
     {
-
     }
 }

+ 2 - 0
src/Hotline/Realtimes/IRealtimeService.cs

@@ -9,5 +9,7 @@ namespace Hotline.Realtimes
         Task AnsweredAsync(string userId, AnsweredDto dto, CancellationToken cancellationToken);
 
         Task ByeAsync(string userId, ByeDto dto, CancellationToken cancellationToken);
+
+        Task RestApplyPassAsync(string userId, CancellationToken cancellationToken);
     }
 }

+ 1 - 1
src/Hotline/Settings/SysDicData.cs

@@ -34,6 +34,6 @@ namespace Hotline.Settings
         public string? ParentId { get; set; }
 
         [SugarColumn(IsIgnore = true)]
-        public List<SysDicData> children { get; set; }
+        public List<SysDicData> Children { get; set; }
     }
 }

+ 5 - 4
src/Hotline/Settings/WorkflowModule.cs

@@ -23,8 +23,7 @@ public class WorkflowModule
         {
             { WorkflowModuleConsts.Order, "工单办理" },
             { WorkflowModuleConsts.KnowledgeAdd, "新增知识审批" },
-            { WorkflowModuleConsts.KnowledgeUpdate, "知识更新" },
-            { WorkflowModuleConsts.KnowledgeDelete, "知识删除" },
+            { WorkflowModuleConsts.TelRestApply,"分机小休申请" },
         };
 }
 
@@ -39,7 +38,9 @@ public class WorkflowModuleConsts
     /// 新增知识审批
     /// </summary>
     public const string KnowledgeAdd = "KnowledgeAdd";
-    public const string KnowledgeUpdate = "KnowledgeUpdate";
-    public const string KnowledgeDelete = "KnowledgeDelete";
 
+    /// <summary>
+    /// 分机小休申请
+    /// </summary>
+    public const string TelRestApply = "TelRestApply";
 }