Browse Source

Merge branch 'test' into feature/order_handle_main_secondary

xf 4 months ago
parent
commit
edf71e0715
39 changed files with 950 additions and 266 deletions
  1. 33 3
      src/Hotline.Api/Controllers/Bi/BiCallController.cs
  2. 48 26
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  3. 3 2
      src/Hotline.Api/Controllers/OrderController.cs
  4. 3 2
      src/Hotline.Api/Controllers/TestController.cs
  5. 2 2
      src/Hotline.Api/Program.cs
  6. 6 1
      src/Hotline.Api/StartupExtensions.cs
  7. 10 0
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  8. 1 1
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  9. 3 0
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  10. 1 1
      src/Hotline.Application/Orders/IOrderApplication.cs
  11. 419 116
      src/Hotline.Application/Orders/OrderApplication.cs
  12. 0 40
      src/Hotline.Application/Orders/OrderVisitHandler/OrderVisitUpdateHandler.cs
  13. 1 1
      src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs
  14. 2 2
      src/Hotline.Application/StatisticalReport/CallReport/YiBinCallReportApplication.cs
  15. 1 1
      src/Hotline.Application/StatisticalReport/ICallReportApplication.cs
  16. 4 1
      src/Hotline.Application/StatisticalReport/OrderReportApplication.cs
  17. 44 0
      src/Hotline.Repository.SqlSugar/CallCenter/TrCallRecordRepository.cs
  18. 17 7
      src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs
  19. 165 17
      src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs
  20. 11 1
      src/Hotline.Share/Dtos/CallCenter/BiQueryCallsDto.cs
  21. 0 1
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  22. 3 1
      src/Hotline.Share/Dtos/Kv.cs
  23. 12 2
      src/Hotline.Share/Enums/FlowEngine/EHandleMode.cs
  24. 9 0
      src/Hotline/CallCenter/Calls/ITrCallRecordRepository.cs
  25. 1 1
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  26. 4 0
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  27. 68 0
      src/Hotline/Orders/DatabaseEventHandler/OrderVisitDetailEventHandler.cs
  28. 2 1
      src/Hotline/Orders/IOrderRepository.cs
  29. 0 10
      src/Hotline/Orders/Notifications/UpdateOrderVisitNotify.cs
  30. 0 1
      src/Hotline/Orders/OrderDomainService.cs
  31. 0 1
      src/Hotline/Orders/OrderVisitDomainService.cs
  32. 5 0
      src/Hotline/Settings/SettingConstants.cs
  33. 5 5
      src/Hotline/Statistics/StatisticsDepart.cs
  34. 5 5
      src/Hotline/Statistics/StatisticsDepartSatisfied.cs
  35. 5 5
      src/Hotline/Statistics/StatisticsHotspotSatisfied.cs
  36. 5 5
      src/Hotline/Statistics/StatisticsPurTypeSatisfied.cs
  37. 4 4
      src/Hotline/dataview.md
  38. 35 0
      src/XF.Domain.Repository/Events/DatabaseEventDispatcher.cs
  39. 13 0
      src/XF.Domain.Repository/Events/IUpdateDatabaseEvent.cs

+ 33 - 3
src/Hotline.Api/Controllers/Bi/BiCallController.cs

@@ -636,10 +636,40 @@ public class BiCallController : BaseController
     [HttpGet("query-callout-date-statistics")]
     public async Task<object> QueryCallOutDateStatisticsDetail([FromQuery] QueryCallDateStatisticsDetailDto dto)
     {
-        var list = await _callReportApplication.QueryCallOutDateStatisticsDetail(dto);
-        //return new { List = null, Total = null };
-        return null;
+        List<string> enterpriseTels = _systemSettingCacheManager.GetSetting(SettingConstants.EnterpriseTel)?.SettingValue;
+        var list = await _callReportApplication.QueryCallOutDateStatisticsDetail(dto,enterpriseTels);
 
+        var total = new QueryCallOutDateStatisticsDetailResp()
+        {
+            Date = "合计",
+            PersonCallOutCount = list.Sum(x => x.PersonCallOutCount),
+            EnterpriseCallOutCount = list.Sum(x => x.EnterpriseCallOutCount),
+            AiVisitCallOutCount = list.Sum(x => x.AiVisitCallOutCount),
+            AiCallOutCount = list.Sum(x => x.AiCallOutCount),
+            PersonCallOutPutthroughCount = list.Sum(x => x.PersonCallOutPutthroughCount),
+            EnterpriseCallOutPutthroughCount = list.Sum(x=>x.EnterpriseCallOutPutthroughCount),
+            AiVisitCallOutPutthroughCount = list.Sum(x=>x.AiVisitCallOutPutthroughCount),
+            AiCallOutPutthroughCount = list.Sum(x=>x.AiCallOutPutthroughCount)
+        };
+
+        return new { List = list, Total = total };
+    }
+
+
+    /// <summary>
+    /// 呼出话务统计明细
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("query-callout-date-statistics/export")]
+    public async  Task<FileStreamResult> QueryCallOutDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
+    {
+        List<string> enterpriseTels = _systemSettingCacheManager.GetSetting(SettingConstants.EnterpriseTel)?.SettingValue;
+
+        return _exportApplication.GetExcelFile(
+                dto,
+                await _callReportApplication.QueryCallOutDateStatisticsDetail(dto.QueryDto,enterpriseTels)
+            , "呼出话务统计明细", "Date");
     }
     #endregion
 }

+ 48 - 26
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -34,8 +34,10 @@ using Microsoft.Extensions.Options;
 using Org.BouncyCastle.Utilities.Collections;
 using SqlSugar;
 using System.Data;
+using Hotline.Share.Dtos.WebPortal;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
+using XF.Domain.Filters;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
 
@@ -1401,17 +1403,30 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("seat-satisfaction-statistics-rate")]
         public async Task<SeatSatisfactionStatisticsEvaluateDto> SeatSatisfactionStatisticsRate([FromQuery] PagedKeywordRequest dto)
         {
-            var data = await _orderVisitRepository.Queryable()
-                  .LeftJoin<Order>((ov, o) => ov.OrderId == o.Id)
-                    .Where((ov, o) => ov.VisitTime >= dto.StartTime.Value && ov.VisitTime <= dto.EndTime.Value && ov.VisitState == EVisitState.Visited && o.SeatEvaluate != null
-                    && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && o.SeatEvaluate != ESeatEvaluate.Normal)
-                     .Select((ov, o) => new SeatSatisfactionStatisticsEvaluateDto
-                     {
-                         Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate != ESeatEvaluate.NoSatisfied && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied, 1, 0)),
-                         NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoSatisfied || o.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0))
-                     })
-                     .FirstAsync();
+            var data = await _orderVisitDetailRepository.Queryable()
+               // .Includes(x => x.OrderVisit)
+               .LeftJoin<OrderVisit>((ov, o) => ov.VisitId == o.Id)
+                 .Where((ov, o) => o.VisitTime >= dto.StartTime.Value && o.VisitTime <= dto.EndTime.Value && o.VisitState == EVisitState.Visited
+                 && ov.SeatEvaluate != null && ov.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && ov.SeatEvaluate != ESeatEvaluate.Normal && ov.VisitTarget == EVisitTarget.Seat
+                )
+                 .Select((ov, o) => new SeatSatisfactionStatisticsEvaluateDto
+                 {
+                     Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(ov.SeatEvaluate != ESeatEvaluate.NoSatisfied && ov.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied, 1, 0)),
+                     NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(ov.SeatEvaluate == ESeatEvaluate.NoSatisfied || ov.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0))
+                 })
+                 .FirstAsync();
+            //var data = await _orderVisitRepository.Queryable()
+            //      .LeftJoin<Order>((ov, o) => ov.OrderId == o.Id)
+            //        .Where((ov, o) => ov.VisitTime >= dto.StartTime.Value && ov.VisitTime <= dto.EndTime.Value && ov.VisitState == EVisitState.Visited && o.SeatEvaluate != null
+            //        && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && o.SeatEvaluate != ESeatEvaluate.Normal)
+            //         .Select((ov, o) => new SeatSatisfactionStatisticsEvaluateDto
+            //         {
+            //             Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate != ESeatEvaluate.NoSatisfied && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied, 1, 0)),
+            //             NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoSatisfied || o.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0))
+            //         })
+            //         .FirstAsync();
             return data;
+
         }
 
         /// <summary>
@@ -1492,11 +1507,11 @@ namespace Hotline.Api.Controllers.Bi
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpGet("query-seat-satisfaction-order-visit-list")]
-        public async Task<PagedDto<OrderVisitDto>> QuerySeatSatisfactionOrderVisitList([FromQuery] SeatSatisfactionOrderVisitRequest dto)
+        public async Task<PagedDto<OrderVisitDetailDto>> QuerySeatSatisfactionOrderVisitList([FromQuery] SeatSatisfactionOrderVisitRequest dto)
         {
             var (total, items) = await _orderApplication.QuerySeatSatisfactionOrderVisitList(dto).ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
-            return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
+            return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
         }
 
         /// <summary>
@@ -1526,7 +1541,7 @@ namespace Hotline.Api.Controllers.Bi
         public async Task<FileStreamResult> ExportQuerySeatSatisfactionOrderVisitList([FromBody] ExportExcelDto<SeatSatisfactionOrderVisitRequest> dto)
         {
             var query = _orderApplication.QuerySeatSatisfactionOrderVisitList(dto.QueryDto);
-            List<OrderVisit> orders;
+            List<OrderVisitDetail> orders;
             if (dto.IsExportAll)
             {
                 orders = await query.ToListAsync(HttpContext.RequestAborted);
@@ -1537,12 +1552,12 @@ namespace Hotline.Api.Controllers.Bi
                 orders = items;
             }
 
-            var orderDtos = _mapper.Map<ICollection<OrderVisitDto>>(orders);
+            var orderDtos = _mapper.Map<ICollection<OrderVisitDetailDto>>(orders);
 
             dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
 
             var dtos = orderDtos
-                .Select(stu => _mapper.Map(stu, typeof(OrderVisitDto), dynamicClass))
+                .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass))
                 .Cast<object>()
                 .ToList();
 
@@ -3769,17 +3784,17 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("order_acceptance_time")]
         public async Task<object> OrderAcceptanceTime([FromQuery] TimeSharingPagedKeywordRequest dto)
         {
-            var item = await _orderRepository.OrderAcceptanceTime(dto);
+	        var titleData = await _systemDicDataRepository.Queryable()
+		        .Where(p => p.DicTypeCode == "AcceptType")
+		        .Select(p => new Kv()
+		        {
+			        Key = p.DicDataValue,
+			        Value = p.DicDataName
+		        }).OrderBy(p => p.Key).ToListAsync();
 
-            var titleData = await _systemDicDataRepository.Queryable()
-                .Where(p => p.DicTypeCode == "AcceptType")
-                .Select(p => new
-                {
-                    Key = p.DicDataValue,
-                    Value = p.DicDataName
-                }).ToListAsync();
-
-            return new { Item = item, TitleData = titleData };
+			var item = await _orderRepository.OrderAcceptanceTime(dto);
+			 var res = new  { Item = item, TitleData = titleData };
+			return res;
         }
 
         /// <summary>
@@ -3790,7 +3805,14 @@ namespace Hotline.Api.Controllers.Bi
         [HttpPost("order_acceptance_time_export")]
         public async Task<FileStreamResult> OrderAcceptanceTimeExport([FromBody] TimeSharingPagedKeywordRequest dto)
         {
-            var dataTable = await _orderRepository.OrderAcceptanceTimeExport(dto);
+	        var titleData = await _systemDicDataRepository.Queryable()
+		        .Where(p => p.DicTypeCode == "AcceptType")
+		        .Select(p => new Kv()
+		        {
+			        Key = p.DicDataValue,
+			        Value = p.DicDataName
+		        }).OrderBy(p => p.Key).ToListAsync();
+			var dataTable = await _orderRepository.OrderAcceptanceTimeExport(dto, titleData);
             var stream = ExcelHelper.CreateStream(dataTable);
             return ExcelStreamResult(stream, "受理类型分时统计数据");
         }

+ 3 - 2
src/Hotline.Api/Controllers/OrderController.cs

@@ -5470,7 +5470,6 @@ public class OrderController : BaseController
         }
     }
 
-
     /// <summary>
     /// 工单重办信息
     /// </summary>
