Ver código fonte

超期短信发送和智能回访状态检测

Dun.Jason 8 meses atrás
pai
commit
5c2d2d3a08

+ 5 - 5
src/Hotline.Api/Controllers/TestController.cs

@@ -92,7 +92,7 @@ namespace Hotline.Api.Controllers;
 public class TestController : BaseController
 {
     private readonly ILogger<TestController> _logger;
-    private readonly IAuthorizeGenerator _authorizeGenerator;
+    //private readonly IAuthorizeGenerator _authorizeGenerator;
     private readonly IOptionsSnapshot<CallCenterConfiguration> _options;
     private readonly ISessionContext _sessionContext;
     private readonly IRepository<User> _userRepository;
@@ -147,9 +147,9 @@ public class TestController : BaseController
 
 
     public TestController(
-        INewRockClient client,
+        //INewRockClient client,
         ILogger<TestController> logger,
-        IAuthorizeGenerator authorizeGenerator,
+        //IAuthorizeGenerator authorizeGenerator,
         IOptionsSnapshot<CallCenterConfiguration> options,
         ISessionContext sessionContext,
         IRepository<User> userRepository,
@@ -198,7 +198,7 @@ ICallApplication callApplication
         )
     {
         _logger = logger;
-        _authorizeGenerator = authorizeGenerator;
+        //_authorizeGenerator = authorizeGenerator;
         _options = options;
         _sessionContext = sessionContext;
         _userRepository = userRepository;
@@ -261,7 +261,7 @@ ICallApplication callApplication
         var result3 = await _repositoryts.SearchAsync(new List<string> { "aa", "bb", "ss" }, HttpContext.RequestAborted);
 
 
-        await _orderDomainService.SendOverTimeSms(HttpContext.RequestAborted);
+        //await _orderDomainService.SendOverTimeSms(HttpContext.RequestAborted);
         //await _repositoryts.UpdateVectorAsync("f595e730-909a-45e4-9138-a84bf15f4662",
         //    new List<string> { "ss", "bb" }, HttpContext.RequestAborted);
 

+ 13 - 4
src/Hotline.Api/StartupHelper.cs

@@ -267,16 +267,25 @@ namespace Hotline.Api
 
                 //即将超期和超期短信
                 var autoSendOverTimeSmsKey = new JobKey(nameof(SendOverTimeSmsJob), "send overtime order task");
-                d.AddJob<SendOverTimeSmsJob>(autoSendOrderKey);
+                d.AddJob<SendOverTimeSmsJob>(autoSendOverTimeSmsKey);
                 d.AddTrigger(t => t
                     .WithIdentity("task-send-overtime-order-trigger")
-                    .ForJob(autoSendOrderKey)
+                    .ForJob(autoSendOverTimeSmsKey)
                     .StartNow()
                     .WithCronSchedule("0 30 09,14 * * ?"));
 
-                switch (appConfiguration.AppScope == AppDefaults.AppScope.YiBin)
+                switch (appConfiguration.AppScope)
                 {
-                    //TODO 智能化任务
+                    //智能化任务
+                    case AppDefaults.AppScope.YiBin:
+                        var aiVisitStatusKey = new JobKey(nameof(CheckAiVisitStateJob), "check aivisit state task");
+                        d.AddJob<CheckAiVisitStateJob>(aiVisitStatusKey);
+                        d.AddTrigger(t => t
+                        .WithIdentity("task-check-aivisit-state-trigger")
+                        .ForJob(aiVisitStatusKey)
+                        .StartNow()
+                        .WithCronSchedule("0 0/5 * * * ? *"));
+                        break;
                     default:
                         break;
                 }

+ 1 - 1
src/Hotline.Api/config/appsettings.Development.json

@@ -1,7 +1,7 @@
 {
   "AllowedHosts": "*",
   "AppConfiguration": {
-    "AppScope": "ZiGong",
+    "AppScope": "YiBin",
     "YiBin": {
       "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
       //智能回访

+ 29 - 0
src/Hotline.Application/Jobs/CheckAiVisitStateJob.cs

@@ -0,0 +1,29 @@
+using Hotline.Orders;
+using Quartz;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Jobs
+{
+    public class CheckAiVisitStateJob : IJob, IDisposable
+    {
+        private readonly IAiVisitDomainService _aiVisitDomainService;
+        public CheckAiVisitStateJob(IAiVisitDomainService aiVisitDomainService)
+        {
+                _aiVisitDomainService = aiVisitDomainService;
+        }
+        public void Dispose()
+        {
+            
+        }
+
+        public async Task Execute(IJobExecutionContext context)
+        {
+            Console.WriteLine($"{nameof(SendOrderJob)} 执行, {DateTime.Now}");
+            await _aiVisitDomainService.OrderVisitStatusService(context.CancellationToken);
+        }
+    }
+}

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

@@ -1067,4 +1067,13 @@ namespace Hotline.Share.Dtos.Order
     {
         public string OrderId { get; set; }
     }
+
+    public class OverTimeOrderDto
+    {
+        public string OrgId { get; set; }
+
+        public int NearlyOrderCount { get; set; }
+
+        public int ExpiredTimeOrderCount { get; set; }
+    }
 }

+ 67 - 0
src/Hotline/Orders/AiVisitDomainService.cs

@@ -0,0 +1,67 @@
+using Hotline.Ai.Visit;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public class AiVisitDomainService : IAiVisitDomainService, IScopeDependency
+    {
+        private readonly IAiVisitService _aiVisitService;
+        private readonly IRepository<AiOrderVisit> _aiOrderVisitRepository;
+        private readonly IRepository<AiOrderVisitDetail> _aiOrderVisitDetailRepository;
+        private readonly IRepository<OrderVisit> _orderVisitRepository;
+
+        public AiVisitDomainService(IAiVisitService aiVisitService,IRepository<AiOrderVisit> aiOrderVisitRepository, IRepository<AiOrderVisitDetail> aiOrderVisitDetailRepository, IRepository<OrderVisit> orderVisitRepository)
+        {
+            _aiVisitService = aiVisitService;
+            _aiOrderVisitRepository = aiOrderVisitRepository;
+            _aiOrderVisitDetailRepository = aiOrderVisitDetailRepository;
+            _orderVisitRepository = orderVisitRepository;
+        }
+
+
+        public async Task OrderVisitStatusService(CancellationToken cancellationToken)
+        {
+            try
+            {
+                var aivisitList = await _aiOrderVisitRepository.Queryable()
+                .Includes(x => x.AiOrderVisitDetails, d => d.OrderVisit).Where(x => x.TaskState == Share.Enums.Ai.EAiOrderVisitTaskState.InProgress).ToListAsync();
+                if (aivisitList != null)
+                {
+                    foreach (var aivisit in aivisitList)
+                    {
+                        foreach (var aivisitDetail in aivisit.AiOrderVisitDetails)
+                        {
+                            if (!string.IsNullOrEmpty(aivisit.BatchUid) && !string.IsNullOrEmpty(aivisitDetail.TaskUid))
+                            {
+                                var res = await _aiVisitService.QueryAiVisitTask(aivisit.BatchUid, aivisitDetail.TaskUid, cancellationToken);
+                                if (res != null && res.Status == 4)
+                                {
+                                    aivisitDetail.AiOrderVisitState = Share.Enums.Ai.EAiOrderVisitState.LoseEfficacy;
+                                    await _aiOrderVisitDetailRepository.UpdateAsync(aivisitDetail, cancellationToken);
+                                    aivisitDetail.OrderVisit.VisitState = Share.Enums.Order.EVisitState.WaitForVisit;
+                                    aivisitDetail.OrderVisit.IsCanAiVisit = true;
+                                    await _orderVisitRepository.UpdateAsync(aivisitDetail.OrderVisit, cancellationToken);
+                                    aivisit.VisitedFailCount++;
+                                    if ((aivisit.VisitedFailCount + aivisit.VisitedCount) == aivisit.HasVisitCount)
+                                    {
+                                        aivisit.TaskState = Share.Enums.Ai.EAiOrderVisitTaskState.Ended;
+                                    }
+                                    await _aiOrderVisitRepository.UpdateAsync(aivisit, cancellationToken);
+                                }
+                            }
+
+                        }
+                    }
+                }
+
+            }
+            catch { }
+        }
+    }
+}

+ 13 - 0
src/Hotline/Orders/IAiVisitDomainService.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Orders
+{
+    public interface IAiVisitDomainService
+    {
+        Task OrderVisitStatusService(CancellationToken cancellationToken);
+    }
+}

+ 39 - 11
src/Hotline/Orders/OrderDomainService.cs

@@ -20,6 +20,10 @@ using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos.FlowEngine;
 using Microsoft.AspNetCore.Http;
 using Hotline.Settings;
+using SqlSugar;
+using Hotline.Push.Notifies;
+using Hotline.Share.Enums.Push;
+using MediatR;
 
 namespace Hotline.Orders;
 
@@ -42,6 +46,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     private readonly IWorkflowDomainService _workflowDomainService;
     private readonly IRepository<Hotspot> _hotspotRepository;
+    private readonly IMediator _mediator;
 
 
     public OrderDomainService(
@@ -62,7 +67,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         ISystemSettingCacheManager systemSettingCacheManager,
         IRepository<Scheduling> schedulingRepository,
         IWorkflowDomainService workflowDomainService,
-        IRepository<Hotspot> hotspotRepository)
+        IRepository<Hotspot> hotspotRepository,
+        IMediator mediator)
     {
         _orderRepository = orderRepository;
         _orderRedoRepository = orderRedoRepository;
@@ -81,6 +87,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         _systemSettingCacheManager = systemSettingCacheManager;
         _workflowDomainService = workflowDomainService;
         _hotspotRepository = hotspotRepository;
+        _mediator = mediator;
     }
 
     public async Task<Order> GetOrderAsync(string? orderId, bool withHotspot = false, bool withAcceptor = false,
@@ -411,17 +418,38 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     {
         var now = DateTime.Now;
         //查询即将超期和超期工单
-        var orderList = await _orderRepository.Queryable().Where(x=>x.NearlyExpiredTime> now && x.Status< EOrderStatus.Filed).ToListAsync(cancellationToken);
-        //即将超期工单
-        var nearlyOrderList = orderList.Where(x => x.NearlyExpiredTime >= now && x.ExpiredTime > now).ToList();
-        nearlyOrderList.GroupBy(x => x.CurrentHandleOrgId).Select(x => new
+        var orderList = await _orderRepository.Queryable()
+            .Where(x=>x.NearlyExpiredTime> now && x.Status< EOrderStatus.Filed && !string.IsNullOrEmpty(x.CurrentHandleOrgId))
+            .GroupBy(x=>x.CurrentHandleOrgId)
+            .Select(x => new OverTimeOrderDto
+            { 
+                 OrgId = x.CurrentHandleOrgId,
+                 NearlyOrderCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.NearlyExpiredTime >= now && x.ExpiredTime > now,1,0)),
+                 ExpiredTimeOrderCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.ExpiredTime>now,1,0))
+            })
+            .ToListAsync(cancellationToken);
+
+        foreach (var item in orderList)
         {
-            OrgId = x.Key,
-            Count = x.Count()
-        });
-
-        //超期工单
-        var expiredOrderList = orderList.Where(x => x.ExpiredTime > now).ToList();
+            //查询部门所有账号
+            var userlist = await _userRepository.Queryable().Where(x =>
+                x.OrgId == item.OrgId && !string.IsNullOrEmpty(x.PhoneNo) &&
+                x.Roles.Any(d => d.Id == "08dae71e-0eca-4bc4-89fe-7eaefae8a98e")).ToListAsync();
+            //发送短信
+            foreach (var user in userlist)
+            {
+                var messageDto = new Share.Dtos.Push.MessageDto
+                {
+                    PushBusiness = EPushBusiness.OrderExpire,
+                    PushPlatform = EPushPlatform.Sms,
+                    Name = user.Name,
+                    TemplateCode = "1009",
+                    Params = new List<string>() { item.NearlyOrderCount.ToString(), item.ExpiredTimeOrderCount.ToString() },
+                    TelNumber = user.PhoneNo,
+                };
+                await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+            }
+        }
     }
 
     #endregion