@@ -5758,6 +5757,8 @@ public class OrderController : BaseController
 
             await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, order.Status >= EOrderStatus.Filed, EWorkflowTraceType.Recall,
                 HttpContext.RequestAborted);
+
+
             if (order.Status >= EOrderStatus.Filed)
             {
                 var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == special.OrderId);
@@ -7247,7 +7248,7 @@ public class OrderController : BaseController
                     order.AcceptTypeCode = acceptType.DicDataValue;
                     order.SourceChannel = SourceCode.GetDescription();
                     order.SourceChannelCode = ((int)SourceCode).ToString();
-
+                    order.Status = EOrderStatus.Visited;
                     #region 处理数据开始
 
                     // order.Source = SourceCode; //来源

+ 3 - 2
src/Hotline.Api/Controllers/TestController.cs

@@ -519,9 +519,10 @@ ICallApplication callApplication,
         //var r = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToCenter, batchId);
         //var r = _timeLimitDomainService.CalcEndTime(DateTime.Parse("2024-09-12 14:45:47"), Share.Enums.Settings.ETimeType.WorkDay, 2, 80, 50);
         //_capPublisher.PublishDelay((DateTime.Now.AddMinutes(2) - DateTime.Now), EventNames.OrderRelateCall, "123");
-        var times = _expireTime.CalcExpiredTime(DateTime.Parse("2024-12-11 14:45:58"), DateTime.Parse("2024-12-11 14:45:58"), EFlowDirection.CenterToOrg,new OrderTimeClacInfo() { AcceptTypeCode= "20" });
+        //var times = _expireTime.CalcExpiredTime(DateTime.Parse("2024-12-11 14:45:58"), DateTime.Parse("2024-12-11 14:45:58"), EFlowDirection.CenterToOrg,new OrderTimeClacInfo() { AcceptTypeCode= "20" });
+        var times = await _expireTime.CalcWorkTimeToDecimal(DateTime.Parse("2024-12-16 21:36:27"), DateTime.Parse("2024-12-17 12:47:05"), false);
         //await _capPublisher.PublishDelay(EventNames.OrderRelateCall, "123", cancellationToken: HttpContext.RequestAborted);
-        return OpenResponse.Ok(times.Result);
+        return OpenResponse.Ok(times);
     }
 
 

+ 2 - 2
src/Hotline.Api/Program.cs

@@ -38,8 +38,8 @@ try
         .Enrich.FromLogContext()
         .ReadFrom.Configuration(ctx.Configuration), true)
         ;
-
-    builder
+    //builder.Services.AddControllers().AddNewtonsoftJson();
+	builder
         .ConfigureServices()
         .ConfigurePipelines()
         .Run();

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

@@ -40,6 +40,9 @@ using Microsoft.AspNetCore.ResponseCompression;
 using Senparc.Weixin.RegisterServices;
 using Senparc.Weixin.AspNet;
 using Hotline.WeChat;
+using Hotline.Orders;
+using XF.Domain.Repository.Events;
+using Hotline.Orders.DatabaseEventHandler;
 
 
 namespace Hotline.Api;
@@ -184,6 +187,8 @@ internal static class StartupExtensions
                 break;
         }
 
+        //services.AddScoped(typeof(IUpdateDatabase<>), typeof(UpdateDatabase<>));
+        services.AddScoped<IUpdateDatabaseEvent<OrderVisitDetail>, OrderVisitDetailEventHandler>();
 
         //sqlsugar
         services.AddSqlSugar(configuration);
@@ -256,7 +261,7 @@ internal static class StartupExtensions
         //app.UseRequestResponseLogging(app.Configuration);
         
         app.UseResponseCompression();
-        
+
         return app;
     }
 }

+ 10 - 0
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -477,6 +477,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 cancellationToken);
             return new NextStepsDto<NextStepOption>
             {
+                CanReject = startStepDefine.CanReject,
+                CanStartCountersign = startStepDefine.CanStartCountersign,
+                CurrentStepType = startStepDefine.StepType,
+                CurrentHandlerType = startStepDefine.HandlerType,
+                CurrentStepBusinessType = startStepDefine.BusinessType,
                 Steps = new List<NextStepOption> { nextStepOption }
             };
         }
@@ -487,6 +492,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
         return new NextStepsDto<NextStepOption>
         {
+            CanReject = startStepDefine.CanReject,
+            CanStartCountersign = startStepDefine.CanStartCountersign,
+            CurrentStepType = startStepDefine.StepType,
+            CurrentHandlerType = startStepDefine.HandlerType,
+            CurrentStepBusinessType = startStepDefine.BusinessType,
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             Steps = await GetConfigStepsAsync(definition.FlowType, startStepDefine.StepType, startStepDefine.BusinessType,
                 firstStepDefines, cancellationToken)

+ 1 - 1
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -125,7 +125,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId,
                         withExtension: true, cancellationToken: cancellationToken);
                     //order.CheckIfFiled();
-                    order.UpdateHandlingStatus(workflow.IsInCountersign);
+                    //order.UpdateHandlingStatus(workflow.IsInCountersign);
                     _mapper.Map(workflow, order);
                     var now = DateTime.Now;
                     var handleDuration = order.CenterToOrgTime.HasValue && order.ActualHandleTime.HasValue

+ 3 - 0
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -258,8 +258,11 @@ public class OrderMapperConfigs : IRegister
             ;
 
         config.ForType<OrderVisitDetail, OrderFlowVisitDetail>()
+            .IgnoreIf((s, d) => s.OrgProcessingResults == null, d => d.OrgProcessingResults)
             .Map(d => d.OrgProcessingResults, s => s.OrgProcessingResults.Value)
+            .IgnoreIf((s, d) => s.OrgNoSatisfiedReason == null, d => d.OrgNoSatisfiedReason)
             .Map(d => d.OrgNoSatisfiedReason, s => s.OrgNoSatisfiedReason.Select(d => d.Value))
+            .IgnoreIf((s, d) => s.OrgHandledAttitude == null, d => d.OrgHandledAttitude)
             .Map(d => d.OrgHandledAttitude, s => s.OrgHandledAttitude.Value)
             ;
 

+ 1 - 1
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -382,7 +382,7 @@ namespace Hotline.Application.Orders
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        ISugarQueryable<OrderVisit> QuerySeatSatisfactionOrderVisitList(SeatSatisfactionOrderVisitRequest dto);
+        ISugarQueryable<OrderVisitDetail> QuerySeatSatisfactionOrderVisitList(SeatSatisfactionOrderVisitRequest dto);
 
     }
 }

+ 419 - 116
src/Hotline.Application/Orders/OrderApplication.cs

@@ -33,6 +33,7 @@ using Hotline.Share.Enums.Quality;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Mq;
 using Hotline.Share.Requests;
+using Hotline.Statistics;
 using Hotline.Tools;
 using Hotline.Users;
 using Mapster;
@@ -94,6 +95,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
     private readonly IOrderDelayRepository _orderDelayRepository;
     private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
+    private readonly IRepository<SchedulingUser> _schedulingUserRepository;
+    private readonly IRepository<StatisticsHotspotSatisfied> _statisticsHotspotSatisfiedRepository;
+    private readonly IRepository<StatisticsDepartSatisfied> _statisticsDepartSatisfiedRepository;
 
     public OrderApplication(
         IOrderDomainService orderDomainService,
@@ -133,6 +137,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IOrderTerminateRepository orderTerminateRepository,
         IRepository<OrderPublishHistory> orderPublishHistoryRepository,
         IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository,
+        IRepository<SchedulingUser> schedulingUserRepository,
+        IRepository<StatisticsHotspotSatisfied> statisticsHotspotSatisfiedRepository,
+        IRepository<StatisticsDepartSatisfied> statisticsDepartSatisfiedRepository,
         IOrderDelayRepository orderDelayRepository)
     {
         _orderDomainService = orderDomainService;
@@ -173,6 +180,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _sessionContext = sessionContext;
         _orderDelayRepository = orderDelayRepository;
         _orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
+        _schedulingUserRepository = schedulingUserRepository;
+        _statisticsHotspotSatisfiedRepository = statisticsHotspotSatisfiedRepository;
+        _statisticsDepartSatisfiedRepository = statisticsDepartSatisfiedRepository;
+
     }
 
     /// <summary>
@@ -1191,7 +1202,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         await _workflowDomainService.HandleVisitTraceAsync(visit.Id, visitor, visit.VisitTime ?? DateTime.Now, cancellationToken);
 
         var orderDto = _mapper.Map<OrderDto>(visit.Order);
-        await _publisher.PublishAsync(new UpdateOrderVisitNotify(visit.Adapt<OrderVisitNotifyDto>()), cancellationToken);
         if (first != null)
         {
             //推省上
@@ -1768,8 +1778,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto)
     {
         bool IsCenter = _sessionContextProvider.SessionContext.OrgIsCenter;
-        int orgLevel = _sessionContextProvider.SessionContext.OrgLevel;
-        string orgLevelStr = ((orgLevel + 1) * 3).ToString();
+        var orgLevel = _sessionContextProvider.SessionContext.OrgLevel;
+        string orgLevelStr = (_sessionContextProvider.SessionContext.RequiredOrgId.Length + 3).ToString();
+
         var list = _orderVisitDetailRepository.Queryable()
             .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value &&
                         x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
@@ -1781,6 +1792,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.VisitType != null, x => x.OrderVisit.VisitType == dto.VisitType);
 
         var data = new List<VisitAndOrgSatisfactionStatisticsDto>();
+        var oldData = new List<VisitAndOrgSatisfactionStatisticsDto>();
 
         if (IsCenter && list != null)
         {
@@ -1837,11 +1849,11 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         {
             data = await list.GroupBy(x => new
             {
-                VisitOrgCode = x.VisitOrgCode//.Substring(SqlFunc.MappingColumn<int>("0"),SqlFunc.MappingColumn<int>(orgLevelStr))
+                VisitOrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr))
             })
                 .Select(x => new VisitAndOrgSatisfactionStatisticsDto()
                 {
-                    OrgCode = x.VisitOrgCode,//.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr)),
+                    OrgCode = x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr)),
                     TotalSumCount =
                         SqlFunc.AggregateCount(x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr))),
                     VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
@@ -1885,6 +1897,103 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .ToListAsync();
         }
 
+        #region 老系统数据
+        if (await _statisticsDepartSatisfiedRepository.Queryable().Where(x => x.Time >= dto.StartTime.Value && x.Time <= dto.EndTime.Value).AnyAsync())
+        {
+            var query = _statisticsDepartSatisfiedRepository.Queryable()
+                .LeftJoin<SystemOrganize>((x, so) => x.DepartmentId == so.oldBmid)
+                .WhereIF(IsCenter == false, (x, so) => so.Id.StartsWith(_sessionContextProvider.SessionContext.OrgId))
+                .Where((x, so) => x.Time >= dto.StartTime.Value && x.Time <= dto.EndTime.Value);
+            if (IsCenter)
+            {
+                oldData = await query.GroupBy((x, so) => new
+                {
+                    VisitOrgCode = so.Id.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6"))
+                }).Select((x, so) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgCode = so.Id.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                    TotalSumCount = SqlFunc.AggregateSum(x.Total),
+                    VerySatisfiedCount = SqlFunc.AggregateSum(x.VerySatisfaction), //非常满意数
+                    SatisfiedCount = SqlFunc.AggregateSum(x.Satisfaction), //满意数
+                    RegardedAsSatisfiedCount = SqlFunc.AggregateSum(x.TreatSatisfaction), //视为满意
+                    DefaultSatisfiedCount = SqlFunc.AggregateSum(x.DefaultSatisfaction), //默认满意
+                    NoSatisfiedCount = SqlFunc.AggregateSum(x.Dissatisfaction), //不满意
+                    NoEvaluateCount = SqlFunc.AggregateSum(x.NotEvaluated), //未做评价
+                    NoPutThroughCount = SqlFunc.AggregateSum(x.BlockCall), //未接通
+                })
+                .MergeTable()
+                .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
+                .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgName = o.Name,
+                    OrgCode = it.OrgCode,
+                    OrgType = o.OrgType,
+                    TotalSumCount = it.TotalSumCount,
+                    VerySatisfiedCount = it.VerySatisfiedCount, //非常满意数
+                    SatisfiedCount = it.SatisfiedCount, //满意数
+                    RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount, //视为满意
+                    DefaultSatisfiedCount = it.DefaultSatisfiedCount, //默认满意
+                    NoSatisfiedCount = it.NoSatisfiedCount, //不满意
+                    NoEvaluateCount = it.NoEvaluateCount, //未做评价
+                    NoPutThroughCount = it.NoPutThroughCount, //未接通
+                })
+                .ToListAsync(); ;
+
+            }
+            else
+            {
+                oldData = await query.GroupBy((x, so) => new
+                {
+                    VisitOrgCode = so.Id
+                }).Select((x, so) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgCode = so.Id,//.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr)),
+                    TotalSumCount = SqlFunc.AggregateSum(x.Total),
+                    VerySatisfiedCount = SqlFunc.AggregateSum(x.VerySatisfaction), //非常满意数
+                    SatisfiedCount = SqlFunc.AggregateSum(x.Satisfaction), //满意数
+                    RegardedAsSatisfiedCount = SqlFunc.AggregateSum(x.TreatSatisfaction), //视为满意
+                    DefaultSatisfiedCount = SqlFunc.AggregateSum(x.DefaultSatisfaction), //默认满意
+                    NoSatisfiedCount = SqlFunc.AggregateSum(x.Dissatisfaction), //不满意
+                    NoEvaluateCount = SqlFunc.AggregateSum(x.NotEvaluated), //未做评价
+                    NoPutThroughCount = SqlFunc.AggregateSum(x.BlockCall), //未接通
+                })
+                .MergeTable().LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id && (o.Level == orgLevel || o.Level == (orgLevel + 1)))
+                .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgName = o.Name,
+                    OrgCode = it.OrgCode,
+                    OrgType = o.OrgType,
+                    TotalSumCount = it.TotalSumCount,
+                    VerySatisfiedCount = it.VerySatisfiedCount, //非常满意数
+                    SatisfiedCount = it.SatisfiedCount, //满意数
+                    RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount, //视为满意
+                    DefaultSatisfiedCount = it.DefaultSatisfiedCount, //默认满意
+                    NoSatisfiedCount = it.NoSatisfiedCount, //不满意
+                    NoEvaluateCount = it.NoEvaluateCount, //未做评价
+                    NoPutThroughCount = it.NoPutThroughCount, //未接通
+                })
+                .ToListAsync();
+            }
+            data = (from t1 in data
+                    join t2 in oldData on t1.OrgCode equals t2.OrgCode into t1_t2
+                    from item in t1_t2.DefaultIfEmpty()
+                    select new VisitAndOrgSatisfactionStatisticsDto()
+                    {
+                        OrgName = t1.OrgName,
+                        OrgCode = t1.OrgCode,
+                        OrgType = t1.OrgType,
+                        TotalSumCount = t1.TotalSumCount + t1_t2.Select(x => x.TotalSumCount).FirstOrDefault(),
+                        VerySatisfiedCount = t1.VerySatisfiedCount + t1_t2.Select(x => x.VerySatisfiedCount).FirstOrDefault(),//非常满意数
+                        SatisfiedCount = t1.SatisfiedCount + t1_t2.Select(x => x.SatisfiedCount).FirstOrDefault(), //满意数
+                        RegardedAsSatisfiedCount = t1.RegardedAsSatisfiedCount + t1_t2.Select(x => x.RegardedAsSatisfiedCount).FirstOrDefault(), //视为满意
+                        DefaultSatisfiedCount = t1.DefaultSatisfiedCount + t1_t2.Select(x => x.DefaultSatisfiedCount).FirstOrDefault(), //默认满意
+                        NoSatisfiedCount = t1.NoSatisfiedCount + t1_t2.Select(x => x.NoSatisfiedCount).FirstOrDefault(), //不满意
+                        NoEvaluateCount = t1.NoEvaluateCount + t1_t2.Select(x => x.NoEvaluateCount).FirstOrDefault(), //未做评价
+                        NoPutThroughCount = t1.NoPutThroughCount + t1_t2.Select(x => x.NoPutThroughCount).FirstOrDefault(), //未接通
+                    }).ToList();
+        }
+        #endregion
+
         return data;
     }
 
@@ -1895,50 +2004,67 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto)
     {
         bool IsCenter = _sessionContextProvider.SessionContext.OrgIsCenter;
+        var org = await _systemOrganizeRepository.Queryable().FirstAsync(x => x.Id == dto.OrgCode);
+
+        string orgLevelStr = (dto.OrgCode.Length + 3).ToString();
+        var oldData = new List<VisitAndOrgSatisfactionStatisticsDto>();
 
-        var list = await _systemOrganizeRepository.Queryable().Where(x => x.Id.StartsWith(dto.OrgCode))
+        var quer = _systemOrganizeRepository.Queryable().Where(x => x.Id.StartsWith(dto.OrgCode))
             .LeftJoin<OrderVisitDetail>((x, it) => x.Id == it.VisitOrgCode)
-            .Where((x, it) => it.OrderVisit.VisitTime >= dto.StartTime.Value && it.OrderVisit.VisitTime <= dto.EndTime.Value &&
+            .Where((x, it) => it.OrderVisit.VisitTime >= dto.StartTime.Value &&
+                              it.OrderVisit.VisitTime <= dto.EndTime.Value &&
                               it.VisitTarget == EVisitTarget.Org && it.OrderVisit.VisitState == EVisitState.Visited)
             .WhereIF(dto.OrgCode == "001", (x, it) => it.VisitOrgCode == dto.OrgCode)
             .WhereIF(dto.OrgCode != "001", (x, it) => it.VisitOrgCode.StartsWith(dto.OrgCode))
-            .WhereIF(!string.IsNullOrEmpty(dto.LineNum), (x, it) => it.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
-            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
-            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
-            .WhereIF(IsCenter == false, (x, it) => it.VisitOrgCode.StartsWith(_sessionContextProvider.SessionContext.OrgId))
+            .WhereIF(!string.IsNullOrEmpty(dto.LineNum),
+                (x, it) => it.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1,
+                (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2,
+                (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(IsCenter == false,
+                (x, it) => it.VisitOrgCode.StartsWith(_sessionContextProvider.SessionContext.OrgId))
             .WhereIF(dto.VisitType != null, (x, it) => it.OrderVisit.VisitType == dto.VisitType)
             .GroupBy((x, it) => new
             {
-                VisitOrgCode = it.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("9"))
+                VisitOrgCode = it.VisitOrgCode
             })
             .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
             {
-                OrgCode = it.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("9")),
-                TotalSumCount = SqlFunc.AggregateCount(it.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("9"))),
+                OrgCode = it.VisitOrgCode,
+                TotalSumCount = SqlFunc.AggregateCount(it.VisitOrgCode),
                 VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "5", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "5", 1, 0))), //非常满意数
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "5", 1,
+                        0))), //非常满意数
                 SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "4", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "4", 1,
+                        0))), //满意数
                 RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "-1", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "-1", 1, 0))), //视为满意
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "-1", 1,
+                        0))), //视为满意
                 DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "0", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "0", 1, 0))), //默认满意
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "0", 1,
+                        0))), //默认满意
                 NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "2", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "2", 1, 0))), //不满意
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "2", 1,
+                        0))), //不满意
                 NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "7", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "7", 1, 0))), //未做评价
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "7", 1,
+                        0))), //未做评价
                 NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1,
                     SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgProcessingResults, "Key") == "6", 1, 0)),
-                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "6", 1, 0))) //未接通
+                    SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(it.OrgHandledAttitude, "Key") == "6", 1,
+                        0))) //未接通
             })
             .MergeTable()
-            .LeftJoin<SystemOrganize>((x, it) => x.OrgCode == it.Id)
+            .LeftJoin<SystemOrganize>((x, it) =>
+                x.OrgCode == it.Id && (it.Level == org.Level || it.Level == (org.Level + 1)))
             .Select((x, it) => new VisitAndOrgSatisfactionStatisticsDto()
             {
                 OrgName = it.Name,
@@ -1952,8 +2078,68 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 NoSatisfiedCount = x.NoSatisfiedCount, //不满意
                 NoEvaluateCount = x.NoEvaluateCount, //未做评价
                 NoPutThroughCount = x.NoPutThroughCount, //未接通
+            });
+        var list = await quer.ToListAsync();
+
+        #region 老系统数据
+        if (await _statisticsDepartSatisfiedRepository.Queryable().Where(x => x.Time >= dto.StartTime.Value && x.Time <= dto.EndTime.Value).AnyAsync())
+        {
+            var query = _statisticsDepartSatisfiedRepository.Queryable()
+                .LeftJoin<SystemOrganize>((x, so) => x.DepartmentId == so.oldBmid)
+                .WhereIF(dto.OrgCode == "001", (x, so) => so.Id == dto.OrgCode)
+                .WhereIF(dto.OrgCode != "001", (x, so) => so.Id.StartsWith(dto.OrgCode))
+                .Where((x, so) => x.Time >= dto.StartTime.Value && x.Time <= dto.EndTime.Value);
+
+            oldData = await query.GroupBy((x, so) => new
+            {
+                VisitOrgCode = so.Id
+            }).Select((x, so) => new VisitAndOrgSatisfactionStatisticsDto()
+            {
+                OrgCode = so.Id,//.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>(orgLevelStr)),
+                TotalSumCount = SqlFunc.AggregateSum(x.Total),
+                VerySatisfiedCount = SqlFunc.AggregateSum(x.VerySatisfaction), //非常满意数
+                SatisfiedCount = SqlFunc.AggregateSum(x.Satisfaction), //满意数
+                RegardedAsSatisfiedCount = SqlFunc.AggregateSum(x.TreatSatisfaction), //视为满意
+                DefaultSatisfiedCount = SqlFunc.AggregateSum(x.DefaultSatisfaction), //默认满意
+                NoSatisfiedCount = SqlFunc.AggregateSum(x.Dissatisfaction), //不满意
+                NoEvaluateCount = SqlFunc.AggregateSum(x.NotEvaluated), //未做评价
+                NoPutThroughCount = SqlFunc.AggregateSum(x.BlockCall), //未接通
             })
-            .ToListAsync();
+                .MergeTable().LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id && (o.Level == org.Level || o.Level == (org.Level + 1)))
+                .Select((it, o) => new VisitAndOrgSatisfactionStatisticsDto()
+                {
+                    OrgName = o.Name,
+                    OrgCode = it.OrgCode,
+                    OrgType = o.OrgType,
+                    TotalSumCount = it.TotalSumCount,
+                    VerySatisfiedCount = it.VerySatisfiedCount, //非常满意数
+                    SatisfiedCount = it.SatisfiedCount, //满意数
+                    RegardedAsSatisfiedCount = it.RegardedAsSatisfiedCount, //视为满意
+                    DefaultSatisfiedCount = it.DefaultSatisfiedCount, //默认满意
+                    NoSatisfiedCount = it.NoSatisfiedCount, //不满意
+                    NoEvaluateCount = it.NoEvaluateCount, //未做评价
+                    NoPutThroughCount = it.NoPutThroughCount, //未接通
+                })
+                .ToListAsync();
+            list = (from t1 in list
+                    join t2 in oldData on t1.OrgCode equals t2.OrgCode into t1_t2
+                    from item in t1_t2.DefaultIfEmpty()
+                    select new VisitAndOrgSatisfactionStatisticsDto()
+                    {
+                        OrgName = t1.OrgName,
+                        OrgCode = t1.OrgCode,
+                        OrgType = t1.OrgType,
+                        TotalSumCount = t1.TotalSumCount + t1_t2.Select(x => x.TotalSumCount).FirstOrDefault(),
+                        VerySatisfiedCount = t1.VerySatisfiedCount + t1_t2.Select(x => x.VerySatisfiedCount).FirstOrDefault(),//非常满意数
+                        SatisfiedCount = t1.SatisfiedCount + t1_t2.Select(x => x.SatisfiedCount).FirstOrDefault(), //满意数
+                        RegardedAsSatisfiedCount = t1.RegardedAsSatisfiedCount + t1_t2.Select(x => x.RegardedAsSatisfiedCount).FirstOrDefault(), //视为满意
+                        DefaultSatisfiedCount = t1.DefaultSatisfiedCount + t1_t2.Select(x => x.DefaultSatisfiedCount).FirstOrDefault(), //默认满意
+                        NoSatisfiedCount = t1.NoSatisfiedCount + t1_t2.Select(x => x.NoSatisfiedCount).FirstOrDefault(), //不满意
+                        NoEvaluateCount = t1.NoEvaluateCount + t1_t2.Select(x => x.NoEvaluateCount).FirstOrDefault(), //未做评价
+                        NoPutThroughCount = t1.NoPutThroughCount + t1_t2.Select(x => x.NoPutThroughCount).FirstOrDefault(), //未接通
+                    }).ToList();
+        }
+        #endregion
         return list;
     }
 