+ 12 - 4
src/Hotline/dataview.md

@@ -1,5 +1,5 @@
 ### 信件数据查询
-select aaa.*,bbb."SeatVisitResult" from 
+select aaa.*,bbb."SeatVisitResult",ccc."OrgProcessingResults" from 
 (select 
 CASE "ordertemp"."Status"
 	WHEN 500 THEN '已回访'
@@ -83,12 +83,12 @@ CASE "FromGender"
 	ELSE '未知'
 END AS "FromGender" , 
 '-' AS "SeatVisitResult",
-"FirstVisitResult" AS "FirstVisitResult" , 
+'-' AS "NowEvaluate",
 "PushType" AS "PushType" , 
 "Content" AS "Content" , 
 "ActualOpinion" AS "ActualOpinion" ,
 "FileOpinion" AS "FileOpinion" ,
-"Id" AS "SugarNav_Id" FROM "order" ordertemp  WHERE (( "CreationTime" >= '2024-07-17' ) AND ( "CreationTime" < '2024-07-24' ))  AND ( "IsDeleted" = FALSE )ORDER BY "CreationTime" ASC) aaa
+"Id" AS "SugarNav_Id" FROM "order" ordertemp  WHERE (( "CreationTime" >= '2024-07-29' ) AND ( "CreationTime" < '2024-08-10' ))  AND ( "IsDeleted" = FALSE )ORDER BY "CreationTime" ASC) aaa
 left join 
 (select DISTINCT CASE visitdetailtemp."SeatEvaluate"
 	WHEN 0 THEN '默认满意'
@@ -102,7 +102,15 @@ left join
 END AS "SeatVisitResult",visittemp."OrderId" as "OrderId"
  from order_visit visittemp
 left join order_visit_detail visitdetailtemp on visittemp."Id"= visitdetailtemp."VisitId"  
-where visittemp."CreationTime">='2024-07-17' and visitdetailtemp."VisitTarget"=10 AND visittemp."VisitState"=30 ) bbb on aaa."SugarNav_Id"=bbb."OrderId";
+where visittemp."CreationTime">='2024-07-29' and visitdetailtemp."VisitTarget"=10 AND visittemp."VisitState"=30 ) bbb
+on aaa."SugarNav_Id"=bbb."OrderId"
+left join 
+(select DISTINCT
+visitdetailtemptwo."OrgProcessingResults"::JSON->>'Value' as "OrgProcessingResults",visittemptwo."OrderId"
+from order_visit visittemptwo
+left join order_visit_detail visitdetailtemptwo on visittemptwo."Id" = visitdetailtemptwo."VisitId"
+where visittemptwo."CreationTime">='2024-07-29' and visitdetailtemptwo."VisitTarget"=20 AND visittemptwo."VisitState"=30) ccc
+on aaa."SugarNav_Id"=ccc."OrderId";
 
 
 ### 超期件查询