@@ -2349,6 +2535,50 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .ToListAsync();
         }
 
+        //老系统数据
+        if (await _statisticsHotspotSatisfiedRepository.Queryable().Where(x => x.Time >= dto.StartTime.Value && x.Time <= dto.EndTime.Value).AnyAsync())
+        {
+            var oldList = await _statisticsHotspotSatisfiedRepository.Queryable()
+                 .InnerJoin<Hotspot>((x, h) =>
+                     h.Id == x.HotspotId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("2")) &&
+                     h.ParentId == null)
+                .GroupBy((x, h) => new
+                {
+                    HotspotName = h.HotSpotName,
+                    HotspotId = h.Id
+                })
+                .Select((x, h) => new VisitAndHotspotSatisfactionStatisticsDto()
+                {
+                    HotspotName = h.HotSpotName,
+                    HotspotId = h.Id,
+                    TotalSumCount = SqlFunc.AggregateSum(x.Total),
+                    VerySatisfiedCount = SqlFunc.AggregateSum(x.VerySatisfaction), //非常满意数
+                    SatisfiedCount = SqlFunc.AggregateSum(x.Satisfaction), //满意数
+                    RegardedAsSatisfiedCount = SqlFunc.AggregateSum(x.TreatSatisfaction), //视为满意
+                    DefaultSatisfiedCount = SqlFunc.AggregateSum(x.DefaultSatisfaction), //默认满意
+                    NoSatisfiedCount = SqlFunc.AggregateSum(x.Dissatisfaction), //不满意
+                    NoEvaluateCount = SqlFunc.AggregateSum(x.NotEvaluated), //未做评价
+                    NoPutThroughCount = SqlFunc.AggregateSum(x.BlockCall), //未接通
+                })
+                .ToListAsync();
+
+            data = (from t1 in data
+                    join t2 in oldList on t1.HotspotId equals t2.HotspotId into t1_t2
+                    from item in t1_t2.DefaultIfEmpty()
+                    select new VisitAndHotspotSatisfactionStatisticsDto()
+                    {
+                        HotspotName = t1.HotspotName,
+                        HotspotId = t1.HotspotId,
+                        TotalSumCount = t1.TotalSumCount + t1_t2.Select(x => x.TotalSumCount).FirstOrDefault(),
+                        VerySatisfiedCount = t1.VerySatisfiedCount + t1_t2.Select(x => x.VerySatisfiedCount).FirstOrDefault(),//非常满意数
+                        SatisfiedCount = t1.SatisfiedCount + t1_t2.Select(x => x.SatisfiedCount).FirstOrDefault(), //满意数
+                        RegardedAsSatisfiedCount = t1.RegardedAsSatisfiedCount + t1_t2.Select(x => x.RegardedAsSatisfiedCount).FirstOrDefault(), //视为满意
+                        DefaultSatisfiedCount = t1.DefaultSatisfiedCount + t1_t2.Select(x => x.DefaultSatisfiedCount).FirstOrDefault(), //默认满意
+                        NoSatisfiedCount = t1.NoSatisfiedCount + t1_t2.Select(x => x.NoSatisfiedCount).FirstOrDefault(), //不满意
+                        NoEvaluateCount = t1.NoEvaluateCount + t1_t2.Select(x => x.NoEvaluateCount).FirstOrDefault(), //未做评价
+                        NoPutThroughCount = t1.NoPutThroughCount + t1_t2.Select(x => x.NoPutThroughCount).FirstOrDefault(), //未接通
+                    }).ToList();
+        }
         return data;
     }
 
@@ -3030,17 +3260,30 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<SeatSatisfactionStatisticsDto> SeatSatisfactionStatistics(PagedKeywordRequest dto)
     {
-        var list = _orderVisitRepository.Queryable()
-               .Includes(d => d.Order)
-               .Where(x => x.VisitTime >= dto.StartTime.Value && x.VisitTime <= dto.EndTime.Value && x.VisitState == EVisitState.Visited && x.Order.SeatEvaluate != null
-               && x.Order.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && x.Order.SeatEvaluate != ESeatEvaluate.Normal)
-               .GroupBy(x => x.Order.SeatEvaluate)
-               .Select(x => new SeatSatisfactionStatisticsDto
-               {
-                   SeatEvaluate = x.Order.SeatEvaluate,
-                   Count = SqlFunc.AggregateCount(x.Id)
-               });
+        var list = _orderVisitDetailRepository.Queryable()
+            .Includes(d => d.OrderVisit)
+             .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value && x.OrderVisit.VisitState == EVisitState.Visited
+             && x.SeatEvaluate != null && x.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && x.SeatEvaluate != ESeatEvaluate.Normal && x.VisitTarget == EVisitTarget.Seat
+            )
+             .GroupBy(x => x.SeatEvaluate)
+             .Select(x => new SeatSatisfactionStatisticsDto
+             {
+                 SeatEvaluate = x.SeatEvaluate,
+                 Count = SqlFunc.AggregateCount(x.Id)
+             });
         return list;
+
+        //var list = _orderVisitRepository.Queryable()
+        //       .Includes(d => d.Order)
+        //       .Where(x => x.VisitTime >= dto.StartTime.Value && x.VisitTime <= dto.EndTime.Value && x.VisitState == EVisitState.Visited && x.Order.SeatEvaluate != null
+        //       && x.Order.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && x.Order.SeatEvaluate != ESeatEvaluate.Normal)
+        //       .GroupBy(x => x.Order.SeatEvaluate)
+        //       .Select(x => new SeatSatisfactionStatisticsDto
+        //       {
+        //           SeatEvaluate = x.Order.SeatEvaluate,
+        //           Count = SqlFunc.AggregateCount(x.Id)
+        //       });
+        //return list;
     }
 
     /// <summary>
@@ -3050,29 +3293,55 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<SeatSatisfactionStatisticsListDetailDto> SeatSatisfactionStatisticsListDetail(PagedKeywordRequest dto)
     {
-        var query = _orderVisitRepository.Queryable()
-                 .LeftJoin<Order>((ov, o) => ov.OrderId == o.Id)
-                 .Where((ov, o) => ov.VisitTime >= dto.StartTime.Value && ov.VisitTime <= dto.EndTime.Value && ov.VisitState == EVisitState.Visited && o.SeatEvaluate != null
-                 && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && o.SeatEvaluate != ESeatEvaluate.Normal)
-                 .GroupBy((ov, o) => new
-                 {
-                     o.AcceptorName,
-                     o.AcceptorId
-                 })
-                 .Select((ov, o) => new SeatSatisfactionStatisticsListDetailDto
+        var query = _orderVisitDetailRepository.Queryable()
+            .LeftJoin<OrderVisit>((od, ov) => od.VisitId == ov.Id)
+            .LeftJoin<Order>((od, ov, o) => ov.OrderId == o.Id)
+             //.Includes(d => d.OrderVisit)
+             //.Includes(d => d.OrderVisit, d => d.Order)
+             .Where((od, ov, o) => ov.VisitTime >= dto.StartTime.Value && ov.VisitTime <= dto.EndTime.Value && ov.VisitState == EVisitState.Visited
+                && od.SeatEvaluate != null && od.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && od.SeatEvaluate != ESeatEvaluate.Normal && od.VisitTarget == EVisitTarget.Seat)
+              .GroupBy((od, ov, o) => new
+              {
+                  o.AcceptorName,
+                  o.AcceptorId
+              })
+                 .Select((od, ov, o) => new SeatSatisfactionStatisticsListDetailDto
                  {
                      UserName = o.AcceptorName,
                      UserId = o.AcceptorId,
-                     DefaultSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.DefaultSatisfied, 1, 0)),
-                     VeryNoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0)),
-                     NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoSatisfied, 1, 0)),
-                     Normal = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.Normal, 1, 0)),
-                     Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.Satisfied, 1, 0)),
-                     VerySatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.VerySatisfied, 1, 0)),
-                     NoConnect = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoConnect, 1, 0)),
-                     NoEvaluate = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoEvaluate, 1, 0))
+                     DefaultSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.DefaultSatisfied, 1, 0)),
+                     VeryNoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0)),
+                     NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.NoSatisfied, 1, 0)),
+                     Normal = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.Normal, 1, 0)),
+                     Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.Satisfied, 1, 0)),
+                     VerySatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.VerySatisfied, 1, 0)),
+                     NoConnect = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.NoConnect, 1, 0)),
+                     NoEvaluate = SqlFunc.AggregateSum(SqlFunc.IIF(od.SeatEvaluate == ESeatEvaluate.NoEvaluate, 1, 0))
                  });
         return query;
+        //var query = _orderVisitRepository.Queryable()
+        //         .LeftJoin<Order>((ov, o) => ov.OrderId == o.Id)
+        //         .Where((ov, o) => ov.VisitTime >= dto.StartTime.Value && ov.VisitTime <= dto.EndTime.Value && ov.VisitState == EVisitState.Visited && o.SeatEvaluate != null
+        //         && o.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && o.SeatEvaluate != ESeatEvaluate.Normal)
+        //         .GroupBy((ov, o) => new
+        //         {
+        //             o.AcceptorName,
+        //             o.AcceptorId
+        //         })
+        //         .Select((ov, o) => new SeatSatisfactionStatisticsListDetailDto
+        //         {
+        //             UserName = o.AcceptorName,
+        //             UserId = o.AcceptorId,
+        //             DefaultSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.DefaultSatisfied, 1, 0)),
+        //             VeryNoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied, 1, 0)),
+        //             NoSatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoSatisfied, 1, 0)),
+        //             Normal = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.Normal, 1, 0)),
+        //             Satisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.Satisfied, 1, 0)),
+        //             VerySatisfied = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.VerySatisfied, 1, 0)),
+        //             NoConnect = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoConnect, 1, 0)),
+        //             NoEvaluate = SqlFunc.AggregateSum(SqlFunc.IIF(o.SeatEvaluate == ESeatEvaluate.NoEvaluate, 1, 0))
+        //         });
+        //return query;
     }
 
     /// <summary>
@@ -3080,21 +3349,37 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    public ISugarQueryable<OrderVisit> QuerySeatSatisfactionOrderVisitList(SeatSatisfactionOrderVisitRequest dto)
+    public ISugarQueryable<OrderVisitDetail> QuerySeatSatisfactionOrderVisitList(SeatSatisfactionOrderVisitRequest dto)
     {
-        var query = _orderVisitRepository.Queryable()
-            .Includes(d => d.Order)
-            .Includes(d => d.Employee)
-            .Includes(d => d.OrderVisitDetails)
-           .Where(p => p.VisitTime >= dto.StartTime.Value && p.VisitTime <= dto.EndTime.Value && p.VisitState == EVisitState.Visited && p.Order.SeatEvaluate != null
-           && p.Order.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && p.Order.SeatEvaluate != ESeatEvaluate.Normal)
-           .WhereIF(!string.IsNullOrEmpty(dto.UserId), p => p.Order.AcceptorId == dto.UserId)
-           .WhereIF(dto.SeatEvaluate.HasValue, p => p.Order.SeatEvaluate == dto.SeatEvaluate)
-           .WhereIF(!string.IsNullOrEmpty(dto.UserName), p => p.Order.AcceptorName == dto.UserName)
-           .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title.Contains(dto.Title))
-           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No.Contains(dto.No))
-            .OrderByDescending(p => p.VisitTime);
+        var query = _orderVisitDetailRepository.Queryable()
+              .Includes(x => x.OrderVisit, d => d.Order)
+              .Includes(x => x.OrderVisit, d => d.Employee)
+              .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value
+                  && x.OrderVisit.VisitState == EVisitState.Visited && x.SeatEvaluate != null
+                  && x.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && x.SeatEvaluate != ESeatEvaluate.Normal && x.VisitTarget == EVisitTarget.Seat)
+                 .WhereIF(!string.IsNullOrEmpty(dto.UserId), x => x.OrderVisit.Order.AcceptorId == dto.UserId)
+               .WhereIF(dto.SeatEvaluate.HasValue, x => x.SeatEvaluate == dto.SeatEvaluate)
+               .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.OrderVisit.Order.AcceptorName == dto.UserName)
+               .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order.Title.Contains(dto.Title))
+               .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order.No.Contains(dto.No))
+            .OrderByDescending(x => x.OrderVisit.VisitTime);
         return query;
+        //var query = _orderVisitRepository.Queryable()
+        //    .Includes(d => d.Order)
+        //    .Includes(d => d.Employee)
+        //    .Includes(d => d.OrderVisitDetails)
+        //   .Where(p => p.VisitTime >= dto.StartTime.Value && p.VisitTime <= dto.EndTime.Value && p.VisitState == EVisitState.Visited && p.Order.SeatEvaluate != null
+        //   && p.Order.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied && p.Order.SeatEvaluate != ESeatEvaluate.Normal)
+
+
+
+        //   .WhereIF(!string.IsNullOrEmpty(dto.UserId), p => p.Order.AcceptorId == dto.UserId)
+        //   .WhereIF(dto.SeatEvaluate.HasValue, p => p.Order.SeatEvaluate == dto.SeatEvaluate)
+        //   .WhereIF(!string.IsNullOrEmpty(dto.UserName), p => p.Order.AcceptorName == dto.UserName)
+        //   .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title.Contains(dto.Title))
+        //   .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No.Contains(dto.No))
+        //    .OrderByDescending(p => p.VisitTime);
+        //return query;
     }
 
     #region private
@@ -3302,15 +3587,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 SendOrderNum = 0,
                 NoSendOrderNum = SqlFunc.AggregateDistinctCount(w.ExternalId),
             });
-        var items = await itemsHandled.LeftJoin(itemsNo, (hand, nohand) => hand.UserId == nohand.UserId)
-            .GroupBy((hand, nohand) => new { hand.UserId, hand.UserName })
-            .Select((hand, nohand) => new BiOrderSendVo
-            {
-                UserId = hand.UserId,
-                UserName = hand.UserName,
+        var items = await _schedulingUserRepository.Queryable()
+            .LeftJoin(itemsHandled, (all, hand) => all.UserId == hand.UserId)
+            .LeftJoin(itemsNo, (all, hand, nohand) => hand.UserId == nohand.UserId)
+            .GroupBy((all, hand, nohand) => new { all.UserId, all.UserName })
+            .Select((all, hand, nohand) => new BiOrderSendVo
+            {
+                UserId = all.UserId,
+                UserName = all.UserName,
                 SendOrderNum = SqlFunc.AggregateSum(hand.SendOrderNum),
                 NoSendOrderNum = SqlFunc.AggregateSum(nohand.NoSendOrderNum),
-            }).ToListAsync();
+            }).MergeTable().Where(vo => vo.SendOrderNum > 0 || vo.NoSendOrderNum > 0).ToListAsync();
 
         var items2 = await _workflowTraceRepository.Queryable()
             .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
@@ -3450,12 +3737,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 
     public ISugarQueryable<Order> QueryWaitedForSeat(QueryOrderWaitedDto dto)
     {
-        EOrderStatus[] handleStatuses = EnumExts.GetFields<EOrderStatus>().Select(d => (EOrderStatus)d.Key).ToArray();
-        handleStatuses = handleStatuses.WhereIF(dto.IsHandled.HasValue,
-                d => dto.IsHandled!.Value
-                    ? d is not EOrderStatus.WaitForAccept and not EOrderStatus.BackToUnAccept and not EOrderStatus.SpecialToUnAccept and not EOrderStatus.HandOverToUnAccept
-                    : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept or EOrderStatus.HandOverToUnAccept or EOrderStatus.Handling)
-            .ToArray();
+        //EOrderStatus[] handleStatuses = EnumExts.GetFields<EOrderStatus>().Select(d => (EOrderStatus)d.Key).ToArray();
+        //handleStatuses = handleStatuses.WhereIF(dto.IsHandled.HasValue,
+        //        d => dto.IsHandled!.Value
+        //            ? d is not EOrderStatus.WaitForAccept and not EOrderStatus.BackToUnAccept and not EOrderStatus.SpecialToUnAccept and not EOrderStatus.HandOverToUnAccept
+        //            : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept or EOrderStatus.HandOverToUnAccept or EOrderStatus.Handling
+        //            or EOrderStatus.Countersigning)
+        //    .ToArray();
 
         //var query = _orderRepository.Queryable()
         //    .Includes(d => d.WorkflowSteps.Where(step =>
@@ -3470,41 +3758,57 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         //    );
         var query = _orderRepository.Queryable();
 
-        var hasHandled = dto.IsHandled.HasValue && dto.IsHandled.Value;
-        if (hasHandled)
+        switch (dto.TypeCode)
         {
-            query.Includes(d => d.WorkflowSteps.Where(step =>
-                    !string.IsNullOrEmpty(step.HandlerId)
-                    && step.HandlerId == _sessionContext.UserId
-                    && step.Status == EWorkflowStepStatus.Handled
-                ))
-                .Where(d => d.WorkflowSteps
-                    .Any(step =>
+            case 0://待办
+                query.Includes(d => d.WorkflowSteps.Where(step =>
+                            ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+                             (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                             (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)) ||
+                             (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)
+                              && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId)))
+                        .OrderByDescending(step => step.CreationTime)
+                        .Take(1)
+                        .ToList())
+                    .Where(d => d.WorkflowSteps
+                                    .Any(step =>
+                                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+                                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)) ||
+                                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)
+                                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
+                                        && step.Status < EWorkflowStepStatus.Handled)
+                                || (SqlFunc.IsNullOrEmpty(d.WorkflowId) && SqlFunc.IsNullOrEmpty(d.SignerId)
+                                    || (!SqlFunc.IsNullOrEmpty(d.SignerId) && d.SignerId == _sessionContext.UserId))
+                    )
+                    .Where(d => d.Status < EOrderStatus.Filed
+                        && (d.Status <= EOrderStatus.HandOverToUnAccept
+                        || d.Status == EOrderStatus.Handling//指派给班长再指派回坐席时
+                        || d.Status == EOrderStatus.Countersigning//跨级派单业务如发起会签再回到坐席会签汇总时
+                        ))
+                    ;
+
+                break;
+            case 1://交办: 已派单其他节点的工单,该选项卡下工单若办结就不显示
+                query.Includes(d => d.WorkflowSteps.Where(step =>
                         !string.IsNullOrEmpty(step.HandlerId)
                         && step.HandlerId == _sessionContext.UserId
-                        && step.Status == EWorkflowStepStatus.Handled));
+                        && step.Status == EWorkflowStepStatus.Handled
+                    ).ToList())
+                    .Where(d => d.WorkflowSteps
+                        .Any(step =>
+                            !string.IsNullOrEmpty(step.HandlerId)
+                            && step.HandlerId == _sessionContext.UserId
+                            && step.Status == EWorkflowStepStatus.Handled)
+                    && d.Status < EOrderStatus.Filed);
+                break;
+            case 2://办结: 当前登录坐席作为最初受理人已办结的工单
+                query.Where(d =>
+                    d.Status >= EOrderStatus.Filed
+                    && d.AcceptorId == _sessionContextProvider.SessionContext.RequiredUserId);
+                break;
         }
-        else
-        {
 
-            query.Includes(d => d.WorkflowSteps.Where(step =>
-                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)) ||
-                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)
-                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId)))
-                    .OrderByDescending(step => step.CreationTime)
-                    .Take(1)
-                    .ToList())
-                .Where(d => d.WorkflowSteps
-                .Any(step =>
-                    ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-                     (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-                     (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)) ||
-                     (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)
-                      && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
-                    && step.Status < EWorkflowStepStatus.Handled));
-        }
 
         //query = query.Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
         //.Where(step => step.ExternalId == d.Id &&
@@ -3517,14 +3821,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         //    (string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContextProvider.SessionContext.RequiredUserId))
         //);
 
-
         return query
-            // 交办件:已派单其他节点的工单,该选项卡下工单若办结就不显示
-            .WhereIF(dto.TypeCode.HasValue == true && dto.TypeCode == 1, d => d.ProcessType == EProcessType.Jiaoban && d.Status < EOrderStatus.Filed)
-            // 办结件:当前登录坐席作为最初受理人已办结的工单
-            .WhereIF(dto.TypeCode.HasValue == true && dto.TypeCode == 2, d => d.Status >= EOrderStatus.Filed && d.AcceptorId == _sessionContextProvider.SessionContext.RequiredUserId)
+            //// 交办件:已派单其他节点的工单,该选项卡下工单若办结就不显示
+            //.WhereIF(dto.TypeCode.HasValue == true && dto.TypeCode == 1, d => /*d.ProcessType == EProcessType.Jiaoban &&*/ d.Status < EOrderStatus.Filed)
+            //// 办结件:当前登录坐席作为最初受理人已办结的工单
+            //.WhereIF(dto.TypeCode.HasValue == true && dto.TypeCode == 2, d => d.Status >= EOrderStatus.Filed && d.AcceptorId == _sessionContextProvider.SessionContext.RequiredUserId)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
-            .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
+            //.WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!))
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
             .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode)
@@ -3542,13 +3845,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
             .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
             .Where(x => x.Status != EOrderStatus.BackToProvince)
-            .WhereIF(dto.TypeCode.HasValue == false, m => m.Status < EOrderStatus.Filed)
+            //.WhereIF(dto.TypeCode.HasValue == false, m => m.Status < EOrderStatus.Filed)
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.AcceptorName == dto.AcceptorName)
              //.OrderBy(d => d.Status)
-             .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
+             .OrderByIF(dto.TypeCode != 0, d => d.StartTime, OrderByType.Desc)
             //.OrderByIF(dto.IsHandled == false, d => new { IsUrgent = d.IsUrgent }, OrderByType.Desc)
             //.OrderByIF(dto.IsHandled == false, d => new { d.Status })
-            .OrderByIF(dto.IsHandled == false && string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc)
+            .OrderByIF(dto.TypeCode == 0 && string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc)
             .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.CreationTime, OrderByType.Asc) //创建时间升序
             .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, d => d.CreationTime, OrderByType.Desc) //创建时间降序
             .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序

+ 0 - 40
src/Hotline.Application/Orders/OrderVisitHandler/OrderVisitUpdateHandler.cs

@@ -1,40 +0,0 @@
-using DotNetCore.CAP;
-using Hotline.Application.Quality;
-using Hotline.Orders;
-using Hotline.Orders.Notifications;
-using Hotline.Share.Dtos.Order;
-using Hotline.Share.Enums.Order;
-using Hotline.Share.Enums.Quality;
-using Hotline.Users;
-using Mapster;
-using MediatR;
-using XF.Domain.Repository;
-
-namespace Hotline.Application.Orders.OrderVisitHandler;
-public class OrderVisitUpdateHandler : INotificationHandler<UpdateOrderVisitNotify>
-{
-    private readonly IOrderRepository _orderRepository;
-    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
-
-    public OrderVisitUpdateHandler(IOrderRepository orderRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository)
-    {
-        _orderRepository = orderRepository;
-        _orderVisitDetailRepository = orderVisitDetailRepository;
-    }
-
-    public async Task Handle(UpdateOrderVisitNotify notification, CancellationToken cancellationToken)
-    {
-        var visit = notification.orderVisit;
-
-        var orgDetail = await _orderVisitDetailRepository.Queryable()
-            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org).FirstAsync(cancellationToken);
-        var seatDetail = await _orderVisitDetailRepository.Queryable()
-            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Seat).FirstAsync(cancellationToken);
-
-        await _orderRepository.Updateable()
-            .SetColumns(m => m.OrgProcessingResults == orgDetail.OrgProcessingResults)
-            .SetColumns(m => m.SeatEvaluate == seatDetail.SeatEvaluate)
-            .Where(m => m.Id == visit.OrderId)
-            .ExecuteCommandAsync(cancellationToken);
-    }
-}

+ 1 - 1
src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs

@@ -262,7 +262,7 @@ public abstract class CallReportApplicationBase : ICallReportApplication
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    public virtual Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
+    public virtual Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto, List<string> enterpriseTels)
     {
         throw new NotImplementedException();
     }

+ 2 - 2
src/Hotline.Application/StatisticalReport/CallReport/YiBinCallReportApplication.cs

@@ -285,9 +285,9 @@ public class YiBinCallReportApplication : CallReportApplicationBase, ICallReport
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    public override async Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto)
+    public override async Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto,List<string> enterpriseTels)
     {
-        return null;
+        return await _trCallRecordRepositoryEx.QueryCallOutDateStatisticsDetail(dto.StartTime.Value, dto.EndTime.Value,enterpriseTels);
     }
 
 

+ 1 - 1
src/Hotline.Application/StatisticalReport/ICallReportApplication.cs

@@ -75,6 +75,6 @@ namespace Hotline.Application.StatisticalReport
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto);
+        Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(QueryCallDateStatisticsDetailDto dto,List<string> enterpriseTels);
     }
 }

+ 4 - 1
src/Hotline.Application/StatisticalReport/OrderReportApplication.cs

@@ -33,6 +33,7 @@ using Hotline.Share.Dtos;
 using Hotline.Share.Tools;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
+using Hotline.SeedData;
 
 namespace Hotline.Application.StatisticalReport
 {
@@ -1754,7 +1755,9 @@ namespace Hotline.Application.StatisticalReport
                 .Where(x => SqlFunc.JsonListObjectAny(x.OrgNoSatisfiedReason, "Key", dto.DissatisfiedKey))
                 .WhereIF(dto.VisitOrgName.NotNullOrEmpty(), x => x.VisitOrgName.Contains(dto.VisitOrgName))
                 .WhereIF(IsCenter == false, x => x.VisitOrgCode.StartsWith(_sessionContext.RequiredOrgId))
-                .WhereIF(IsCenter == true, x => x.VisitOrgCode.StartsWith(dto.OrgCode))
+                // .WhereIF(IsCenter == true, x => x.VisitOrgCode.StartsWith(dto.OrgCode))
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == OrgSeedData.CenterId, x => x.VisitOrgCode == dto.OrgCode)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode != OrgSeedData.CenterId, x => x.VisitOrgCode.StartsWith(dto.OrgCode))
                 .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.No.Contains(dto.Keyword) || x.OrderVisit.Order.Title.Contains(dto.Keyword))
                 .WhereIF(!string.IsNullOrEmpty(dto.OrgProcessingResults), x => SqlFunc.JsonListObjectAny(x.OrgProcessingResults, "Key", dto.OrgProcessingResults))
                 .OrderBy(x => x.OrderVisit.VisitTime);

+ 44 - 0
src/Hotline.Repository.SqlSugar/CallCenter/TrCallRecordRepository.cs

@@ -1,10 +1,13 @@
 using Hotline.CallCenter.Calls;
+using Hotline.Orders;
 using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.CallCenter;
 using SqlSugar;
 using XF.Domain.Dependency;
+using static System.Runtime.InteropServices.JavaScript.JSType;
 
 namespace Hotline.Repository.SqlSugar.CallCenter
 {
@@ -295,6 +298,7 @@ namespace Hotline.Repository.SqlSugar.CallCenter
                 .Select(x => new QueryCallDateStatisticsDetailResp()
                 {
                     Date = x.CreatedTime.ToString("yyyy-MM-dd"),
+                    IvrCallInTotal = SqlFunc.AggregateSum(SqlFunc.IIF(x.BeginIvrTime.HasValue && !x.BeginQueueTime.HasValue && !x.BeginRingTime.HasValue && x.OnState == EOnState.NoOn, 1, 0)), //IVR挂断
                     PersonCallInCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.IvrDtmf.Substring(x.IvrDtmf.Length - 1, 1) == "1", 1, 0)),
                     EnterpriseCallInCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.IvrDtmf.Substring(x.IvrDtmf.Length - 1, 1) == "2", 1, 0)),
                     AiCallInCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.Gateway == "82826886", 1, 0)),
@@ -344,5 +348,45 @@ namespace Hotline.Repository.SqlSugar.CallCenter
                 .OrderBy(x => x.Date);
             return await query.ToListAsync();
         }
+
+        public async Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(DateTime startTime,DateTime endTime,List<string> enterpriseTels)
+        {
+            var callTable = Db.Queryable<TrCallRecord>()
+                .Where(x => x.CreatedTime >= startTime && x.CreatedTime <= endTime && SqlFunc.Length(x.Gateway) > 4 && x.CallDirection == ECallDirection.Out && SqlFunc.Length(x.TelNo)==4)
+                .GroupBy(x => x.CreatedTime.ToString("yyyy-MM-dd"))
+                .Select(x => new QueryCallOutDateStatisticsDetailResp()
+                {
+                    Date = x.CreatedTime.ToString("yyyy-MM-dd"),
+                    PersonCallOutCount = SqlFunc.AggregateSum(SqlFunc.IIF(1 == 1 && !enterpriseTels.Contains(x.TelNo),1,0)),
+                    EnterpriseCallOutCount = SqlFunc.AggregateSum(SqlFunc.IIF(1== 1 && enterpriseTels.Contains(x.TelNo),1,0)),
+                    PersonCallOutPutthroughCount = SqlFunc.AggregateSum(SqlFunc.IIF(!enterpriseTels.Contains(x.TelNo) && x.OnState == EOnState.On, 1, 0)),
+                    EnterpriseCallOutPutthroughCount = SqlFunc.AggregateSum(SqlFunc.IIF(enterpriseTels.Contains(x.TelNo) && x.OnState == EOnState.On, 1, 0)),
+                }).MergeTable();
+
+            var aiVisitCallTable =  Db.Queryable<AiOrderVisitDetail>()
+                .Where(x => x.CallTime >= startTime && x.CallTime <= endTime)
+                .GroupBy(x => x.CallTime.Value.ToString("yyyy-MM-dd"))
+                .Select(x => new QueryCallOutDateStatisticsDetailResp()
+                {
+                    Date = x.CallTime.Value.ToString("yyyy-MM-dd"),
+                    AiVisitCallOutCount = SqlFunc.AggregateCount(x.Id),
+                    AiVisitCallOutPutthroughCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.AiIsContact!=null || x.AiVolved!=null || x.AiOrgProcessingResults != null ,1,0))
+                }).MergeTable();
+
+            var list = await callTable.LeftJoin(aiVisitCallTable, (a, b) => a.Date == b.Date)
+                .Select((a, b) => new QueryCallOutDateStatisticsDetailResp()
+                {
+                    Date = a.Date,
+                    PersonCallOutCount = a.PersonCallOutCount,
+                    EnterpriseCallOutCount = a.EnterpriseCallOutCount,
+                    AiVisitCallOutCount = b.AiVisitCallOutCount,
+                    AiCallOutCount = 0,
+                    PersonCallOutPutthroughCount= a.PersonCallOutPutthroughCount,
+                    EnterpriseCallOutPutthroughCount = a.EnterpriseCallOutPutthroughCount,
+                    AiVisitCallOutPutthroughCount = b.AiVisitCallOutPutthroughCount,
+                    AiCallOutPutthroughCount = 0,
+                }).ToListAsync();
+            return list;
+        }
     }
 }

+ 17 - 7
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs

@@ -1,4 +1,5 @@
-using System.Collections;
+using System;
+using System.Collections;
 using System.ComponentModel;
 using System.ComponentModel.DataAnnotations;
 using System.Diagnostics;
@@ -9,7 +10,9 @@ using System.Text.Encodings.Web;
 using System.Text.Json;
 using System.Text.RegularExpressions;
 using System.Text.Unicode;
+using Hotline.Share.Tools;
 using Hotline.Users;
+using Microsoft.AspNetCore.Builder;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Serilog;
@@ -18,6 +21,7 @@ using XF.Domain.Entities;
 using XF.Domain.Extensions;
 using XF.Domain.Options;
 using XF.Domain.Repository;
+using XF.Domain.Repository.Events;
 using XF.Utility.SequentialId;
 
 namespace Hotline.Repository.SqlSugar.Extensions
@@ -26,6 +30,7 @@ namespace Hotline.Repository.SqlSugar.Extensions
     {
         public static void AddSqlSugar(this IServiceCollection services, IConfiguration configuration, string dbName = "Hotline")
         {
+            services.AddScoped<DatabaseEventDispatcher>();
             //多租户 new SqlSugarScope(List<ConnectionConfig>,db=>{});
 
             SqlSugarScope sqlSugar = new SqlSugarScope(new ConnectionConfig()
@@ -115,7 +120,10 @@ namespace Hotline.Repository.SqlSugar.Extensions
                     PgSqlIsAutoToLowerCodeFirst = false, // 建表建驼峰表。5.1.3.30 
                 }
             },
-                SetDbAop
+                db => 
+                {
+                    SetDbAop(db, services);
+                }
             );
 
             ISugarUnitOfWork<HotlineDbContext> context = new SugarUnitOfWork<HotlineDbContext>(sqlSugar);
@@ -204,7 +212,7 @@ namespace Hotline.Repository.SqlSugar.Extensions
 
         #region private
 
-        private static void SetDbAop(SqlSugarClient db)
+        private static void SetDbAop(SqlSugarClient db, IServiceCollection services)
         {
             /***写AOP等方法***/
             db.Aop.OnLogExecuting = (sql, pars) =>
@@ -262,13 +270,15 @@ namespace Hotline.Repository.SqlSugar.Extensions
             {
                 if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.OperationType == DataFilterType.UpdateByObject)
                 {
-                    var entityName = entityInfo.EntityName;
-                    Console.WriteLine(entityName);
+                    services.BuildServiceProvider()
+                    .GetService<DatabaseEventDispatcher>()?
+                    .Dispatch(entityInfo.EntityValue, entityInfo.OperationType);
                 }
                 if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.OperationType == DataFilterType.InsertByObject)
                 {
-                    var entityName = entityInfo.EntityName;
-                    Console.WriteLine(entityName);
+                    services.BuildServiceProvider()
+                    .GetService<DatabaseEventDispatcher>()?
+                    .Dispatch(entityInfo.EntityValue, entityInfo.OperationType);
                 }
             };
 

+ 165 - 17
src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs

@@ -1,4 +1,5 @@
-using Hotline.CallCenter.Calls;
+using System.Collections;
+using Hotline.CallCenter.Calls;
 using Hotline.Orders;
 using Hotline.Repository.SqlSugar.DataPermissions;
 using Hotline.Repository.SqlSugar.Extensions;
@@ -25,6 +26,11 @@ using XF.Domain.Dependency;
 using XF.Domain.Repository;
 using System.Collections.Generic;
 using Hotline.SeedData;
+using Hotline.Share.Notifications.NewRockCallCenter;
+using Hotline.Statistics;
+using System.Dynamic;
+using Hotline.Share.Dtos;
+using Org.BouncyCastle.Crypto.Fpe;
 
 namespace Hotline.Repository.SqlSugar.Orders
 {
@@ -370,7 +376,7 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <param name="dto"></param>
         /// <returns></returns>
         public async Task<DataTable> OrderHotspotTimeExport(TimeSharingPagedKeywordRequest dto)
-        {
+		{
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
             {
@@ -423,7 +429,7 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <param name="dto"></param>
         /// <returns></returns>
         public async Task<object> OrderAcceptanceTime(TimeSharingPagedKeywordRequest dto)
-        {
+		{
             List<int> dts = new List<int>();
             for (int i = 0; i < 24; i++)
             {
@@ -444,7 +450,7 @@ namespace Hotline.Repository.SqlSugar.Orders
 
             var listOrg = Db.Queryable<SystemDicData>()
               .LeftJoin(listOrder, (s, p) => s.DicDataValue == p.AcceptTypeCode)
-              .Where((s, p) => s.DicTypeCode == "AcceptType")
+			  .Where((s, p) => s.DicTypeCode == "AcceptType")
               .GroupBy((s, p) => s.DicDataValue).GroupBy((s, p) => s.DicDataName)
               .GroupBy((s, p) => p.Hour)
               .OrderBy((s, p) => s.DicDataValue)
@@ -458,24 +464,103 @@ namespace Hotline.Repository.SqlSugar.Orders
               .MergeTable();
 
             var list = await listHour.LeftJoin(listOrg, (x, p) => x.ColumnName.ToString() == p.Hour)
-                .OrderBy(x => x.ColumnName)
+	            //.Where((x,p)=> !string.IsNullOrEmpty(p.DicDataValue))
+	            .OrderBy((x,p) =>  x.ColumnName )
                .Select((x, p) => new
                {
                    Hour = x.ColumnName.ToString() + ":00 - " + x.ColumnName.ToString() + ":59",
                    p.DicDataValue,
                    p.count
                })
-                .ToPivotListAsync(p => p.DicDataValue, p => p.Hour, p => p.Sum(x => x.count));
-            return list;
+	            .MergeTable()
+               .ToPivotTableAsync(p => p.DicDataValue, p => p.Hour, p =>  p.Sum(x => x.count));
 
-        }
+            var col = list.Columns.Contains("Column1");
+            if (col)
+            {
+				list.Columns.Remove("Column1");
+			}
+            var dtList = list.Clone();
 
-        /// <summary>
-        /// 受理类型分时统计---导出
-        /// </summary>
-        /// <param name="dto"></param>
-        /// <returns></returns>
-        public async Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto)
+			if (await Db.Queryable<StatisticsPurTypeSatisfied>().Where(x => x.Time >= dto.StartTime && x.Time <= dto.EndTime).AnyAsync())
+            {
+				// 老系统数据
+				var oldData = await Db.Queryable<StatisticsPurTypeSatisfied>()
+                    .Where(x => x.Time >= dto.StartTime && x.Time <= dto.EndTime)
+                    .GroupBy(x => x.Month)
+                    .Select(x => new
+                    {
+						Hour = x.Month.ToString() + ":00 - " + x.Month.ToString() + ":59",
+						_1 = SqlFunc.AggregateSum(x.Opinion),
+                        _2 = SqlFunc.AggregateSum(x.PeopleHelp),
+                        _3 = SqlFunc.AggregateSum(x.PollutionReporting),
+                        _10 = SqlFunc.AggregateSum(x.Consult),
+                        _15 = SqlFunc.AggregateSum(x.Suggest),
+                        _20 = SqlFunc.AggregateSum(x.SeekHelp),
+                        _25 = SqlFunc.AggregateSum(x.Praise),
+                        _30 = SqlFunc.AggregateSum(x.Report),
+                        _35 = SqlFunc.AggregateSum(x.Complaint),
+                        _40 = SqlFunc.AggregateSum(x.Rests) + SqlFunc.AggregateSum(x.Invalid),
+                        _50 = SqlFunc.AggregateSum(x.Epidemic),
+                        _SB = SqlFunc.AggregateSum(x.Declare),
+                    }).ToDataTableAsync();
+
+				#region  处理数据
+
+				foreach (DataColumn column in dtList.Columns)
+				{
+					if (column.ColumnName != "Hour") column.DataType = typeof(Int64);
+				}
+
+				for (int i = 0; i < list.Rows.Count; i++)
+				{
+					DataRow newRow = dtList.NewRow();
+					for (int j = 0; j < list.Columns.Count; j++)
+					{
+						if (oldData.Columns[j].ColumnName == "Hour")
+						{
+							newRow[j] = list.Rows[i][j];
+						}
+						else
+						{
+							var num = string.IsNullOrEmpty(list.Rows[i][j].ToString()) ? 0 : int.Parse(list.Rows[i][j].ToString());
+							var oldRow = oldData.Select("Hour ='" + list.Rows[i]["Hour"] + "'").FirstOrDefault();
+                            var oldColName = "_" + dtList.Columns[j].ColumnName;
+                            var allNum = oldRow == null ? num : oldRow.Field<Int64>(oldColName) + num;
+							newRow[j] = allNum;
+						}
+					}
+					dtList.Rows.Add(newRow);
+				}
+
+				#endregion
+			}
+			return ToDynamicList(dtList);
+        }
+		public static List<dynamic> ToDynamicList( DataTable dt)
+		{
+			List<dynamic> dynamicList = new List<dynamic>();
+
+			foreach (DataRow row in dt.Rows)
+			{
+				dynamic dynamicObj = new ExpandoObject();
+				var expandoDict = (IDictionary<string, object>)dynamicObj;
+				foreach (DataColumn column in dt.Columns)
+				{
+					expandoDict[column.ColumnName] = row[column];
+				}
+				dynamicList.Add(dynamicObj);
+			}
+
+			return dynamicList;
+		}
+
+		/// <summary>
+		/// 受理类型分时统计---导出
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		public async Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto, List<Kv> title)
         {
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
@@ -510,7 +595,7 @@ namespace Hotline.Repository.SqlSugar.Orders
               })
               .MergeTable();
 
-            var dt = await listHour.LeftJoin(listOrg, (x, p) => x.ColumnName.ToString() == p.Hour)
+            var list = await listHour.LeftJoin(listOrg, (x, p) => x.ColumnName.ToString() == p.Hour)
                .OrderBy(x => x.ColumnName)
               .Select((x, p) => new
               {
@@ -519,8 +604,71 @@ namespace Hotline.Repository.SqlSugar.Orders
                   p.count
               })
                .ToPivotTableAsync(p => p.DicDataName, p => p.Hour, p => p.Sum(x => x.count));
-
-            return InitDatatTable(dt, dto.AddColumnName);
+			var dtList = list.Clone();
+
+			if (await Db.Queryable<StatisticsPurTypeSatisfied>().Where(x => x.Time >= dto.StartTime && x.Time <= dto.EndTime).AnyAsync())
+			{
+				// 老系统数据
+				var oldData = await Db.Queryable<StatisticsPurTypeSatisfied>()
+					.Where(x => x.Time >= dto.StartTime && x.Time <= dto.EndTime)
+					.GroupBy(x => x.Month)
+					.Select(x => new
+					{
+						Hour = x.Month.ToString() + ":00 - " + x.Month.ToString() + ":59",
+						_1 = SqlFunc.AggregateSum(x.Opinion),
+						_2 = SqlFunc.AggregateSum(x.PeopleHelp),
+						_3 = SqlFunc.AggregateSum(x.PollutionReporting),
+						_10 = SqlFunc.AggregateSum(x.Consult),
+						_15 = SqlFunc.AggregateSum(x.Suggest),
+						_20 = SqlFunc.AggregateSum(x.SeekHelp),
+						_25 = SqlFunc.AggregateSum(x.Praise),
+						_30 = SqlFunc.AggregateSum(x.Report),
+						_35 = SqlFunc.AggregateSum(x.Complaint),
+						_40 = SqlFunc.AggregateSum(x.Rests) + SqlFunc.AggregateSum(x.Invalid),
+						_50 = SqlFunc.AggregateSum(x.Epidemic),
+						_SB = SqlFunc.AggregateSum(x.Declare),
+					}).ToDataTableAsync();
+
+				#region  处理数据
+
+				foreach (var item in title)
+				{
+					var isColumn = oldData.Columns.Contains("_"+item.Key);
+					if (isColumn)
+					{
+						oldData.Columns["_" + item.Key].ColumnName = item.Value;
+					}
+				}
+
+				foreach (DataColumn col in dtList.Columns)
+				{
+					if (col.ColumnName != "Hour") col.DataType = typeof(Int64);
+				}
+
+				for (int i = 0; i < list.Rows.Count; i++)
+				{
+					DataRow newRow = dtList.NewRow();
+					for (int j = 0; j < list.Columns.Count; j++)
+					{
+						if (oldData.Columns[j].ColumnName == "Hour")
+						{
+							newRow[j] = list.Rows[i][j];
+						}
+						else
+						{
+							var num = string.IsNullOrEmpty(list.Rows[i][j].ToString()) ? 0 : int.Parse(list.Rows[i][j].ToString());
+							var oldRow = oldData.Select("Hour ='"+ list.Rows[i]["Hour"] + "'").FirstOrDefault();
+							//var oldColName = "_" + dtList.Columns[j].ColumnName;
+							var allNum = oldRow == null ? num : oldRow.Field<Int64>(dtList.Columns[j].ColumnName) + num;
+							newRow[j] = allNum;
+						}
+					}
+					dtList.Rows.Add(newRow);
+				}
+
+				#endregion
+			}
+			return InitDatatTable(dtList, dto.AddColumnName);
         }
 
         /// <summary>

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

@@ -456,26 +456,36 @@ public class QueryCallOutDateStatisticsDetailResp
     /// </summary>
     public double CallOutPutthroughRate => CallOutTotal == 0 ? 0 : Math.Round(((double)CallOutPutthroughCount / CallOutTotal) * 100, 2);
 
-    
+    public string CallOutPutthroughRateText => CallOutPutthroughRate + "%";
+
     /// <summary>
     /// 个人服务呼出接通率
     /// </summary>
     public double PersonCallOutPutthroughRate => PersonCallOutCount == 0 ? 0 : Math.Round(((double)PersonCallOutPutthroughCount / PersonCallOutCount) * 100, 2);
 
+    public string PersonCallOutPutthroughRateText => PersonCallOutPutthroughRate + "%";
+
     /// <summary>
     /// 企业服务呼出接通率
     /// </summary>
     public double EnterpriseCallOutPutthroughRate => EnterpriseCallOutCount == 0 ? 0 : Math.Round(((double)EnterpriseCallOutPutthroughCount / EnterpriseCallOutCount) * 100, 2);
 
+
+    public string EnterpriseCallOutPutthroughRateText => EnterpriseCallOutPutthroughRate + "%";
+
     /// <summary>
     /// 智能回访呼出接通率
     /// </summary>
     public double AiVisitCallOutPutthroughRate => AiVisitCallOutCount == 0 ? 0 : Math.Round(((double)AiVisitCallOutPutthroughCount / AiVisitCallOutCount) * 100, 2);
 
+    public string AiVisitCallOutPutthroughRatetext => AiVisitCallOutPutthroughRate + "%";
+
     /// <summary>
     /// 智能外呼呼出接通率
     /// </summary>
     public double AiCallOutPutthroughRate => AiCallOutCount == 0 ? 0 : Math.Round(((double)AiCallOutPutthroughCount / AiCallOutCount) * 100, 2);
+
+    public string AiCallOutPutthroughRateText => AiCallOutPutthroughRate + "%";
 }
 
 #endregion

+ 0 - 1
src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs

@@ -23,7 +23,6 @@ public class NextStepsDto
     /// </summary>
     public bool CanStartCountersign { get; set; }
 
-
     /// <summary>
     /// 是否显示主办对象
     /// </summary>

+ 3 - 1
src/Hotline.Share/Dtos/Kv.cs

@@ -1,4 +1,6 @@
-namespace Hotline.Share.Dtos;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Hotline.Share.Dtos;
 
 public class Kv
 {

+ 12 - 2
src/Hotline.Share/Enums/FlowEngine/EHandleMode.cs

@@ -7,14 +7,24 @@ namespace Hotline.Share.Enums.FlowEngine;
 /// </summary>
 public enum EHandleMode
 {
-    //tdo 按地市配置显示文字
-
     /// <summary>
     /// 正常办理
     /// </summary>
     [Description("正常")]
     Normal = 0,
 
+    /// <summary>
+    /// 审核通过(审批流程特有)
+    /// </summary>
+    [Description("审核通过")]
+    Approved = 20,
+
+    /// <summary>
+    /// 审核不通过(审批流程特有)
+    /// </summary>
+    [Description("审核不通过")]
+    NotApproved = 21,
+
     /// <summary>
     /// 退回
     /// </summary>

+ 9 - 0
src/Hotline/CallCenter/Calls/ITrCallRecordRepository.cs

@@ -59,5 +59,14 @@ namespace Hotline.CallCenter.Calls
         /// <param name="endTime"></param>
         /// <returns></returns>
         Task<List<QueryEnterpriseCallDateStatisticsDetailResp>> QueryEnterpriseCallDateStatisticsDetail(DateTime startTime, DateTime endTime);
+
+
+        /// <summary>
+        /// 呼出话务统计明细
+        /// </summary>
+        /// <param name="startTime"></param>
+        /// <param name="endTime"></param>
+        /// <returns></returns>
+        Task<List<QueryCallOutDateStatisticsDetailResp>> QueryCallOutDateStatisticsDetail(DateTime startTime, DateTime endTime, List<string> enterpriseTels);
     }
 }

+ 1 - 1
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -247,7 +247,7 @@ public abstract class StepBasicEntity : CreationEntity
     /// <summary>
     /// 办理方式
     /// </summary>
-    public EHandleMode? HandleMode { get; set; } = EHandleMode.Normal;
+    public EHandleMode? HandleMode { get; set; }
 
     /// <summary>
     /// 审核结果(非审批流程无意义)

+ 4 - 0
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -2074,6 +2074,10 @@ namespace Hotline.FlowEngine.Workflows
             step.Opinion = dto.Opinion;
             step.Remark = dto.Remark;
             step.ReviewResult = dto.ReviewResult;
+            if (workflow.FlowType is EFlowType.Review)
+                step.HandleMode = dto.ReviewResult == EReviewResult.Approval
+                    ? EHandleMode.Approved
+                    : EHandleMode.NotApproved;
 
             //step办理状态
             HandleStep(step, handleMode, dto.Opinion, dto.NextStepCode);

+ 68 - 0
src/Hotline/Orders/DatabaseEventHandler/OrderVisitDetailEventHandler.cs

@@ -0,0 +1,68 @@
+using Hotline.Settings;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using XF.Domain.Repository;
+using XF.Domain.Repository.Events;
+
+namespace Hotline.Orders.DatabaseEventHandler;
+
+/// <summary>
+/// OrderVisit 更新数据后执行事务处理
+/// 更新 order 表中的 OrgProcessingResults 和 SeatEvaluate 字段
+/// </summary>
+public class OrderVisitDetailEventHandler : IUpdateDatabaseEvent<OrderVisitDetail>
+{
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly IOrderRepository _orderRepository;
+    private readonly IRepository<OrderVisit> _orderVisitRepository;
+    private readonly ISystemLogRepository _systemLogRepository;
+
+    public OrderVisitDetailEventHandler(IOrderRepository orderRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, IRepository<OrderVisit> orderVisitRepository, ISystemLogRepository systemLogRepository)
+    {
+        _orderRepository = orderRepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _orderVisitRepository = orderVisitRepository;
+        _systemLogRepository = systemLogRepository;
+    }
+
+    public void OnInsert(OrderVisitDetail entity)
+    {
+        OrderUpdate(entity);
+    }
+
+    public void OnUpdate(OrderVisitDetail entity)
+    {
+        OrderUpdate(entity);
+    }
+
+    private void OrderUpdate(OrderVisitDetail visit)
+    {
+        var name = "回填Order回访字段";
+        if (visit.VisitTarget == EVisitTarget.Org && visit.OrgProcessingResults != null)
+        {
+            var orderId = _orderVisitRepository.Queryable()
+                .Where(m => m.Id == visit.VisitId)
+                .Select(m => new { m.OrderId, m.No })
+                .First();
+            _orderRepository.Updateable()
+                .SetColumns(m => m.OrgProcessingResults == visit.OrgProcessingResults)
+                .Where(m => m.Id == orderId.OrderId)
+                .ExecuteCommand();
+            _systemLogRepository.Add(name, $"OrgProcessingResults: {visit.OrgProcessingResults.ToJson()}", orderId.No, orderId.No, 1);
+        }
+
+        if (visit.VisitTarget == EVisitTarget.Seat && visit.SeatEvaluate != null)
+        {
+            var orderId = _orderVisitRepository.Queryable()
+                .Where(m => m.Id == visit.VisitId)
+                .Select(m => new { m.OrderId, m.No })
+                .First();
+            _orderRepository.Updateable()
+                .SetColumns(m => m.SeatEvaluate == visit.SeatEvaluate)
+                .Where(m => m.Id == orderId.OrderId)
+                .ExecuteCommand();
+            _systemLogRepository.Add(name, $"SeatEvaluate: {visit.SeatEvaluate}",orderId.No, orderId.No, 1);
+        }
+
+    }
+}

+ 2 - 1
src/Hotline/Orders/IOrderRepository.cs

@@ -2,6 +2,7 @@
 using Hotline.Share.Requests;
 using SqlSugar;
 using System.Data;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Order;
 using XF.Domain.Repository;
 using Hotline.Share.Dtos.Bi;
@@ -68,7 +69,7 @@ namespace Hotline.Orders
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto);
+        Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto, List<Kv> title);
 
         /// <summary>
         /// 信件来源分时统计

+ 0 - 10
src/Hotline/Orders/Notifications/UpdateOrderVisitNotify.cs

@@ -1,10 +0,0 @@
-using Hotline.Share.Dtos.Order;
-using MediatR;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Hotline.Orders.Notifications;
-public record UpdateOrderVisitNotify(OrderVisitNotifyDto orderVisit) : INotification;

+ 0 - 1
src/Hotline/Orders/OrderDomainService.cs

@@ -278,7 +278,6 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         await _orderVisitDetailRepository.AddRangeAsync(visitedDetail, cancellationToken);
         await _publisher.PublishAsync(new ContingencyManagementNotify(order, order.Title, order.Content, order.ActualOpinion),
     PublishStrategy.ParallelWhenAll, cancellationToken);
-        await _publisher.PublishAsync(new UpdateOrderVisitNotify(orderVisit.Adapt<OrderVisitNotifyDto>()), cancellationToken);
 
         //handle publish trace
         var acceptor = new UserInfo(orderPublish.CreatorId, orderPublish.CreatorName,

+ 0 - 1
src/Hotline/Orders/OrderVisitDomainService.cs

@@ -176,7 +176,6 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
                 await _orderVisitDetailRepository.UpdateAsync(detailSeat);
             });
 
-        await _publisher.PublishAsync(new UpdateOrderVisitNotify(orderVisit.Adapt<OrderVisitNotifyDto>()), cancellationToken: CancellationToken.None);
 
         if (orderVisit.VisitState != EVisitState.Visited) return;
         orderVisit.Order.Visited(visitSatisfactionKv.Key, visitSatisfactionKv.Value);

+ 5 - 0
src/Hotline/Settings/SettingConstants.cs

@@ -672,5 +672,10 @@ namespace Hotline.Settings
         /// 办结是否发送查询短信
         /// </summary>
         public const string IsOpenSendEndSms = "IsOpenSendEndSms";
+
+        /// <summary>
+        /// 企业话机
+        /// </summary>
+        public const string EnterpriseTel = "EnterpriseTel";
     }
 }

+ 5 - 5
src/Hotline/Statistics/StatisticsDepart.cs

@@ -198,11 +198,11 @@ namespace Hotline.Statistics
 		[SugarColumn(Length = 10, DecimalDigits = 6, ColumnDescription = "总满意率")]
 		public decimal AllSatisfaction { get; set; }
 
-		///// <summary>
-		///// 统计日期
-		///// </summary>
-		//[SugarColumn(ColumnDescription = "统计日期")]
-		//public int DateTime { get; set; }
+		/// <summary>
+		/// 统计日期
+		/// </summary>
+		[SugarColumn(ColumnDescription = "统计日期")]
+		public DateTime Time { get; set; }
 
 		/// <summary>
 		/// 统计时限

+ 5 - 5
src/Hotline/Statistics/StatisticsDepartSatisfied.cs

@@ -132,11 +132,11 @@ namespace Hotline.Statistics
 		public int ScreenWaitNum { get; set; }
 
 
-		///// <summary>
-		///// 统计日期
-		///// </summary>
-		//[SugarColumn(ColumnDescription = "统计日期")]
-		//public int DateTime { get; set; }
+		/// <summary>
+		/// 统计日期
+		/// </summary>
+		[SugarColumn(ColumnDescription = "统计日期")]
+		public DateTime Time { get; set; }
 
 		/// <summary>
 		/// 统计时限

+ 5 - 5
src/Hotline/Statistics/StatisticsHotspotSatisfied.cs

@@ -101,11 +101,11 @@ namespace Hotline.Statistics
 		[SugarColumn(ColumnDescription = "(自贡)甄别为满意 自贡的视为满意名字是甄别为满意")]
 		public int ScreenSatisfaction { get; set; }
 
-		///// <summary>
-		///// 统计日期
-		///// </summary>
-		//[SugarColumn(ColumnDescription = "统计日期")]
-		//public int DateTime { get; set; }
+		/// <summary>
+		/// 统计日期
+		/// </summary>
+		[SugarColumn(ColumnDescription = "统计日期")]
+		public DateTime Time { get; set; }
 
 		/// <summary>
 		/// 统计时限

+ 5 - 5
src/Hotline/Statistics/StatisticsPurTypeSatisfied.cs

@@ -102,11 +102,11 @@ namespace Hotline.Statistics
 		[SugarColumn(ColumnDescription = "无效")]
 		public int Invalid { get; set; }
 
-		///// <summary>
-		///// 统计日期
-		///// </summary>
-		//[SugarColumn(ColumnDescription = "统计日期")]
-		//public int DateTime { get; set; }
+		/// <summary>
+		/// 统计日期
+		/// </summary>
+		[SugarColumn(ColumnDescription = "统计日期")]
+		public DateTime Time { get; set; }
 
 		/// <summary>
 		/// 统计时限

+ 4 - 4
src/Hotline/dataview.md

@@ -342,10 +342,10 @@ WHERE ordervisitdetailtemp."VisitTarget" = 20 and ordervisittemp."VisitTime">='2
 
 
  ### 信件清单查询(新)
-  select '' as "序号",
+   select '' as "序号",
 aaa.信件状态,aaa."是否超期",aaa.来源,aaa.转接来源,aaa.当前节点,aaa.重办次数,aaa.甄别状态,aaa.受理编号,aaa.省编号,aaa.受理时间,aaa.标题,aaa.期满时间,aaa."一级部门",
 aaa.二级部门,aaa."接办部门",aaa."办结时间",aaa."受理类型",aaa."热点类型",aaa.热点全称,aaa."区域",aaa.区域全称,aaa."受理人",aaa."姓名",aaa."联系电话",aaa."来电电话",
-aaa."事发地址",aaa."具体对象",aaa."来电人主体",aaa."性别",ccc."SeatVisitResult" as "坐席满意度",bbb."OrgProcessingResults" as "满意度",aaa."推送分类",aaa."受理内容",
+aaa."事发地址",aaa."具体对象",aaa."来电人主体",aaa."性别",ccc."SeatVisitResult" as "坐席满意度",bbb."VisitOrgName" as "回访部门",bbb."OrgProcessingResults" as "满意度",aaa."推送分类",aaa."受理内容",
 aaa."承办意见",aaa."归档意见" from 
 (select 
 CASE "ordertemp"."Status"
@@ -438,10 +438,10 @@ END AS "性别" ,
 "Content" AS "受理内容" , 
 "ActualOpinion" AS "承办意见" ,
 "FileOpinion" AS "归档意见" ,
-"Id" AS "SugarNav_Id" FROM "order" ordertemp  WHERE (( "CreationTime" >= '2024-08-29' ) AND ( "CreationTime" <= '2024-08-30' ))  AND ( "IsDeleted" = FALSE )ORDER BY "CreationTime" ASC) aaa
+"Id" AS "SugarNav_Id" FROM "order" ordertemp  WHERE (( "CreationTime" >= '2024-08-29' ) AND ( "CreationTime" <= '2024-11-30' ))  AND ( "IsDeleted" = FALSE )ORDER BY "CreationTime" ASC) aaa
 left JOIN
 (select 
- string_agg(visitdetailtemptwo."OrgProcessingResults"::JSON->>'Value','/') as "OrgProcessingResults",visittemptwo."OrderId" as "OrderId"
+ string_agg(visitdetailtemptwo."VisitOrgName",'/') as "VisitOrgName",string_agg(visitdetailtemptwo."OrgProcessingResults"::JSON->>'Value','/') as "OrgProcessingResults",visittemptwo."OrderId" as "OrderId"
 from order_visit visittemptwo
 left join order_visit_detail visitdetailtemptwo on visittemptwo."Id" = visitdetailtemptwo."VisitId"
 where  visittemptwo."CreationTime">='2024-08-29' and visitdetailtemptwo."VisitTarget"=20 AND visittemptwo."VisitState"=30 group by visittemptwo."OrderId") as bbb

+ 35 - 0
src/XF.Domain.Repository/Events/DatabaseEventDispatcher.cs

@@ -0,0 +1,35 @@
+using Microsoft.Extensions.DependencyInjection;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace XF.Domain.Repository.Events;
+public class DatabaseEventDispatcher
+{
+    private readonly IServiceProvider _serviceProvider;
+
+    public DatabaseEventDispatcher(IServiceProvider serviceProvider)
+    {
+        _serviceProvider = serviceProvider;
+    }
+
+    public void Dispatch<TEntity>(TEntity entity, DataFilterType operationType) where TEntity : new()
+    {
+        var targetInterface = typeof(IUpdateDatabaseEvent<>).MakeGenericType(entity.GetType());
+        var handler = _serviceProvider.GetService(targetInterface);
+        if (handler == null) return;
+
+        switch (operationType)
+        {
+            case DataFilterType.UpdateByObject:
+                targetInterface?.GetMethod("OnUpdate")?.Invoke(handler,[entity]);
+                break;
+            case DataFilterType.InsertByObject:
+                targetInterface?.GetMethod("OnInsert")?.Invoke(handler, [entity]);
+                break;
+        }
+    }
+}

+ 13 - 0
src/XF.Domain.Repository/Events/IUpdateDatabaseEvent.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace XF.Domain.Repository.Events;
+
+public interface IUpdateDatabaseEvent<TEntity> where TEntity : new()
+{
+    void OnUpdate(TEntity entity);
+    void OnInsert(TEntity entity);
+}