qinchaoyue 7 місяців тому
батько
коміт
06b7e2d176
100 змінених файлів з 4524 додано та 1395 видалено
  1. 1 1
      .gitignore
  2. 9 0
      Hotline.sln
  3. 5 2
      src/Hotline.Api/Controllers/AiController.cs
  4. 25 4
      src/Hotline.Api/Controllers/ArticleController.cs
  5. 47 20
      src/Hotline.Api/Controllers/Bi/BiCallController.cs
  6. 4 4
      src/Hotline.Api/Controllers/Bi/BiKnowledgeController.cs
  7. 211 68
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  8. 50 20
      src/Hotline.Api/Controllers/Bigscreen/SeatController.cs
  9. 13 0
      src/Hotline.Api/Controllers/CommonPController.cs
  10. 390 0
      src/Hotline.Api/Controllers/DataSharingController.cs
  11. 3 20
      src/Hotline.Api/Controllers/EnforcementOrderController.cs
  12. 24 22
      src/Hotline.Api/Controllers/IPPbxController.cs
  13. 289 359
      src/Hotline.Api/Controllers/OrderController.cs
  14. 10 4
      src/Hotline.Api/Controllers/SettingController.cs
  15. 270 428
      src/Hotline.Api/Controllers/TestController.cs
  16. 19 20
      src/Hotline.Api/Controllers/WebPortalController.cs
  17. 6 0
      src/Hotline.Api/Program.cs
  18. 11 9
      src/Hotline.Api/StartupExtensions.cs
  19. 10 8
      src/Hotline.Api/StartupHelper.cs
  20. 34 2
      src/Hotline.Api/config/appsettings.Development.json
  21. 27 0
      src/Hotline.Application.Tests/Application/ExpireTimeHandlerTest.cs
  22. 98 0
      src/Hotline.Application.Tests/Application/OrderApplicationTest.cs
  23. 3 3
      src/Hotline.Application.Tests/DefaultHttpContextAccessor.cs
  24. 43 0
      src/Hotline.Application.Tests/Domain/LuZhouExpireTimeTest.cs
  25. 100 0
      src/Hotline.Application.Tests/Domain/YiBinExpireTimeTest.cs
  26. 135 0
      src/Hotline.Application.Tests/Domain/ZiGongExpireTimeTest.cs
  27. 1 0
      src/Hotline.Application.Tests/Hotline.Application.Tests.csproj
  28. 44 0
      src/Hotline.Application.Tests/Mock/MediatorMock.cs
  29. 3 0
      src/Hotline.Application.Tests/ReadME.md
  30. 58 0
      src/Hotline.Application.Tests/Repository/OrderVisitRepositoryTest.cs
  31. 36 6
      src/Hotline.Application.Tests/Startup.cs
  32. 2 0
      src/Hotline.Application/ApplicationStartupExtensions.cs
  33. 67 0
      src/Hotline.Application/Bulletin/BulletinApplication.cs
  34. 18 0
      src/Hotline.Application/Bulletin/IBulletinApplication.cs
  35. 415 71
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  36. 27 6
      src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs
  37. 1 1
      src/Hotline.Application/Jobs/SendOverTimeSmsJob.cs
  38. 22 0
      src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs
  39. 0 2
      src/Hotline.Application/JudicialManagement/EnforcementApplication.cs
  40. 3 5
      src/Hotline.Application/JudicialManagement/JudicialManagementOrderNotifyHandler.cs
  41. 3 1
      src/Hotline.Application/Mappers/CallMapperConfigs.cs
  42. 21 0
      src/Hotline.Application/Mappers/MapperConfigs.cs
  43. 2 2
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  44. 2 2
      src/Hotline.Application/Mappers/WebPortalMapperConfigs.cs
  45. 29 0
      src/Hotline.Application/Mappers/WorkflowMapperConfigs.cs
  46. 35 11
      src/Hotline.Application/Orders/IOrderApplication.cs
  47. 390 136
      src/Hotline.Application/Orders/OrderApplication.cs
  48. 1 1
      src/Hotline.Application/Orders/OrderScreenHandler/OrderScreenEndWorkflowHandler.cs
  49. 3 11
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  50. 0 1
      src/Hotline.Application/StatisticalReport/CallReportApplication.cs
  51. 0 14
      src/Hotline.Application/StatisticalReport/OrderReportApplication.cs
  52. 198 18
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  53. 36 10
      src/Hotline.Application/Subscribers/InternalCapSubscriber.cs
  54. 102 0
      src/Hotline.Application/Systems/BaseDataApplication.cs
  55. 1 0
      src/Hotline.Application/Tels/ITelApplication.cs
  56. 9 5
      src/Hotline.Application/Tels/TelApplication.cs
  57. 1 12
      src/Hotline.Repository.SqlSugar/CallCenter/TrCallRecordRepository.cs
  58. 28 0
      src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingAttributeRepository.cs
  59. 24 0
      src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingInventoryRepository.cs
  60. 21 0
      src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingRepository.cs
  61. 21 36
      src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs
  62. 102 0
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs
  63. 9 0
      src/Hotline.Share/Dtos/CallCenter/BiQueryCallsDto.cs
  64. 23 0
      src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/TianQuePushOrderReceiverDto.cs
  65. 107 0
      src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/TianQueReceiverOpinionDto.cs
  66. 18 0
      src/Hotline.Share/Dtos/DataSharingSearch/AcceptTypeList.cs
  67. 17 0
      src/Hotline.Share/Dtos/DataSharingSearch/GetBulletinListDto.cs
  68. 61 0
      src/Hotline.Share/Dtos/DataSharingSearch/GetOrderDetailDto.cs
  69. 26 0
      src/Hotline.Share/Dtos/DataSharingSearch/GetOrderNoPwdDto.cs
  70. 39 0
      src/Hotline.Share/Dtos/DataSharingSearch/GridOperatorSendSmsDto.cs
  71. 1 1
      src/Hotline.Share/Dtos/FlowEngine/Definition/StepDefineBasic.cs
  72. 26 1
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  73. 60 2
      src/Hotline.Share/Dtos/FlowEngine/NextWorkflowDto.cs
  74. 8 0
      src/Hotline.Share/Dtos/FlowEngine/PreviousWorkflowDto.cs
  75. 4 0
      src/Hotline.Share/Dtos/FlowEngine/StartWorkflowDto.cs
  76. 1 1
      src/Hotline.Share/Dtos/FlowEngine/Workflow/StepBasicDto.cs
  77. 1 1
      src/Hotline.Share/Dtos/Order/OrderBiDto.cs
  78. 35 10
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  79. 1 0
      src/Hotline.Share/Dtos/Order/OrderPreviousDto.cs
  80. 26 0
      src/Hotline.Share/Dtos/Order/OrderPushTypeDto.cs
  81. 2 0
      src/Hotline.Share/Dtos/Order/OrderSpecialDto.cs
  82. 4 1
      src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs
  83. 165 4
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  84. 1 1
      src/Hotline.Share/Dtos/Order/OrderWaitedDto.cs
  85. 28 15
      src/Hotline.Share/Dtos/Order/PublishedDto.cs
  86. 6 0
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  87. 30 0
      src/Hotline.Share/Dtos/Order/SendBackDto.cs
  88. 15 0
      src/Hotline.Share/Dtos/Push/FWMessage/MessageDataDto.cs
  89. 32 1
      src/Hotline.Share/Dtos/Push/MessagePagedDto.cs
  90. 6 0
      src/Hotline.Share/Dtos/Settings/IsFuzzyQueryAttribute.cs
  91. 6 0
      src/Hotline.Share/Dtos/Settings/NoCodeAttribute.cs
  92. 20 0
      src/Hotline.Share/Dtos/Settings/SystemDicDataDto.cs
  93. 79 2
      src/Hotline.Share/Dtos/Settings/TimeConfig.cs
  94. 7 0
      src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs
  95. 36 0
      src/Hotline.Share/Enums/FlowEngine/EDynamicPolicy.cs
  96. 33 0
      src/Hotline.Share/Enums/FlowEngine/EDynamicPolicyCountersign.cs
  97. 6 0
      src/Hotline.Share/Enums/FlowEngine/EHandlerType.cs
  98. 10 10
      src/Hotline.Share/Enums/Order/ESeatEvaluate.cs
  99. 5 0
      src/Hotline.Share/Enums/Order/ESource.cs
  100. 7 0
      src/Hotline.Share/Enums/Order/ESpecialType.cs

+ 1 - 1
.gitignore

@@ -21,7 +21,7 @@
 [Rr]eleases/
 x64/
 x86/
-TestResults/
+TestResult/
 [Aa][Rr][Mm]/
 [Aa][Rr][Mm]64/
 bld/

+ 9 - 0
Hotline.sln

@@ -52,6 +52,10 @@ EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XingTang.Sdk", "src\XingTang.Sdk\XingTang.Sdk.csproj", "{CF2A8B80-FF4E-4291-B383-D735BB629F32}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.XingTang", "src\Hotline.XingTang\Hotline.XingTang.csproj", "{9F99C272-5BC2-452C-9D97-BC756AF04669}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XingTang.Sdk", "src\XingTang.Sdk\XingTang.Sdk.csproj", "{CF2A8B80-FF4E-4291-B383-D735BB629F32}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.Application.Tests", "src\Hotline.Application.Tests\Hotline.Application.Tests.csproj", "{801A8807-F95E-428B-B8C3-3F9244B9E080}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotline.XingTang", "src\Hotline.XingTang\Hotline.XingTang.csproj", "{9F99C272-5BC2-452C-9D97-BC756AF04669}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotline.Application.Tests", "src\Hotline.Application.Tests\Hotline.Application.Tests.csproj", "{21E8510A-9D78-44B6-AC9C-2A9D4023853D}"
 EndProject
@@ -139,6 +143,10 @@ Global
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{9F99C272-5BC2-452C-9D97-BC756AF04669}.Release|Any CPU.Build.0 = Release|Any CPU
+		{801A8807-F95E-428B-B8C3-3F9244B9E080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{801A8807-F95E-428B-B8C3-3F9244B9E080}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{801A8807-F95E-428B-B8C3-3F9244B9E080}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{801A8807-F95E-428B-B8C3-3F9244B9E080}.Release|Any CPU.Build.0 = Release|Any CPU
 		{21E8510A-9D78-44B6-AC9C-2A9D4023853D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{21E8510A-9D78-44B6-AC9C-2A9D4023853D}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{21E8510A-9D78-44B6-AC9C-2A9D4023853D}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -177,6 +185,7 @@ Global
 		{9F99C272-5BC2-452C-9D97-BC756AF04669} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
 		{21E8510A-9D78-44B6-AC9C-2A9D4023853D} = {08D63205-1445-430F-A4AB-EF1744E3AC11}
 		{1A71273C-0ACC-4B70-8405-E443DE278D9F} = {D041C554-B78E-4AAF-B597-E309DC8EEF4F}
+		{801A8807-F95E-428B-B8C3-3F9244B9E080} = {08D63205-1445-430F-A4AB-EF1744E3AC11}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {4B8EA790-BD13-4422-8D63-D6DBB77B823F}

+ 5 - 2
src/Hotline.Api/Controllers/AiController.cs

@@ -567,7 +567,7 @@ namespace Hotline.Api.Controllers
                                 //处理部门
                                 var orgDetail = visitDetail.Where(x => x.VisitTarget == Share.Enums.Order.EVisitTarget.Org).ToList();
                                 //过滤结果
-                                var orgProcessingResults = new Kv();
+                                Kv? orgProcessingResults = null;
                                 //var orgHandledAttitude = new Kv();
                                 ESeatEvaluate? seatEvaluate = null;
                                 var visitContent = "";
@@ -667,7 +667,10 @@ namespace Hotline.Api.Controllers
                                 orgDetail.ForEach(x =>
                                 {
                                     //x.OrgHandledAttitude = orgHandledAttitude;
-                                    x.OrgProcessingResults = orgProcessingResults;
+                                    if (orgProcessingResults!=null)
+                                    {
+                                        x.OrgProcessingResults = orgProcessingResults;
+                                    }
                                     x.VisitContent = visitContent;
                                     x.Volved = isSolve;
                                     x.IsContact = isContact;

+ 25 - 4
src/Hotline.Api/Controllers/ArticleController.cs

@@ -1,4 +1,5 @@
 using DotNetCore.CAP;
+using Hotline.Application.Bulletin;
 using Hotline.Application.FlowEngine;
 using Hotline.Article;
 using Hotline.Caching.Interfaces;
@@ -36,8 +37,23 @@ namespace Hotline.Api.Controllers
         private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
         private readonly IMediator _mediator;
         private readonly ICapPublisher _capPublisher;
-
-        public ArticleController(IRepository<Bulletin> bulletinRepository, IMapper mapper, ISystemDomainService systemDomainService, ISystemOrganizeRepository organizeRepository, IWorkflowApplication workflowApplication, IRepository<Circular> circularRepository, ISessionContext sessionContext, IRepository<CircularRecord> circularRecordRepository, IRepository<CircularReadGroup> circularReadGroupRepository, IRepository<User> userRepository, ICircularRecordDomainService circularRecordDomainService, ISystemDicDataCacheManager systemDicDataCacheManager, IMediator mediator, ICapPublisher capPublisher)
+        private readonly IBulletinApplication _bulletinApplication;
+
+        public ArticleController(IRepository<Bulletin> bulletinRepository,
+            IMapper mapper,
+            ISystemDomainService systemDomainService,
+            ISystemOrganizeRepository organizeRepository,
+            IWorkflowApplication workflowApplication,
+            IRepository<Circular> circularRepository,
+            ISessionContext sessionContext,
+            IRepository<CircularRecord> circularRecordRepository,
+            IRepository<CircularReadGroup> circularReadGroupRepository,
+            IRepository<User> userRepository,
+            ICircularRecordDomainService circularRecordDomainService,
+            ISystemDicDataCacheManager systemDicDataCacheManager,
+            IMediator mediator,
+            ICapPublisher capPublisher,
+            IBulletinApplication bulletinApplication)
         {
             _bulletinRepository = bulletinRepository;
             _mapper = mapper;
@@ -52,6 +68,7 @@ namespace Hotline.Api.Controllers
             _systemDicDataCacheManager = systemDicDataCacheManager;
             _mediator = mediator;
             _capPublisher = capPublisher;
+            _bulletinApplication = bulletinApplication;
         }
         #region 通知
 
@@ -446,6 +463,10 @@ namespace Hotline.Api.Controllers
             var model = await _bulletinRepository.Queryable()
                 .Includes(x => x.ExaminMan)
                 .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
+
+            if (model != null && !string.IsNullOrEmpty(model.Content))
+                model.Content = _bulletinApplication.GetSiteUrls(model.Content);
+
             return _mapper.Map<BulletinDto>(model);
         }
 
@@ -476,7 +497,7 @@ namespace Hotline.Api.Controllers
                 var publishBulletin = _mapper.Map<PublishBulletinDto>(bulletin);
 
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlinePushBulletin, publishBulletin, cancellationToken: HttpContext.RequestAborted);
-                
+
                 //todo await _bulletinService.PushBulletin(publishBulletin, HttpContext.RequestAborted);
             }
             else
@@ -589,7 +610,7 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("当前状态不能操作上架或下架");
 
             bulletin.IsArrive = dto.IsArrive;
-            if (bulletin.IsArrive==false)
+            if (bulletin.IsArrive == false)
             {
                 bulletin.ExaminTime = null;
                 bulletin.ExaminManId = null;

+ 47 - 20
src/Hotline.Api/Controllers/Bi/BiCallController.cs

@@ -118,7 +118,6 @@ public class BiCallController : BaseController
         //    items = items.OrderBy(d => d.Hour).ToList();
         //}
         #endregion
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
         return await _trCallRecordRepositoryEx.GetQueryCalls(dto.StartTime.Value, dto.EndTime.Value, dto.Keyword);
 
@@ -135,8 +134,6 @@ public class BiCallController : BaseController
     {
         if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-        dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         var list = await _trCallRecordRepositoryEx.GetQueryCalls(dto.QueryDto.StartTime.Value, dto.QueryDto.EndTime.Value, dto.QueryDto.Keyword);
 
         if (list != null && list.Count > 0)
@@ -174,7 +171,6 @@ public class BiCallController : BaseController
     {
         if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
             throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
         var items = await _callReportApplication.QueryCallsDetailAsync(dto);
 
@@ -210,7 +206,6 @@ public class BiCallController : BaseController
     {
         if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue)
             throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
         var items = await _callReportApplication.QueryCallsDetailAsync(dto.QueryDto);
 
@@ -307,7 +302,7 @@ public class BiCallController : BaseController
     {
         if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
             throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
         //超时接通量
         int CallInOverConnRingTime = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOverConnRingTime)?.SettingValue[0]);
         //坐席超时挂断时间
@@ -355,7 +350,7 @@ public class BiCallController : BaseController
     {
         if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue)
             throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
         //超时接通量
         int CallInOverConnRingTime = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOverConnRingTime)?.SettingValue[0]);
         //坐席超时挂断时间
@@ -412,8 +407,8 @@ public class BiCallController : BaseController
     [HttpPost("seats/export")]
     public async Task<FileStreamResult> ExportSeatss([FromBody] ExportExcelDto<ReportPagedRequest> dto)
     {
-        if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue) 
+            throw UserFriendlyException.SameMessage("请选择时间!");
 
         var list =  await _callReportApplication.QuerySeatCallAsync(dto.QueryDto);
         if (list != null && list.Count > 0)
@@ -457,8 +452,8 @@ public class BiCallController : BaseController
     [AllowAnonymous]
     public async Task<IReadOnlyList<BiSeatCallsDto>> QuerySeatCallsAsync([FromQuery] ReportPagedRequest dto)
     {
-        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) 
+            throw UserFriendlyException.SameMessage("请选择时间!");
 
         //获取配置
         int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
@@ -514,8 +509,8 @@ public class BiCallController : BaseController
     [AllowAnonymous]
     public async Task<IReadOnlyList<BiSeatRestDto>> QuerySeatRest([FromQuery] QuerySeatRestRequest dto)
     {
-        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) 
+            throw UserFriendlyException.SameMessage("请选择时间!");
 
         return await _telRestRepository.Queryable()
             .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.UserName.Contains(dto.UserName))
@@ -546,9 +541,8 @@ public class BiCallController : BaseController
     [AllowAnonymous]
     public async Task<PagedDto<BiSeatSwitchDto>> QuerySeatSwitch([FromQuery] QuerySeatSwitchRequest dto)
     {
-        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) 
+            throw UserFriendlyException.SameMessage("请选择时间!");
 
         var (total, items) = await _trCallRecordRepository.Queryable()
             .Where(x => !string.IsNullOrEmpty(x.AgentTransferNumber))
@@ -577,13 +571,15 @@ public class BiCallController : BaseController
     /// <returns></returns>
     [HttpGet("hourcall")]
     [AllowAnonymous]
-    public async Task<List<TrCallHourDto>> QueryHourCall([FromQuery] DateTime StartTime, DateTime? EndTime, string source)
+    public async Task<List<TrCallHourDto>> QueryHourCall([FromQuery] BiQueryHourCallDto dto)
     {
+        if (!dto.EndTime.HasValue)
+            throw UserFriendlyException.SameMessage("请选择时间!");
         //获取配置
         int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
         int effectiveTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
         int connectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.ConnectByeTimes)?.SettingValue[0]);
-        var list = await _trCallRecordRepositoryEx.GetCallHourList(StartTime, EndTime, noConnectByeTimes, effectiveTimes, connectByeTimes, source);
+        var list = await _trCallRecordRepositoryEx.GetCallHourList(dto.StartTime, dto.EndTime, noConnectByeTimes, effectiveTimes, connectByeTimes, dto.Source);
         return list;
     }
 
@@ -595,6 +591,8 @@ public class BiCallController : BaseController
     [AllowAnonymous]
     public async Task<FileStreamResult> ExportQueryHourCall([FromBody] ExportExcelDto<BiQueryHourCallDto> dto)
     {
+         if (!dto.QueryDto.EndTime.HasValue)
+            throw UserFriendlyException.SameMessage("请选择时间!");
         //获取配置
         int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
         int effectiveTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
@@ -634,6 +632,8 @@ public class BiCallController : BaseController
     [HttpGet("hourcall_list")]
     public async Task<object> QueryCallList([FromQuery] DateTime StartTime, DateTime? EndTime, string type, string source, TimeSpan? startHourTo, int pageIndex, int pageSize)
     {
+        if(!EndTime.HasValue)
+            throw UserFriendlyException.SameMessage("请选择时间!");
         //获取配置
         int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
         int effectiveTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
@@ -666,14 +666,41 @@ public class BiCallController : BaseController
     /// <returns></returns>
     [AllowAnonymous]
     [HttpGet("gateway-query")]
-    public async Task<List<CallHotLineDto>> QueryGateWay(DateTime StartTime, DateTime EndTime, string gateway)
+    public async Task<List<CallHotLineDto>> QueryGateWay([FromQuery] BiQueryGateWayDto dto)
     {
         //获取配置
         int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
         int effectiveTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
         int connectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.ConnectByeTimes)?.SettingValue[0]);
         int ringTims = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.RingTims)?.SettingValue[0]);
-        var list = await _trCallRecordRepositoryEx.GetCallHotLineList(StartTime, EndTime, gateway, noConnectByeTimes, effectiveTimes, connectByeTimes, ringTims);
+        var list = await _trCallRecordRepositoryEx.GetCallHotLineList(dto.StartTime, dto.EndTime, dto.gateway, noConnectByeTimes, effectiveTimes, connectByeTimes, ringTims);
         return list;
     }
+
+    /// <summary>
+    /// 热线号码统计导出
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("gateway-query/export")]
+    public async Task<FileStreamResult> ExportQueryGatetWay(ExportExcelDto<BiQueryGateWayDto> dto)
+    {
+        //获取配置
+        int noConnectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
+        int effectiveTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
+        int connectByeTimes = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.ConnectByeTimes)?.SettingValue[0]);
+        int ringTims = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.RingTims)?.SettingValue[0]);
+        var list = await _trCallRecordRepositoryEx.GetCallHotLineList(dto.QueryDto.StartTime, dto.QueryDto.EndTime, dto.QueryDto.gateway, noConnectByeTimes, effectiveTimes, connectByeTimes, ringTims);
+
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+        var dtos = list
+            .Select(stu => _mapper.Map(stu, typeof(CallHotLineDto), dynamicClass))
+            .Cast<object>()
+            .ToList();
+
+        var stream = ExcelHelper.CreateStream(dtos);
+
+        return ExcelStreamResult(stream, "热线号码统计");
+    }
 }

+ 4 - 4
src/Hotline.Api/Controllers/Bi/BiKnowledgeController.cs

@@ -34,8 +34,8 @@ namespace Hotline.Api.Controllers.Bi
 		[HttpGet("data_list")]
 		public async Task<PagedDto<KnowledgeBiDataListVo>> DataList([FromQuery] KnowledgeBiDataListDto dto)
 		{
-            if (!dto.CreationTimeStart.HasValue || !dto.CreationTimeEnd.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.CreationTimeEnd = dto.CreationTimeEnd.Value.AddDays(1).AddSeconds(-1);
+            if (!dto.CreationTimeStart.HasValue || !dto.CreationTimeEnd.HasValue) 
+				throw UserFriendlyException.SameMessage("请选择时间!");
 
 			var query = _knowledgeRepository.DataList(dto, HttpContext.RequestAborted);
 			switch (dto.SortField)
@@ -81,8 +81,8 @@ namespace Hotline.Api.Controllers.Bi
 		[HttpPost("data_list/_export")]
 		public async Task<FileStreamResult> DataList([FromBody] ExportExcelDto<KnowledgeBiDataListDto> dto)
 		{
-			if (!dto.QueryDto.CreationTimeStart.HasValue || !dto.QueryDto.CreationTimeEnd.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-			dto.QueryDto.CreationTimeEnd = dto.QueryDto.CreationTimeEnd.Value.AddDays(1).AddSeconds(-1);
+			if (!dto.QueryDto.CreationTimeStart.HasValue || !dto.QueryDto.CreationTimeEnd.HasValue) 
+				throw UserFriendlyException.SameMessage("请选择时间!");
 			var query = _knowledgeRepository.DataList(dto.QueryDto, HttpContext.RequestAborted);
 			List<KnowledgeBiDataListVo> data;
 			if (dto.IsExportAll)

+ 211 - 68
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -26,6 +26,7 @@ using Hotline.Share.Tools;
 using Hotline.Tools;
 using MapsterMapper;
 using MediatR;
+using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
 using System.Data;
@@ -132,6 +133,171 @@ namespace Hotline.Api.Controllers.Bi
             _organizeRepository = organizeRepository;
         }
 
+        /// <summary>
+        /// 部门发布量统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("published/statistics/department")]
+        public async Task<PagedDto<PublishedOrderStatisticsDto>> QueryPublishedOrderDepartmentAsync([FromQuery] QueryOrderPublishStatisticsAllDto dto)
+        {
+            var (total, items) = await _orderApplication.QueryPublishedOrderDepartmentAsync(dto, false);
+            return new PagedDto<PublishedOrderStatisticsDto>(total, _mapper.Map<IReadOnlyList<PublishedOrderStatisticsDto>>(items));
+        }
+
+        /// <summary>
+        /// 部门发布量统计-导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("published/statistics/department/export")]
+        public async Task<FileStreamResult> ExportQueryPublishedOrderDepartmentAsync([FromBody] ExportExcelDto<QueryOrderPublishStatisticsAllDto> dto)
+        {
+            var (total, list) = await _orderApplication.QueryPublishedOrderDepartmentAsync(dto.QueryDto, dto.IsExportAll);
+            if (list != null && list.Count > 0)
+            {
+                list.Add(new PublishedOrderStatisticsDto()
+                {
+                    Name = "合计",
+                    PrivateCount = list.Sum(m => m.PrivateCount),
+                    // TotalCount = list.Sum(p => p.TotalCount),
+                    PublicCount = list.Sum(m => m.PublicCount),
+                    WaitCount = list.Sum(m => m.WaitCount)
+                });
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(PublishedOrderStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "部门发布量统计");
+        }
+
+        /// <summary>
+        /// 发布量统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("published/statistics/user")]
+        public async Task<PagedDto<PublishedOrderStatisticsDto>> QueryPublishedOrderUserAsync([FromQuery] QueryOrderPublishStatisticsDto dto)
+        {
+            var (total, list) = await _orderApplication.QueryPublishedOrderAsync(dto, false);
+            return new PagedDto<PublishedOrderStatisticsDto>(total, _mapper.Map<IReadOnlyList<PublishedOrderStatisticsDto>>(list));
+        }
+
+        /// <summary>
+        /// 发布量统计-导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("published/statistics/user/export")]
+        public async Task<FileStreamResult> ExportQueryPublishedOrder([FromBody] ExportExcelDto<QueryOrderPublishStatisticsDto> dto)
+        {
+            var (total, list) = await _orderApplication.QueryPublishedOrderAsync(dto.QueryDto, dto.IsExportAll);
+            if (list != null && list.Count > 0)
+            {
+                list.Add(new PublishedOrderStatisticsDto()
+                {
+                    Name = "合计",
+                    PrivateCount = list.Sum(m => m.PrivateCount),
+                    //TotalCount = list.Sum(p => p.TotalCount),
+                    PublicCount = list.Sum(m => m.PublicCount),
+                    WaitCount = list.Sum(m => m.WaitCount)
+                });
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(PublishedOrderStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "发布量统计");
+        }
+
+        /// <summary>
+        /// 发布量统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("published/statistics")]
+        public async Task<PublishedOrderStatisticsDto> QueryPublishedOrderAsync([FromQuery] QueryOrderPublishStatisticsAllDto dto)
+        {
+            var waitCount = await _orderRepository.Queryable()
+             .Where(order => order.CreationTime >= dto.StartTime && order.CreationTime <= dto.EndTime)
+             .Where(order => order.Status == EOrderStatus.Filed)
+             .Select(order => SqlFunc.AggregateCount(order.Id))
+             .FirstAsync();
+
+            var publicCount = await _orderPublishRepository.Queryable()
+                .Where(publish => publish.CreationTime >= dto.StartTime && publish.CreationTime <= dto.EndTime)
+                .Where(publish => publish.PublishState == true)
+                .Select(publish => SqlFunc.AggregateCount(publish.Id))
+                .FirstAsync();
+
+            var privateCount = await _orderPublishRepository.Queryable()
+                .Where(publish => publish.CreationTime >= dto.StartTime && publish.CreationTime <= dto.EndTime)
+                .Where(publish => publish.PublishState == false)
+                .Select(publish => SqlFunc.AggregateCount(publish.Id))
+                .FirstAsync();
+
+
+            return new PublishedOrderStatisticsDto
+            {
+                // TotalCount = totalCount,
+                PrivateCount = privateCount,
+                PublicCount = publicCount,
+                WaitCount = waitCount
+            };
+        }
+
+        /// <summary>
+        /// 回访来源统计
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("visit/source")]
+        [AllowAnonymous]
+        public async Task<IList<OrderVisitSourceChannelDto>> QueryOrderVisitSourceChannelAsync([FromQuery] QueryOrderVisitSourceChannelDto dto)
+            => await _orderApplication.QueryOrderVisitSourceChannelAsync(dto);
+
+        /// <summary>
+        /// 回访来源统计--导出
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("visit/source/export")]
+        [AllowAnonymous]
+        public async Task<FileStreamResult> QueryOrderVisitSourceChannelExportAsync([FromBody] ExportExcelDto<QueryOrderVisitSourceChannelDto> dto)
+        {
+            var list = await _orderApplication.QueryOrderVisitSourceChannelAsync(dto.QueryDto);
+            if (list != null && list.Count > 0)
+            {
+                list.Add(new OrderVisitSourceChannelDto()
+                {
+                    SourceChannel = "合计",
+                    Count = list.Sum(p => p.Count)
+                });
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = list
+                .Select(stu => _mapper.Map(stu, typeof(OrderVisitSourceChannelDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "回访来源统计");
+        }
+
         /// <summary>
         /// 部门超期统计明细
         /// </summary>
@@ -343,8 +509,6 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             var query = _hotspotTypeRepository.Queryable(false, true)
                 .LeftJoin<Order>((x, o) => o.HotspotSpliceName != null && (x.HotSpotFullName == o.HotspotSpliceName || o.HotspotSpliceName.Contains(x.HotSpotFullName)) && o.IsDeleted == false)
                 .WhereIF(dto.StartTime.HasValue, (x, o) => o.CreationTime >= dto.StartTime)
@@ -364,7 +528,7 @@ namespace Hotline.Api.Controllers.Bi
         }
 
         /// <summary>
-        /// 热点数据统计
+        /// 热点数据统计 TODO和前端沟通
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
@@ -472,7 +636,6 @@ namespace Hotline.Api.Controllers.Bi
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
             if (dto.AddColumnName is null || dto.AddColumnName.Count == 0) throw UserFriendlyException.SameMessage("导出字段不能为空");
             if (dto.AddColumnName.FirstOrDefault() != "部门名称") throw UserFriendlyException.SameMessage("导出字段第一个必须是'部门名称'");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
             var (dissatisfiedReason, list) = await _orderReportApplication.QueryVisitNoSatisfiedAsync(dto, _sessionContext.OrgIsCenter);
             var dataTable = await _orderReportApplication.ExportQueryVisitNoSatisfiedAsync(dissatisfiedReason, list, dto.AddColumnName);
@@ -491,8 +654,6 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             var (dissatisfiedReason, list) = await _orderReportApplication
                 .QueryVisitNoSatisfiedAsync(_mapper.Map<QueryVisitNoSatisfiedDto>(dto), _sessionContext.OrgIsCenter);
             return new { DicReason = dissatisfiedReason, Data = list };
@@ -508,20 +669,19 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             var IsCenter = _sessionContext.OrgIsCenter;
 
             var (total, items) = await _orderVisitDetailRepository.Queryable()
                 .Includes(x => x.OrderVisit, d => d.Order)
                 .Includes(x => x.OrderVisit, d => d.Employee)
-                .Where(x => x.VisitOrgCode == dto.OrgCode)
+                //.Where(x => x.VisitOrgCode == dto.OrgCode)
                 .Where(x => x.OrderVisit.VisitState == EVisitState.Visited)
                 .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value)
                 .Where(x => x.OrderVisit.VisitTime <= dto.EndTime.Value)
                 .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(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.No.Contains(dto.Keyword) || x.OrderVisit.Order.Title.Contains(dto.Keyword))
                 .OrderBy(x => x.OrderVisit.VisitTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
@@ -640,11 +800,9 @@ namespace Hotline.Api.Controllers.Bi
         public async Task<PagedDto<OrderBiSpecialListVo>> SpecialDataList([FromQuery] ReportPagedRequest dto)
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
             var IsCenter = _sessionContext.OrgIsCenter;
 
-
             var query = _orderSpecialRepository.Queryable()
                 .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
                 .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
@@ -682,7 +840,6 @@ namespace Hotline.Api.Controllers.Bi
         public async Task<PagedDto<OrderSpecialDto>> List([FromQuery] OrderSpecialListDto dto)
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
             var IsCenter = _sessionContext.OrgIsCenter;
             var (total, items) = await _orderSpecialRepository.Queryable()
@@ -709,7 +866,7 @@ namespace Hotline.Api.Controllers.Bi
         public async Task<PagedDto<AcceptTypeTop10Vo>> AcceptTypeTop10List([FromQuery] ReportPagedRequest dto)
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
             dto.PageIndex = 1;
             dto.PageSize = 10;
             var IsCenter = _sessionContext.OrgIsCenter;
@@ -786,7 +943,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("hotport-org-statistics")]
         public async Task<object> HotPortJoinOrgStatistics([FromQuery] HotPortJoinOrgStatisticsRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var IsCenter = _sessionContext.OrgIsCenter;
             return await _orderRepository.HotPortJoinOrgStatistics(dto.StartTime, dto.EndTime, IsCenter, _sessionContext.OrgId);
         }
@@ -801,8 +957,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("visit-measure-statistics")]
         public async Task<VisitMeasureStatisticsDto> VisitMeasureStatistics(DateTime StartTime, DateTime EndTime, string? VisitName)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             var list = await _orderVisitRepository.Queryable()
                 .Includes(x => x.Employee)
                  .Where(x => x.VisitTime >= StartTime && x.VisitTime <= EndTime && x.VisitState == EVisitState.Visited)
@@ -848,8 +1002,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("hotspot-statistics")]
         public async Task<object> HotspotStatistics(DateTime StartTime, DateTime EndTime, int TypeId, string? HotspotCode)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             var IsCenter = _sessionContext.OrgIsCenter;
 
             if (string.IsNullOrEmpty(HotspotCode))
@@ -1140,6 +1292,7 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("visit-org-satisfaction-detail")]
         public async Task<PagedDto<OrgVisitDetailListResp>> VisitAndOrgSatisfactionDetail([FromQuery] VisitAndOrgSatisfactionDetailDto dto)
         {
+            //var (total, items) = await _orderApplication.VisitAndOrgSatisfactionDetail(dto)
             var (total, items) = await _orderRepository.VisitAndOrgSatisfactionDetail(dto)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
             return new PagedDto<OrgVisitDetailListResp>(total, _mapper.Map<IReadOnlyList<OrgVisitDetailListResp>>(items));
@@ -1187,8 +1340,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("center_report_forms_statistics")]
         public async Task<CenterReportStatisticsDto> CenterReportFormsStatistics(DateTime StartTime, DateTime EndTime)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             CenterReportStatisticsDto centerReportStatisticsDto = new();
 
             //信件总量
@@ -1980,7 +2131,6 @@ namespace Hotline.Api.Controllers.Bi
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             int CallCount = 2;
             var HighFrequencyCallStatistics = _systemSettingCacheManager.GetSetting(SettingConstants.HighFrequencyCallStatistics)?.SettingValue[0];
             if (HighFrequencyCallStatistics != null)
@@ -2026,7 +2176,6 @@ namespace Hotline.Api.Controllers.Bi
             if (string.IsNullOrEmpty(dto.FromPhone))
                 throw UserFriendlyException.SameMessage("号码不能为空!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             var data = await _trCallRecordRepository.Queryable()
                     .LeftJoin<Order>((p, o) => p.ExternalId == o.Id)
                    .Where((p, o) => p.OverTime >= dto.StartTime && p.OverTime <= dto.EndTime)
@@ -2062,8 +2211,9 @@ namespace Hotline.Api.Controllers.Bi
             //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
             .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
             .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo!) //联系电话
-            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
-            .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
+            //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
+            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.OrderPushTypes.Any(opt => opt.PushTypeCode == dto.PushTypeCode)) //推送分类
+			.WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
             .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
             //.WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
             .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)//工单状态
@@ -2097,9 +2247,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("highmatter-warning")]
         public async Task<PagedDto<HighMatterWarningDto>> HighMatterWarning([FromQuery] HighMatterWarningRequest dto)
         {
-
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             List<string> filterTitle = new List<string>();
             filterTitle.Add("无声");
             filterTitle.Add("骚扰");
@@ -2162,7 +2309,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("highmatter-warning-detail")]
         public async Task<PagedDto<OrderDto>> HighMatterWarningDetail([FromQuery] HighMatterWarningDetailRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             List<string> filterTitle = new List<string>();
             filterTitle.Add("无声");
             filterTitle.Add("骚扰");
@@ -2192,7 +2338,6 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             var query = _orderApplication.OrderReTransact(dto);
             var (total, items) = await query
                 .ToPagedListAsync(dto, HttpContext.RequestAborted);
@@ -2302,7 +2447,6 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             return await _orderApplication.SendOrderReportAsync(dto);
         }
 
@@ -2316,7 +2460,6 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
             var list = await _orderApplication.SendOrderReportAsync(dto.QueryDto);
 
             if (list != null && list.Count > 0)
@@ -2354,9 +2497,8 @@ namespace Hotline.Api.Controllers.Bi
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
-            var (total, items) = await _workflowStepRepository.Queryable()
+            var (total, items) = await _workflowTraceRepository.Queryable()
                 //.LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
                 .InnerJoin<SchedulingUser>((x, su) => x.HandlerId == su.UserId)
                 .Where((x, su) => x.ModuleCode == "OrderHandle" && x.BusinessType == EBusinessType.Send)
@@ -2668,7 +2810,7 @@ namespace Hotline.Api.Controllers.Bi
             foreach (var item in itemsVo)
             {
                 // item.UnsignedTime = _timeLimitDomainService.CalcWorkTimeToHour(item.WorkflowStep.CreationTime, item.WorkflowStep.Status != EWorkflowStepStatus.WaitForAccept && item.WorkflowStep.AcceptTime.HasValue ?  item.WorkflowStep.AcceptTime!.Value : DateTime.Now, false);
-                item.UnsignedTime = await _expireTime.CalcWorkTimeToHour(item.WorkflowStep.CreationTime, item.WorkflowStep.Status != EWorkflowStepStatus.WaitForAccept && item.WorkflowStep.AcceptTime.HasValue ?  item.WorkflowStep.AcceptTime!.Value : DateTime.Now, false);
+                item.UnsignedTime = await _expireTime.CalcWorkTimeToHour(item.WorkflowStep.CreationTime, item.WorkflowStep.Status != EWorkflowStepStatus.WaitForAccept && item.WorkflowStep.AcceptTime.HasValue ? item.WorkflowStep.AcceptTime!.Value : DateTime.Now, false);
             }
             return new PagedDto<UnsignedOrderDto>(total, itemsVo);
         }
@@ -2721,9 +2863,11 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("order_source_report")]
         public async Task<IReadOnlyList<OrderSourceVo>> QueryOrderSourceReport([FromQuery] QueryOrderSourceRequest dto)
         {
-            var count = await _orderApplication.QueryOrderSource(dto).CountAsync();
+            //var count = await _orderApplication.QueryOrderSource(dto).CountAsync();
             var query = _orderApplication.QueryOrderSource(dto);
-            var items = await query.GroupBy(d => d.SourceChannel).Select(d => new OrderSourceVo { Source = d.SourceChannel, Num = SqlFunc.AggregateCount(d.Id), TotalSumCount = count }).ToListAsync(HttpContext.RequestAborted);
+            var items = await query.GroupBy(d => d.SourceChannel).Select(d => new OrderSourceVo { Source = d.SourceChannel, Num = SqlFunc.AggregateCount(d.Id) }).ToListAsync(HttpContext.RequestAborted);
+            var count = items.Sum(x => x.Num);
+            items.ForEach(x => x.TotalSumCount = count);
             items.Add(new OrderSourceVo { Source = "合计", Num = count, TotalSumCount = count });
             return items;
         }
@@ -2735,8 +2879,8 @@ namespace Hotline.Api.Controllers.Bi
         [HttpPost("order_source/_export")]
         public async Task<FileStreamResult> QueryOrderSourceReport([FromBody] ExportExcelDto<QueryOrderSourceRequest> dto)
         {
-            var count = await _orderApplication.QueryOrderSource(dto.QueryDto).CountAsync();
-            var query = _orderApplication.QueryOrderSource(dto.QueryDto).GroupBy(d => d.SourceChannel).Select(d => new OrderSourceVo { Source = d.SourceChannel, Num = SqlFunc.AggregateCount(d.Id), TotalSumCount = count });
+            //var count = await _orderApplication.QueryOrderSource(dto.QueryDto).CountAsync();
+            var query = _orderApplication.QueryOrderSource(dto.QueryDto).GroupBy(d => d.SourceChannel).Select(d => new OrderSourceVo { Source = d.SourceChannel, Num = SqlFunc.AggregateCount(d.Id) });
             List<OrderSourceVo> orderSources;
             if (dto.IsExportAll)
             {
@@ -2747,6 +2891,8 @@ namespace Hotline.Api.Controllers.Bi
                 var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
                 orderSources = items;
             }
+            var count = orderSources.Sum(x => x.Num);
+            orderSources.ForEach(x => x.TotalSumCount = count);
             orderSources.Add(new OrderSourceVo { Source = "合计", Num = count, TotalSumCount = count });
             dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
             var dtos = orderSources
@@ -2974,6 +3120,7 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("org-visitdetail-list")]
         public async Task<PagedDto<OrgVisitDetailListResp>> OrgVisitDetailList([FromQuery] OrgVisitDetailListReq dto)
         {
+            //var query = _orderReportApplication.OrgVisitDetailList(dto);
             var query = _orderRepository.OrgVisitDetailList(dto);
             var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
@@ -3152,7 +3299,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("accepttype-statistics")]
         public async Task<List<AcceptTypeStatisticsDto>> AcceptTypeStatistics([FromQuery] AcceptTypeStatisticsReq dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var list = await _orderReportApplication.AcceptTypeStatistics(dto).ToListAsync();
             int SumCount = list.Sum(x => x.SumCount);
             list.Add(new AcceptTypeStatisticsDto()
@@ -3179,7 +3325,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpPost("accepttype-statistics-export")]
         public async Task<FileStreamResult> AcceptTypeStatisticsExport([FromBody] ExportExcelDto<AcceptTypeStatisticsReq> dto)
         {
-
             var list = await _orderReportApplication.AcceptTypeStatistics(dto.QueryDto).ToListAsync();
             int SumCount = list.Sum(x => x.SumCount);
             list.Add(new AcceptTypeStatisticsDto()
@@ -3243,8 +3388,6 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("area_subordinate")]
         public async Task<object> AreaSubordinate(DateTime StartTime, DateTime EndTime, int? TypeId, string? AreaCode, string? Line)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             string count = "6";
             if (!string.IsNullOrEmpty(AreaCode) && AreaCode != "511500")
                 count = (AreaCode.Length + 2).ToString();
@@ -3816,18 +3959,18 @@ namespace Hotline.Api.Controllers.Bi
         {
             var items = await _orderApplication.OrderCenterAccept(dto).ToListAsync(HttpContext.RequestAborted);
             items.Add(new OrderCenterAcceptVo
-			{
-				Time = "合计",
-				AcceptNum = items.Sum(p => p.AcceptNum),
-				ValidNum = items.Sum(p => p.ValidNum),
-				RepetitionNum = items.Sum(p => p.RepetitionNum),
-				InvalidNum = items.Sum(p => p.InvalidNum),
-				HandleNum = items.Sum(p => p.HandleNum),
-				NoHandleNum = items.Sum(p => p.NoHandleNum),
-				BackNum = items.Sum(p => p.BackNum),
-				DutyDeskNum = items.Sum(p => p.DutyDeskNum),
-			});
-			return items;
+            {
+                Time = "合计",
+                AcceptNum = items.Sum(p => p.AcceptNum),
+                ValidNum = items.Sum(p => p.ValidNum),
+                RepetitionNum = items.Sum(p => p.RepetitionNum),
+                InvalidNum = items.Sum(p => p.InvalidNum),
+                HandleNum = items.Sum(p => p.HandleNum),
+                NoHandleNum = items.Sum(p => p.NoHandleNum),
+                BackNum = items.Sum(p => p.BackNum),
+                DutyDeskNum = items.Sum(p => p.DutyDeskNum),
+            });
+            return items;
         }
         /// <summary>
         /// 中心受理统计导出
@@ -3851,17 +3994,17 @@ namespace Hotline.Api.Controllers.Bi
             }
             datas.Add(new OrderCenterAcceptVo
             {
-	            Time = "合计",
-	            AcceptNum = datas.Sum(p => p.AcceptNum),
-	            ValidNum = datas.Sum(p => p.ValidNum),
-	            RepetitionNum = datas.Sum(p => p.RepetitionNum),
-	            InvalidNum = datas.Sum(p => p.InvalidNum),
-	            HandleNum = datas.Sum(p => p.HandleNum),
-	            NoHandleNum = datas.Sum(p => p.NoHandleNum),
-	            BackNum = datas.Sum(p => p.BackNum),
-	            DutyDeskNum = datas.Sum(p => p.DutyDeskNum),
+                Time = "合计",
+                AcceptNum = datas.Sum(p => p.AcceptNum),
+                ValidNum = datas.Sum(p => p.ValidNum),
+                RepetitionNum = datas.Sum(p => p.RepetitionNum),
+                InvalidNum = datas.Sum(p => p.InvalidNum),
+                HandleNum = datas.Sum(p => p.HandleNum),
+                NoHandleNum = datas.Sum(p => p.NoHandleNum),
+                BackNum = datas.Sum(p => p.BackNum),
+                DutyDeskNum = datas.Sum(p => p.DutyDeskNum),
             });
-			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
             var dtos = datas
                 .Select(stu => _mapper.Map(stu, typeof(OrderCenterAcceptVo), dynamicClass))
                 .Cast<object>()
@@ -3879,9 +4022,9 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("center-accept-user")]
         public async Task<PagedDto<OrderCenterAcceptUserVo>> OrderCenterAcceptUser([FromQuery] OrderCenterAcceptPagedRequest dto)
         {
-			var (total, items) = await _orderApplication.OrderCenterAcceptUser(dto).ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<OrderCenterAcceptUserVo>(total, items);
-		}
+            var (total, items) = await _orderApplication.OrderCenterAcceptUser(dto).ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<OrderCenterAcceptUserVo>(total, items);
+        }
         /// <summary>
         /// 中心受理值班坐席统计导出
         /// </summary>
@@ -4040,7 +4183,7 @@ namespace Hotline.Api.Controllers.Bi
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("ordervisit-jude-statistics-export")]
-        public async Task<FileStreamResult> OrderVisitJudeStatisticsExport([FromBody]ExportExcelDto<OrderVisitJudeStatisticsReq> dto)
+        public async Task<FileStreamResult> OrderVisitJudeStatisticsExport([FromBody] ExportExcelDto<OrderVisitJudeStatisticsReq> dto)
         {
             var query = _orderApplication.OrderVisitJudeStatistics(dto.QueryDto);
             List<OrderVisitJudeStatisticsRep> exportList;

+ 50 - 20
src/Hotline.Api/Controllers/Bigscreen/SeatController.cs

@@ -1,29 +1,59 @@
 using Hotline.Application.Bigscreen;
+using Hotline.Caching.Interfaces;
+using Hotline.Settings;
+using Hotline.Share.Dtos.TrCallCenter;
+using Mapster;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
+using Tr.Sdk;
+using Tr.Sdk.Tels;
 
 namespace Hotline.Api.Controllers.Bigscreen
 {
-	public class SeatController : BaseController
-	{
-		private readonly ISeatStateDataService _seatStateDataService;
+    public class SeatController : BaseController
+    {
+        private readonly ISeatStateDataService _seatStateDataService;
+        private readonly ITrClient _trClient;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
-		public SeatController(ISeatStateDataService seatStateDataService) {
-			_seatStateDataService = seatStateDataService;
-		}
+        public SeatController(ISeatStateDataService seatStateDataService, ISystemSettingCacheManager systemSettingCacheManager, ITrClient trClient)
+        {
+            _seatStateDataService = seatStateDataService;
+            _systemSettingCacheManager = systemSettingCacheManager;
+            _trClient = trClient;
+        }
 
-		/// <summary>
-		/// 首次进入大屏获取数据
-		/// </summary>
-		/// <returns></returns>
-		[AllowAnonymous]
-		[HttpGet("base_data")]
-		public async Task<object> GetSeatStateData() {
-			var call24 = await _seatStateDataService.GetCall24(HttpContext.RequestAborted);
-			var callTop10 = await _seatStateDataService.GetCallTop10(HttpContext.RequestAborted);
-			var callList =await _seatStateDataService.GetCallList(HttpContext.RequestAborted);
-			var callAverage = await _seatStateDataService.GetCallAverage(HttpContext.RequestAborted);
-			return new object[] { call24, callTop10, callList, callAverage };
-		}
-	}
+        /// <summary>
+        /// 首次进入大屏获取数据
+        /// </summary>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpGet("base_data")]
+        public async Task<object> GetSeatStateData()
+        {
+            var call24 = await _seatStateDataService.GetCall24(HttpContext.RequestAborted);
+            var callTop10 = await _seatStateDataService.GetCallTop10(HttpContext.RequestAborted);
+            var callList = await _seatStateDataService.GetCallList(HttpContext.RequestAborted);
+            var callAverage = await _seatStateDataService.GetCallAverage(HttpContext.RequestAborted);
+
+
+            return new object[] { call24, callTop10, callList, callAverage };
+        }
+
+
+        /// <summary>
+        /// 获取监听分机
+        /// </summary>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpGet("query-listentels")]
+        public async Task<List<TelOutDto>> GetListenTels()
+        {
+            var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
+            return (await _trClient.QueryTelsAsync(new QueryTelRequest(), HttpContext.RequestAborted))
+                .Where(m => listenTels.Contains(m.TelNo))
+                .ToList()
+                .Adapt<List<TelOutDto>>();
+        }
+    }
 }

+ 13 - 0
src/Hotline.Api/Controllers/CommonPController.cs

@@ -25,6 +25,7 @@ using Hotline.Share.Dtos.Order;
 using System.Runtime.InteropServices;
 using Lucene.Net.Util;
 using NPOI.Util;
+using XF.Domain.Entities;
 
 namespace Hotline.Api.Controllers
 {
@@ -228,6 +229,12 @@ namespace Hotline.Api.Controllers
 				//待办
 				var waitedDataList = await _orderRepository
 					.Queryable(hasHandled: false, isAdmin: isAdmin)
+					.Where(d => SqlFunc.Subqueryable<WorkflowStep>()
+						.Where(step => step.ExternalId == d.Id &&
+						               ((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))))
+						.Any())
 					.Includes(d => d.OrderSpecials)
 					.Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.BackToUnAccept && d.Status != EOrderStatus.SpecialToUnAccept && d.Status != EOrderStatus.HandOverToUnAccept)
 					.Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
@@ -395,6 +402,12 @@ namespace Hotline.Api.Controllers
 				//待办
 				var waitedDataList = await _orderRepository
 					.Queryable(hasHandled: false, isAdmin: isAdmin)
+					.Where(d => SqlFunc.Subqueryable<WorkflowStep>()
+						.Where(step => step.ExternalId == d.Id &&
+						               ((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))))
+						.Any())
 					.Includes(d => d.OrderSpecials)
 					.Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.BackToUnAccept && d.Status != EOrderStatus.SpecialToUnAccept && d.Status != EOrderStatus.HandOverToUnAccept)
 					.Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)

+ 390 - 0
src/Hotline.Api/Controllers/DataSharingController.cs

@@ -0,0 +1,390 @@
+using Hotline.Application.Bulletin;
+using Hotline.Article;
+using Hotline.Caching.Interfaces;
+using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
+using Hotline.Push.Notifies;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Settings;
+using Hotline.Settings.Hotspots;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Article;
+using Hotline.Share.Dtos.DataSharingSearch;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Article;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Push;
+using MapsterMapper;
+using MediatR;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using System.Threading;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Api.Controllers
+{
+    /// <summary>
+    /// 提供给DS查询数据用
+    /// </summary>
+    public class DataSharingController : BaseController
+    {
+        private readonly IMapper _mapper;
+        private readonly IOrderRepository _orderRepository;
+        private readonly IRepository<Bulletin> _bulletinRepository;
+        private readonly IBulletinApplication _bulletinApplication;
+        private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
+        private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
+        private readonly IRepository<Hotspot> _hotspotTypeRepository;
+        private readonly IMediator _mediator;
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="mapper"></param>
+        /// <param name="orderRepository"></param>
+        /// <param name="bulletinRepository"></param>
+        /// <param name="bulletinApplication"></param>
+        /// <param name="sysDicDataCacheManager"></param>
+        /// <param name="workflowTraceRepository"></param>
+        /// <param name="hotspotTypeRepository"></param>
+        /// <param name="mediator"></param>
+        public DataSharingController(IMapper mapper,
+            IOrderRepository orderRepository,
+            IRepository<Bulletin> bulletinRepository,
+            IBulletinApplication bulletinApplication,
+            ISystemDicDataCacheManager sysDicDataCacheManager,
+            IRepository<WorkflowTrace> workflowTraceRepository,
+            IRepository<Hotspot> hotspotTypeRepository,
+            IMediator mediator)
+        {
+            _mapper = mapper;
+            _orderRepository = orderRepository;
+            _bulletinRepository = bulletinRepository;
+            _bulletinApplication = bulletinApplication;
+            _sysDicDataCacheManager = sysDicDataCacheManager;
+            _workflowTraceRepository = workflowTraceRepository;
+            _hotspotTypeRepository = hotspotTypeRepository;
+            _mediator = mediator;
+        }
+
+        /// <summary>
+        /// 查询受理类型
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("get_accept_type_list")]
+        [AllowAnonymous]
+        public async Task<List<AcceptTypeList>> GetAcceptTypeList()
+        {
+            //查询数据
+            var data = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType);
+            List<AcceptTypeList> acceptTypeList = new List<AcceptTypeList>();
+            if (data != null && data.Count > 0)
+            {
+                foreach (var item in data)
+                {
+                    acceptTypeList.Add(new AcceptTypeList()
+                    {
+                        Name = item.DicDataName,
+                        Value = item.DicDataValue
+                    });
+                }
+            }
+            return acceptTypeList;
+        }
+
+        /// <summary>
+        /// 根据工单编号和密码查询信件详情
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpPost("get_order_detail_by_no_pwd")]
+        public async Task<OrderDto> GetOrderDetail([FromBody] GetOrderNoPwdDto dto)
+        {
+            var order = await _orderRepository.Queryable()
+                  .Where(p => p.No == dto.No && p.Password == dto.Password)
+                  .WhereIF(!string.IsNullOrEmpty(dto.SourceChannelCode), p => p.SourceChannelCode == dto.SourceChannelCode)
+                  .FirstAsync();
+
+            return _mapper.Map<OrderDto>(order);
+        }
+
+        /// <summary>
+        /// 根据工单编号查询信件详情
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpPost("get_order_detail_by_no")]
+        public async Task<OrderDto> GetOrderDetailByNo([FromBody] GetOrderDetailDto dto)
+        {
+            var order = await _orderRepository.Queryable()
+                 .Where(p => p.No == dto.No)
+                 .FirstAsync();
+            return _mapper.Map<OrderDto>(order);
+        }
+
+        /// <summary>
+        /// 根据工单Id查询信件详情
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpPost("get_order_detail_by_id")]
+        public async Task<PublishDto> GetOrderDetailById([FromBody] GetOrderDetailDto dto)
+        {
+            var order = await _orderRepository.Queryable()
+                 .Includes(d => d.OrderPublish)
+                 .Where(p => p.Id == dto.Id)
+                 .FirstAsync();
+            return _mapper.Map<PublishDto>(order);
+        }
+
+        /// <summary>
+        /// 平台查询自己写入的工单
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get_order_list_own")]
+        [AllowAnonymous]
+        public async Task<PagedDto<OrderDto>> GetOrderByList([FromBody] GetOrderList dto)
+        {
+            var (total, items) = await _orderRepository.Queryable()
+                .Where(p => p.SourceChannelCode == dto.SourceChannelCode)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.Contains(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.Mobile), p => p.Contact.Contains(dto.Mobile))
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), p => p.AcceptTypeCode == dto.AcceptTypeCode)
+                .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, p => p.CreationTime < dto.EndTime)
+                .WhereIF(dto.HandleStateCode == "1", p => p.Status < EOrderStatus.Filed)
+                .WhereIF(dto.HandleStateCode == "2", p => p.Status >= EOrderStatus.Filed)
+                .OrderByDescending(p => p.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+        }
+
+        /// <summary>
+        /// 查询工单发布后公开的数据
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get_order_list_publish")]
+        [AllowAnonymous]
+        public async Task<PagedDto<PublishDto>> GetOrderByListOpen([FromBody] GetOrderList dto)
+        {
+            var (total, items) = await _orderRepository.Queryable()
+                .Includes(d => d.OrderPublish)
+                .Where(p => p.OrderPublish.PublishState == true)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.Contains(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.Mobile), p => p.Contact.Contains(dto.Mobile))
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), p => p.AcceptTypeCode == dto.AcceptTypeCode)
+                .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, p => p.CreationTime < dto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), p => p.AreaCode == dto.AreaCode)
+                .OrderByDescending(p => p.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+            return new PagedDto<PublishDto>(total, _mapper.Map<IReadOnlyList<PublishDto>>(items));
+        }
+
+        /// <summary>
+        /// 根据工单编号和密码查询流程
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get_workflow_by_no_pwd")]
+        [AllowAnonymous]
+        public async Task<List<WorkflowTraceDto>> GetWorkflowByNoPwd([FromBody] GetOrderNoPwdDto dto)
+        {
+            var order = await _orderRepository.Queryable()
+                  .Where(p => p.No == dto.No && p.Password == dto.Password)
+                  .WhereIF(!string.IsNullOrEmpty(dto.SourceChannelCode), p => p.SourceChannelCode == dto.SourceChannelCode)
+                  .FirstAsync();
+            List<WorkflowTraceDto> workflow = new();
+            if (order == null)
+                return workflow;
+
+            var data = await _workflowTraceRepository.Queryable()
+                    .Where(p => p.ExternalId == order.Id && p.ModuleCode == "OrderHandle" && p.Status == EWorkflowStepStatus.Handled && p.TraceState == EWorkflowTraceState.Normal)
+                   .OrderBy(p => p.CreationTime)
+                    .ToListAsync();
+            workflow = _mapper.Map<List<WorkflowTraceDto>>(data);
+            return workflow;
+        }
+
+        /// <summary>
+        /// 查询公告列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("query_bulletin_list")]
+        [AllowAnonymous]
+        public async Task<PagedDto<BulletinDto>> QueryBulletinList([FromBody] GetBulletinListDto dto)
+        {
+            var (total, items) = await _bulletinRepository.Queryable()
+                .Where(p => p.LoseEfficacyTime >= DateTime.Now)
+                .Where(p => SqlFunc.JsonListObjectAny(p.PushRanges, "Key", dto.PushRanges))
+                .Where(p => p.IsArrive == true && p.BulletinState == EBulletinState.ReviewPass)
+                .WhereIF(!string.IsNullOrEmpty(dto.BulletinTypeId), d => d.BulletinTypeId == dto.BulletinTypeId)
+                .OrderByDescending(p => p.BulletinTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+            return new PagedDto<BulletinDto>(total, _mapper.Map<IReadOnlyList<BulletinDto>>(items));
+        }
+
+        /// <summary>
+        /// 公告详情
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get_bulletin_detail")]
+        [AllowAnonymous]
+        public async Task<BulletinDto> GetBulletinEntity([FromBody] GetOrderDetailDto dto)
+        {
+            var model = await _bulletinRepository.Queryable()
+                .Includes(x => x.ExaminMan)
+                .FirstAsync(x => x.Id == dto.Id && x.IsArrive == true && x.BulletinState == EBulletinState.ReviewPass, HttpContext.RequestAborted);
+
+            if (model != null)
+            {
+                model.ReadedNum = model.ReadedNum++;
+                await _bulletinRepository.UpdateAsync(model, HttpContext.RequestAborted);
+            }
+
+            if (model != null && !string.IsNullOrEmpty(model.Content))
+                model.Content = _bulletinApplication.GetSiteUrls(model.Content);
+
+            return _mapper.Map<BulletinDto>(model);
+        }
+
+        /// <summary>
+        /// 今日受理分类统计
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("get_pur_type_report")]
+        [AllowAnonymous]
+        public async Task<object> GetPurTypeReport()
+        {
+            var list = await _orderRepository.Queryable()
+                 .Where(p => p.CreationTime >= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")))
+                .Where(p => p.CreationTime <= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 23:59:59")))
+                .Where(p => p.AcceptTypeCode != null && p.AcceptType != null)
+                .Select(it => new
+                {
+                    it.AcceptType,
+                    it.AcceptTypeCode
+                })
+                .MergeTable()//将查询出来的结果合并成一个新表
+                 .GroupBy(it => new { it.AcceptType, it.AcceptTypeCode })//对新表进行分组
+                 .Select(it => new
+                 {
+                     PurTypeName = it.AcceptType,
+                     Count = SqlFunc.AggregateCount(it.AcceptTypeCode)
+                 })
+                 .ToListAsync();
+            return list;
+        }
+
+        /// <summary>
+        /// 今日统计
+        /// </summary>
+        /// <returns></returns>
+        [AllowAnonymous]
+        [HttpPost("get_day_count")]
+        public async Task<object> GetDayCount()
+        {
+            //今日已办结
+            var dayTrandCount = await _orderRepository.Queryable().Where(p => p.CreationTime >= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")) &&
+            p.CreationTime <= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 23:59:59")) && p.Status >= EOrderStatus.Filed).CountAsync();
+
+            //今日总量
+            var dayCount = await _orderRepository.Queryable().Where(p => p.CreationTime >= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")) &&
+            p.CreationTime <= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 23:59:59"))).CountAsync();
+
+            //总共已办结
+            var allTrandCount = await _orderRepository.Queryable().Where(p => p.Status >= EOrderStatus.Filed).CountAsync();
+
+            //总共总量
+            var allCount = await _orderRepository.Queryable().Where(p => p.Status >= EOrderStatus.WaitForAccept).CountAsync();
+
+            return new { DayTrandCount = dayTrandCount, DayCount = dayCount, AllTrandCount = allTrandCount, AllCount = allCount };
+
+        }
+
+        /// <summary>
+        /// 查询热点分类
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("get_hotspot_statistics_list")]
+        [AllowAnonymous]
+        public async Task<object> GetHotspotStatistics()
+        {
+            var list = await _hotspotTypeRepository.Queryable()
+                .LeftJoin<Order>((it, o) => it.Id == o.HotspotId)
+                .Where((it, o) => o.CreationTime >= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")))
+                .Where((it, o) => o.CreationTime <= Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 23:59:59")))
+                .Where((it, o) => o.Id != null && o.HotspotId != null)
+                .GroupBy((it, o) => new { Id = it.Id.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("2")) })
+                .Select((it, o) => new
+                {
+                    HotspotCode = it.Id.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("2")),
+                    SumCount = SqlFunc.AggregateCount(it.HotSpotName)
+                })
+                .MergeTable()
+                .LeftJoin<Hotspot>((x, q) => x.HotspotCode == q.Id)
+                .Select((x, q) => new
+                {
+                    Name = q.HotSpotName,
+                    Value = x.SumCount
+                })
+                .ToListAsync();
+
+            return list;
+        }
+
+        /// <summary>
+        ///  随手拍网格员-短信接口
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("grid_operator_send_sms")]
+        [AllowAnonymous]
+        public async Task<string> GridOperatorSendSms([FromBody] GridOperatorSendSmsDto dto)
+        {
+            if (dto == null)
+                return "数据获取失败";
+            var order = await _orderRepository.GetAsync(p => p.No == dto.ReplyCode, HttpContext.RequestAborted);
+            if (order == null)
+                return "工单查询失败";
+
+            var messageDto = new Share.Dtos.Push.MessageDto
+            {
+                PushBusiness = EPushBusiness.OrderSend,
+                ExternalId = order.Id,
+                OrderId = order.Id,
+                PushPlatform = EPushPlatform.Sms,
+                Remark = order.Title,
+                Name = dto.MemberName,
+                TemplateCode = "1010",
+                Params = new List<string>() { dto.AppealNumber },
+                TelNumber = dto.MemberMobile,
+
+            };
+            if (dto.SendType == "2")
+            {
+                messageDto.TemplateCode = "1011";
+                messageDto.PushBusiness= EPushBusiness.OrderExpire;
+            }
+
+            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
+            return "提交成功";
+        }
+    }
+}

+ 3 - 20
src/Hotline.Api/Controllers/EnforcementOrderController.cs

@@ -104,8 +104,9 @@ namespace Hotline.Api.Controllers
            //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.Order.EmergencyLevel))  //紧急程度
            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.Order.FromPhone.Contains(dto.FromPhone)) //来电号码
            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Order.Contact.Contains(dto.PhoneNo!)) //联系电话
-           .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.Order.PushTypeCode == dto.PushTypeCode) //推送分类
-           .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.Order.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
+           //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.Order.PushTypeCode == dto.PushTypeCode) //推送分类
+           .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.Order.OrderPushTypes.Any(opt=> opt.PushTypeCode == dto.PushTypeCode)) //推送分类
+		   .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.Order.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
            .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.Order.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
            .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Order.Status))  //工单状态
            .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Order.Status <= EOrderStatus.SpecialToUnAccept)
@@ -271,9 +272,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("event_classification_statistics")]
         public async Task<object> GetEventClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime, string Id, string AreaCode)
         {
-
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             var items = await _judicialComplaintsEventTypeRepository.Queryable()
              .LeftJoin<EnforcementOrders>((x, o) => o.EventTypeSpliceName != null && (x.EventTypeName == o.EventTypeSpliceName || o.EventTypeSpliceName.Contains(x.EventTypeName)))
             .LeftJoin<Order>((x, o, p) => p.Id == o.Id)
@@ -324,8 +322,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("event_classification_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetEventClassificationStatisticsOrderListAsync([FromQuery] QueryEventClassificationStatisticsDto dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             var (total, items) = await _enforcementOrdersRepository.Queryable()
             .Includes(x => x.Order)
             .Where(d => d.Order.Id != null)
@@ -347,8 +343,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_departmental_processing_statistics")]
         public async Task<object> GetDepartmentalProcessingStatisticsAsync(DateTime StartTime, DateTime EndTime)
         {
-
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
             var data = await _enforcementOrdersRepository.Queryable()
                    .Includes(x => x.Order)
                    .Where(d => d.Order.Id != null)
@@ -382,8 +376,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_departmental_processing_statistics_child")]
         public async Task<object> GetDepartmentalProcessingStatisticsChildAsync(DateTime StartTime, DateTime EndTime, string OrgCode)
         {
-
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
             if (string.IsNullOrEmpty(OrgCode))
                 throw UserFriendlyException.SameMessage("部门code不能为空!");
 
@@ -421,8 +413,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_departmental_processing_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetDepartmentalProcessingStatisticsOrderListAsync([FromQuery] QueryDepartmentalProcessingStatisticsDto dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             var (total, items) = await _enforcementOrdersRepository.Queryable()
             .Includes(x => x.Order)
             .Where(d => d.Order.Id != null)
@@ -445,7 +435,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("regional_classification_statistics")]
         public async Task<object> GetRegionalClassificationStatisticsAsync(DateTime StartTime, DateTime EndTime)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
             var areaCode = _sessionContext.OrgAreaCode ?? "511500";
             var list = await _enforcementOrdersRepository.Queryable()
                .Includes(x => x.Order)
@@ -482,8 +471,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("regional_classification_statistics_order_list")]
         public async Task<PagedDto<EnforcementOrderListDto>> GetRegionalClassificationStatisticsOrderListAsync([FromQuery] QueryRegionalClassificationStatisticsDto dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             var (total, items) = await _enforcementOrdersRepository.Queryable()
             .Includes(x => x.Order)
             .Where(d => d.Order.Id != null)
@@ -508,8 +495,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_visit_org_satisfaction_statistics")]
         public async Task<object> GetVisitAndOrgSatisfactionStatisticsAsync(DateTime StartTime, DateTime EndTime, int TypeId)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             var list = await _enforcementOrdersRepository.Queryable()
                  .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
                  .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)
@@ -577,8 +562,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("enforcement_visit_org_satisfaction_statistics_child")]
         public async Task<object> GetVisitAndOrgSatisfactionStatisticsChildAsync(DateTime StartTime, DateTime EndTime, int TypeId, string OrgCode)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             var list = await _enforcementOrdersRepository.Queryable()
                  .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
                  .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)

+ 24 - 22
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -120,6 +120,8 @@ namespace Hotline.Api.Controllers
         public async Task<List<TrTelDto>> TrQueryTels()
         {
             var tels = await _trClient.QueryTelsAsync(new QueryTelRequest() { }, HttpContext.RequestAborted);
+            var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
+            tels = tels.Where(m => listenTels.Contains(m.TelNo) ==  false).ToList();
             var returnlist = _mapper.Map<List<TrTelDto>>(tels);
             string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
             returnlist.ForEach(x =>
@@ -136,10 +138,10 @@ namespace Hotline.Api.Controllers
         /// <returns></returns>
         [HttpGet("query-telstate")]
         [AllowAnonymous]
-        public async Task<IReadOnlyList<TrTelStateDto>> TrQueryTelState([FromQuery] string? state)
+        public async Task<IReadOnlyList<TrTelStateDto>> TrQueryTelState([FromQuery] string? state, bool hasListen)
         {
             var tels = await _trClient.QueryTelStateAsync(new QueryTelStateRequest() { State = state }, HttpContext.RequestAborted);
-            //var workList = _userCacheManager.GetWorks();
+            var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
             var workList = await _workRepository.Queryable().Where(d=> 1 == 1 && !d.EndTime.HasValue).ToListAsync();
             var query = from tel in tels.AgentList
                         join works in workList on tel.TelNo equals works.TelNo into workD
@@ -168,6 +170,10 @@ namespace Hotline.Api.Controllers
                             WorkUserId = (work != null) ? work.UserId: "",
                             WorkUserName = (work != null) ? work.UserName: "",
                         };
+            if (hasListen == false)
+            {
+                query = query.Where(m => listenTels.Contains(m.TelNo) == false);
+            }
             var list = query.OrderBy(x=>x.TelNo).OrderByDescending(x=>x.CreatedAt).ToList();
             return list;// _mapper.Map<IReadOnlyList<TrTelStateDto>>(tels.AgentList);
         }
@@ -182,6 +188,10 @@ namespace Hotline.Api.Controllers
         public async Task<TrTelStateDto> TrQueryTelStateByTelNo([FromQuery]string? telno)
         {
             var tels = await _trClient.QueryTelStateAsync(new QueryTelStateRequest() { TelNo = telno }, HttpContext.RequestAborted);
+
+            var listenTels = _systemSettingCacheManager.GetSetting(SettingConstants.ListenTels)?.SettingValue;
+            tels.Agents = tels.Agents?.Where(m => listenTels.Contains(m.TelNo) == false).ToList();
+
             var tel = tels.Agents?.FirstOrDefault();
             if (tel != null)
             {
@@ -615,21 +625,19 @@ namespace Hotline.Api.Controllers
             }
             await _trCallRecordRepository.AddAsync(model, HttpContext.RequestAborted);
 
-            if (model.CallDirection == ECallDirection.In)
+           
+            var publishCallRecordDto = new PublishCallRecrodDto() { };
+            if (order != null)
             {
-                var publishCallRecordDto = new PublishCallRecrodDto() { };
-                if (order != null)
-                {
-                    var orderDto = _mapper.Map<OrderDto>(order);
-                    publishCallRecordDto.Order = orderDto;
-                }
-                var trCallDto = _mapper.Map<TrCallDto>(model);
-                publishCallRecordDto.TrCallRecordDto = trCallDto;
-                if (string.IsNullOrEmpty(model.AgentTransferNumber))
-                {
-                    //推省上
-                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallBye, publishCallRecordDto);
-                }
+                var orderDto = _mapper.Map<OrderDto>(order);
+                publishCallRecordDto.Order = orderDto;
+            }
+            var trCallDto = _mapper.Map<TrCallDto>(model);
+            publishCallRecordDto.TrCallRecordDto = trCallDto;
+            if (string.IsNullOrEmpty(model.AgentTransferNumber))
+            {
+                //推省上
+                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallBye, publishCallRecordDto);
             }
 
             return OpenResponse.Ok("success");
@@ -820,12 +828,6 @@ namespace Hotline.Api.Controllers
         [HttpGet("telaction-list")]
         public async Task<PagedDto<TelActionListRep>> TelActionList([FromQuery] TelActionListDto dto)
         {
-            if (!dto.EndTime.HasValue)
-            {
-                dto.EndTime = DateTime.Now.Date;
-            }
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             var (total,items) = await _telActionRecordRepository.Queryable()
                 .WhereIF(string.IsNullOrEmpty(dto.TelNo) == false, x => x.TelNo.Contains(dto.TelNo))
                 .WhereIF(dto.ActionTtype != null, x => x.ActionType == dto.ActionTtype)

Різницю між файлами не показано, бо вона завелика
+ 289 - 359
src/Hotline.Api/Controllers/OrderController.cs


+ 10 - 4
src/Hotline.Api/Controllers/SettingController.cs

@@ -180,13 +180,19 @@ namespace Hotline.Api.Controllers
         [HttpPost("setdaysettings")]
         public async Task SetDaySettings([FromBody]SetDaySettingsRequest request)
         {
-            List<DaySetting> daysettings = new List<DaySetting>();
             foreach (var item in request.list)
             {
-                daysettings.Add(new DaySetting() { Day = item, IsWorkDay = request.isWorkDay });
+                var day = await _daysettingRepository.GetAsync(x => x.Day.Date == item.Date, HttpContext.RequestAborted);
+                if (day != null)
+                {
+                    day.IsWorkDay = request.isWorkDay;
+                    await _daysettingRepository.UpdateAsync(day, HttpContext.RequestAborted);
+                }
+                else
+                {
+                    await _daysettingRepository.AddAsync(new DaySetting() { Day = item, IsWorkDay = request.isWorkDay },HttpContext.RequestAborted);
+                }
             }
-
-            await _daysettingRepository.AddRangeAsync(daysettings);
         }
 
         #endregion

+ 270 - 428
src/Hotline.Api/Controllers/TestController.cs

@@ -14,6 +14,7 @@ using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Configs;
 using Hotline.CallCenter.Ivrs;
 using Hotline.CallCenter.Tels;
+using Hotline.Configurations;
 using Hotline.ContingencyManagement;
 using Hotline.FlowEngine;
 using Hotline.FlowEngine.Definitions;
@@ -44,6 +45,7 @@ using Hotline.Users;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Builder.Extensions;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 using MiniExcelLibs;
@@ -117,14 +119,16 @@ public class TestController : BaseController
     private readonly IRepository<Tel> _telRepository;
     private readonly IOrderDomainService _orderDomainService;
     private readonly ICallApplication _callApplication;
+    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     //private readonly ITypedCache<List<User>> _cache;
     //private readonly ICacheManager<User> _cache;
     private readonly ICalcExpireTime _expireTime;
+    private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
 
-    public TestController(
+	public TestController(
         //INewRockClient client,
         ILogger<TestController> logger,
         //IAuthorizeGenerator authorizeGenerator,
@@ -143,7 +147,7 @@ public class TestController : BaseController
         IDistributedLock distributedLock,
         IRepository<OrderUrge> orderUrgeRepository,
         IRepositoryTextSearch<OrderTs> repositoryts,
-        //ITimeLimitDomainService timeLimitDomainService,
+        ITimeLimitDomainService timeLimitDomainService,
         IWfModuleDomainService wfModuleDomainService,
         IDaySettingRepository daySettingRepository,
         //ITrClient trClient,
@@ -170,9 +174,12 @@ IRepository<EnforcementOrdersHandler> enforcementOrdersHandlerRepository,
 IRepository<ContingencyManagementHotspot> contingencyManagementHotspotRepository,
 IRepository<Hotspot> hotspotRepository,
 IOrderDomainService orderDomainService,
-ICallApplication callApplication
-,
-ICalcExpireTime expireTime)
+ICallApplication callApplication,
+        IOptionsSnapshot<AppConfiguration> appOptions,
+        ISystemSettingCacheManager systemSettingCacheManager,
+        ICalcExpireTime expireTime,
+        IOptions<CityBaseConfiguration> cityBaseConfiguration
+		)
     {
         _logger = logger;
         //_authorizeGenerator = authorizeGenerator;
@@ -189,7 +196,7 @@ ICalcExpireTime expireTime)
         _distributedLock = distributedLock;
         _orderUrgeRepository = orderUrgeRepository;
         _repositoryts = repositoryts;
-        //_timeLimitDomainService = timeLimitDomainService;
+        _timeLimitDomainService = timeLimitDomainService;
         _wfModuleDomainService = wfModuleDomainService;
         _daySettingRepository = daySettingRepository;
         //_trClient = trClient;
@@ -218,8 +225,11 @@ ICalcExpireTime expireTime)
         _telRepository = telRepository;
         _orderDomainService = orderDomainService;
         _callApplication = callApplication;
+        _appOptions = appOptions;
+        _systemSettingCacheManager = systemSettingCacheManager;
         _expireTime = expireTime;
-    }
+        _cityBaseConfiguration = cityBaseConfiguration;
+	}
 
 
     [HttpGet("time")]
@@ -273,6 +283,8 @@ ICalcExpireTime expireTime)
         //var r = await _aiVisitService.QueryAiVisitTaskResult(batchId, DateTime.Parse("2024-07-28"), DateTime.Parse("2024-08-01"), HttpContext.RequestAborted);
 
         //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);
+
 
         return OpenResponse.Ok(DateTime.Now.ToString("F"));
     }
@@ -440,14 +452,14 @@ ICalcExpireTime expireTime)
             foreach (var item in list)
             {
                 var creationTimeHandleDurationWorkday = item.FiledTime.HasValue
-                  ? 
+                  ?
                   //_timeLimitDomainService.CalcWorkTimeEx(
                   await _expireTime.CalcWorkTimeEx(
                       item.CreationTime, item.FiledTime.Value,
                   item.ProcessType is EProcessType.Zhiban)
                   : 0;
                 var centerToOrgHandleDurationWorkday = item.FiledTime.HasValue && item.CenterToOrgTime.HasValue
-                    ? 
+                    ?
                     //_timeLimitDomainService.CalcWorkTimeEx(
                     await _expireTime.CalcWorkTimeEx(
                         item.CenterToOrgTime.Value, item.FiledTime.Value,
@@ -659,7 +671,7 @@ ICalcExpireTime expireTime)
     [HttpGet("t2")]
     public async Task<string> GetCacheAllowAnonymous()
     {
-        var systemAdministrator = _systemSettingCacheManager.GetSetting(SettingConstants.SystemAdministrator)?.SettingValue[0]; 
+        var systemAdministrator = _systemSettingCacheManager.GetSetting(SettingConstants.SystemAdministrator)?.SettingValue[0];
         return systemAdministrator;
     }
 
@@ -670,215 +682,24 @@ ICalcExpireTime expireTime)
         return systemAdministrator;
     }
 
-    [AllowAnonymous]
-    [HttpPost("t3")]
-    public async Task TestExportExcel()
+    [HttpGet("t4")]
+    public async Task<string> Test4()
     {
-        var orders = await _orderRepository.Queryable()
-            //.Includes(d => d.Workflow, x => x.Steps.Where(d => d.BusinessType == EBusinessType.Send))
-            //.Where(d=>d.Workflow.Steps.Any(d=>d.BusinessType == EBusinessType.Send))
-            .Where(d => d.Status != EOrderStatus.WaitForAccept && d.CenterToOrgTime == null)
-            .ToListAsync(HttpContext.RequestAborted);
-
-        var orderIds = orders.Select(d => d.Id).ToList();
-        var steps = await _workflowStepRepository.Queryable()
-            .Where(d => orderIds.Contains(d.ExternalId) &&
-                        d.BusinessType == EBusinessType.Send &&
-                        d.Status == EWorkflowStepStatus.Handled)
-            .OrderBy(d => d.CreationTime)
-            .ToListAsync(HttpContext.RequestAborted);
-
-        _logger.LogWarning($"取到steps: {steps.Count} 条");
-        var updateOrders = new List<Order>();
-        foreach (var order in orders)
-        {
-            var step = steps.Where(d => d.ExternalId == order.Id)
-                .OrderBy(d => d.CreationTime)
-                .FirstOrDefault();
-            if (step is null) continue;
-
-            order.CenterToOrgTime = step.HandleTime;
-            order.CenterToOrgHandlerId = step.HandlerId;
-            order.CenterToOrgHandlerName = step.HandlerName;
-            order.CenterToOrgOpinion = step.Opinion;
-
-            var handleDuration = order.CenterToOrgTime.HasValue && order.ActualHandleTime.HasValue
-                ? 
-                // _timeLimitDomainService.CalcWorkTime(
-                await _expireTime.CalcWorkTime(
-                    order.CenterToOrgTime.Value,
-                    order.ActualHandleTime.Value, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var fileDuration = order.CenterToOrgTime.HasValue && order.FiledTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.CenterToOrgTime.Value, order.FiledTime.Value, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            //var allDuration = order.StartTime.HasValue
-            //    ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, order.FiledTime.Value,
-            //        order.ProcessType is EProcessType.Zhiban)
-            //    : 0;
-            order.SetHandleDuration();
-            order.SetFileDuration();
-
-            order.HandleDurationWorkday = handleDuration;
-            order.FileDurationWorkday = fileDuration;
-
-            updateOrders.Add(order);
-        }
-
-        _logger.LogWarning($"更新工单:{updateOrders.Count} 条");
-        await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
-    }
-
-    [AllowAnonymous]
-    [HttpPost("t4")]
-    public async Task TestExportExcel1()
-    {
-        var numbers = new List<string>
-        {
-            "20240623000180",
-            "20240622000097",
-            "20240621000055",
-            "20240622000185",
-            "20240623000025",
-            "20240621000099",
-            "20240621000270",
-            "20240622000060",
-            "20240621000144",
-        };
-
-        var orders = await _orderRepository.Queryable()
-            .Includes(d => d.OrderExtension)
-            .Where(d => numbers.Contains(d.No))
-            .ToListAsync(HttpContext.RequestAborted);
-        _logger.LogWarning($"order count: {orders.Count}");
-
-        var workflowIds = orders.Select(d => d.WorkflowId).ToList();
-        var workflows = await _workflowRepository.Queryable()
-            .Includes(d => d.Steps, x => x.WorkflowTrace)
-            .Where(d => workflowIds.Contains(d.Id))
-            .ToListAsync(HttpContext.RequestAborted);
-
-        //var workflowIds = orders.Select(d => d.WorkflowId).ToList();
-        //var workflows = await _workflowRepository.Queryable()
-        //    .Includes(d => d.Steps, x => x.WorkflowTrace)
-        //    //.Includes(d=>d.Traces)
-        //    .Where(d => workflowIds.Contains(d.Id))
-        //    .ToListAsync(HttpContext.RequestAborted);
-
-        var updateOrders = new List<Order>();
-        foreach (var order in orders)
-        {
-            var workflow = workflows.First(d => d.Id == order.WorkflowId);
-
-            _mapper.Map(workflow, order);
-            var now = order.FiledTime.Value;//DateTime.Now;
-            var handleDuration = order.StartTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.StartTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var fileDuration = order.CenterToOrgTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.CenterToOrgTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var allDuration = order.StartTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.StartTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
-                   ? await _expireTime.CalcWorkTime(order.CreationTime, now, order.ProcessType is EProcessType.Zhiban)
-                   : 0;
-            var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.CenterToOrgTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-
-            //order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
-
-            order.HandleDurationWorkday = handleDuration;
-            order.FileDurationWorkday = fileDuration;
-            order.AllDurationWorkday = allDuration;
-            order.CreationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday;
-            order.CenterToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday;
-
-            //计算实际办结时长
-            order.SetHandleDuration();
-            order.SetFileDuration();
-            order.SetAllDuration();
-            order.SetCreationTimeHandleDurationWorkday();
-            order.SetCenterToOrgHandleDurationWorkday();
-
-            var endStep = workflow.Steps.FirstOrDefault(d => d.StepType == EStepType.End);
-            //var endTrace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.StepType == EStepType.End)?.WorkflowTrace;
-            if (endStep is null)
-            {
-                _logger.LogWarning($"endStep 为空, orderNo:{order.No}");
-                continue;
-            }
-
-            var step = workflow.Steps.FirstOrDefault(d => d.Id == endStep.PrevStepId);
-            //var trace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.Id == endTrace.PrevStepId)?.WorkflowTrace;
-            if (step is null)
-            {
-                _logger.LogWarning($"step 为空, orderNo:{order.No}");
-                continue;
-            }
-
-            var trace = step.WorkflowTrace;
-            order.FileUserId = trace.HandlerId;
-            order.FileUserName = trace.HandlerName;
-            order.FileUserOrgId = trace.HandlerOrgId;
-            order.FileUserOrgName = trace.HandlerOrgName;
-            order.FileOpinion = trace.Opinion;
-
-            //记录冗余归档数据
-            if (workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
-            {
-                order.FileUserRole = EFileUserType.Dispatch;
-            }
-            else
-            {
-                order.FileUserRole = EFileUserType.Seat;
-            }
-            if (order.ProcessType == EProcessType.Jiaoban)
-            {
-                order.FileUserRole = EFileUserType.Org;
-            }
-
-            ////是否已解决
-            //order.IsResolved = true;//notification.Dto.External == null ? false : notification.Dto.External.IsResolved;
-
-            //await _orderRepository.UpdateAsync(order, cancellationToken);
-            updateOrders.Add(order);
-
-            //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
-            var orderFlowDto = new OrderFlowDto
-            {
-                Order = _mapper.Map<OrderDto>(order),
-                WorkflowTrace = _mapper.Map<WorkflowTraceDto>(trace)
-            };
-            var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, HttpContext.RequestAborted);
-            if (callRecord != null)
-            {
-                orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
-            }
-            //这里需要判断是否是警情退回
-            orderFlowDto.IsNonPoliceReturn = false;//notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
-            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: HttpContext.RequestAborted);
-            //写入质检  针对受理之后直接结束的工单
-            await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, HttpContext.RequestAborted);
-
-            //司法行政监督管理-工单处理
-            //await _enforcementApplication.AddEnforcementOrderAsync(order, HttpContext.RequestAborted);
-        }
-
-        //_logger.LogWarning($"更新orders:{updateOrders.Count}");
-        //await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
+        return DateTime.Now.ToString("O");
     }
 
     [AllowAnonymous]
     [HttpGet("t5")]
     public async Task<string> GetUserAllowAnonymous()
     {
-        var users = await _userRepository.Queryable()
-            .FirstAsync(d => d.Name == "xf", HttpContext.RequestAborted);
-        return users.Id;
-    }
+        //var users = await _userRepository.Queryable()
+        //    .FirstAsync(d => d.Name == "xf", HttpContext.RequestAborted);
+        //return users.Id;
+        var b = _cityBaseConfiguration.Value;
+
+		var a = await _expireTime.WorkDay_ZG(DateTime.Now);
+        return string.Empty;
+	}
 
     [HttpGet("t6")]
     public async Task<string> GetUserWithAuth()
@@ -897,234 +718,255 @@ ICalcExpireTime expireTime)
         return $"{publicKey} \r\n {privateKey}";
     }
 
-    /// <summary>
-    /// 处理错误工单数据
-    /// </summary>
-    /// <returns></returns>
-    [HttpGet("handle-order-data")]
     [AllowAnonymous]
-    public async Task HandleData()
+    [HttpGet("republish")]
+    public async Task Republish()
     {
-        //var steps = await _workflowStepRepository.Queryable()
-        //    .LeftJoin<Order>((ws, d) => ws.ExternalId == d.Id)
-        //    .Where((ws, d) => d.Status == EOrderStatus.Handling && d.ProcessType == EProcessType.Zhiban && ws.Status == EWorkflowStepStatus.Handled && ws.StepType == EStepType.End)
-        //    .ToListAsync(HttpContext.RequestAborted);
-        var steps = await _workflowStepRepository.Queryable()
-            .LeftJoin<Order>((ws, d) => ws.ExternalId == d.Id)
-            .Where((ws, d) => d.Status == EOrderStatus.Handling && d.ProcessType == EProcessType.Zhiban && ws.Status == EWorkflowStepStatus.Handled && ws.StepType == EStepType.End)
-            .ToListAsync(HttpContext.RequestAborted);
-
-        _logger.LogInformation($"取到数据{steps.Count}条");
-        foreach (var step in steps)
+        var provinceNos = new List<string>
         {
-            var order = await _orderDomainService.GetOrderAsync(step.ExternalId,
-                        withExtension: true, cancellationToken: HttpContext.RequestAborted);
-            var now = step.HandleTime.Value;
-            var handleDuration = order.CenterToOrgTime.HasValue && order.ActualHandleTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.CenterToOrgTime.Value, order.ActualHandleTime.Value, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var fileDuration = order.CenterToOrgTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.CenterToOrgTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var allDuration = order.StartTime.HasValue
-                ? await _expireTime.CalcWorkTime(order.StartTime.Value, now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
-                ? 
-                // _timeLimitDomainService.CalcWorkTimeEx(order.CreationTime, now,
-                await _expireTime.CalcWorkTimeEx(order.CreationTime, now,
-                order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
-                ? 
-                // _timeLimitDomainService.CalcWorkTimeEx(
-                await _expireTime.CalcWorkTimeEx(
-                    order.CenterToOrgTime.Value, now,
-                order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
-            order.FileUserId = step.HandlerId;// notification.Trace.HandlerId;
-            order.FileUserName = step.HandlerName;// notification.Trace.HandlerName;
-            order.FileUserOrgId = step.HandlerOrgId;// notification.Trace.HandlerOrgId;
-            order.FileUserOrgName = step.HandlerOrgName;// notification.Trace.HandlerOrgName;
-            order.FileOrgIsCenter = step.HandlerOrgIsCenter; //notification.Trace.HandlerOrgIsCenter;
-            order.FileOpinion = step.Opinion;//.Dto.Opinion;
-            order.FileUserRole = EFileUserType.Seat;
-            order.IsResolved = false;
-
-
-            order.ActualHandleStepCode = step.Code;
-            order.ActualHandleStepName = step.Name;
-            order.ActualHandleStepId = step.Id;
-            order.ActualHandleStepCreateTime = step.CreationTime;
-            order.ActualHandleStepAcceptTime = step.AcceptTime;
-            order.ActualHandleTime = step.HandleTime;
-            order.ActualHandlerId = step.HandlerId;
-            order.ActualHandlerName = step.HandlerName;
-            order.ActualHandleOrgCode = step.HandlerOrgId;
-            order.ActualHandleOrgName = step.HandlerOrgName;
-            order.ActualHandleOrgAreaCode = step.HandlerOrgAreaCode;
-            order.ActualHandleOrgAreaName = step.HandlerOrgAreaName;
-
-
-            order.CurrentStepId = order.ActualHandleStepId;
-            order.CurrentStepCode = order.ActualHandleStepCode;
-            order.CurrentStepName = order.ActualHandleStepName;
-            order.CurrentStepCreateTime = order.ActualHandleStepCreateTime;
-            order.CurrentStepAcceptTime = order.ActualHandleStepAcceptTime;
-            order.CurrentHandleTime = order.ActualHandleTime;
-            order.CurrentHandlerId = order.ActualHandlerId;
-            order.CurrentHandlerName = order.ActualHandlerName;
-            order.CurrentHandleOrgName = order.ActualHandleOrgName;
-            order.CurrentHandleOrgId = order.ActualHandleOrgCode;
-            order.CurrentHandleOrgAreaCode = order.ActualHandleOrgAreaCode;
-            order.CurrentHandleOrgAreaName = order.ActualHandleOrgAreaName;
-
-            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-            //var workflowTrace = await _workflowTraceRepository.Queryable().Where(x => x.WorkflowId == step.WorkflowId && x.Code == "end").OrderByDescending(x=>x.HandleTime).FirstAsync();
-            //var orderFlowDto = new OrderFlowDto
-            //{
-            //    Order = _mapper.Map<OrderDto>(order)
-            //};
-            //if (workflowTrace!=null)
-            //{
-            //    orderFlowDto.WorkflowTrace = _mapper.Map<WorkflowTraceDto>(workflowTrace);
-            //}
-            //if (order.SourceChannelCode == AppDefaults.SourceChannel.DianHua &&
-            //            !string.IsNullOrEmpty(order.CallId))
-            //{
-
-            //    var call = await _callApplication.GetCallAsync(order.CallId, HttpContext.RequestAborted);
-            //    if (call is not null)
-            //        orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(call);
-            //}
-            //await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: HttpContext.RequestAborted);
-        }
-    }
-
-    /// <summary>
-    /// 处理工单流程错误数据   话务部直接归档件  没有归档节点
-    /// </summary>
-    /// <param name="StartTime"></param>
-    /// <param name="EndTime"></param>
-    /// <returns></returns>
-    [HttpGet("oders_workflow_step")]
-    [AllowAnonymous]
-    public async Task AddJudicialManagementOrders()
-    {
+            "RGDH9951150024082950312",
+"RGDH9951150024080750198",
+"RGDH9951150024083050009",
+"RGDH9951150024083150167",
+"RGDH9951150024083150102",
+"RGDH9951150024083050052",
+"RGDH9951150024080750184",
+"RGDH9951150024083050108",
+"RGDH9951150024083050314",
+"RGDH9951150024083050363",
+"RGDH9951150024083150243",
+"RGDH9951150024082850303",
+"QT9951150024082150023",
+"RGDH9951150024080750185",
+"RGDH9951150024083150065",
+"RGDH9951150024082850032",
+"RGDH9951150024082950295",
+"RGDH9951150024080750189",
+"RGDH9951150024082650189",
+"RGDH9951150024083050008",
+"RGDH9951150024082950036",
+"RGDH9951150024082850341",
+"RGDH9951150024080750215",
+"RGDH9951150024081450005",
+"RGDH9951150024080750212",
+"RGDH9951150024083050137",
+"RGDH9951150024082450124",
+"RGDH9951150024083150188",
+"RGDH9951150024083150083",
+"RGDH9951150024082850082",
+"RGDH9951150024080750174",
+"RGDH9951150024082950371",
+"RGDH9951150024082950114",
+"RGDH9951150024083050339",
+"RGDH9951150024080750217",
+"RGDH9951150024082950040",
+"RGDH9951150024083050031",
+"RGDH9951150024083150267",
+"RGDH9951150024083050064",
+"RGDH9951150024072650086",
+"RGDH9951150024082950360",
+"RGDH9951150024080750195",
+"RGDH9951150024080750210",
+"RGDH9951150024082950250",
+"RGDH9951150024083050145",
+"RGDH9951150024083050356",
+"RGDH9951150024080750194",
+"RGDH9951150024080750173",
+"RGDH9951150024080750213",
+"RGDH9951150024080750218",
+"RGDH9951150024083150271",
+"RGDH9951150024083150134",
+"RGDH9951150024080750179",
+"RGDH9951150024083050140",
+"RGDH9951150024083150262",
+"RGDH9951150024083050119",
+"RGDH9951150024083150177",
+"RGDH9951150024083050146",
+"RGDH9951150024080750223",
+"RGDH9951150024080750221",
+"RGDH9951150024083150130",
+"RGDH9951150024080750209",
+"RGDH9951150024083150237",
+"RGDH9951150024082850095",
+"RGDH9951150024082850223",
+"RGDH9951150024083050077",
+"RGDH9951150024082950118",
+"RGDH9951150024082850056",
+"RGDH9951150024082550177",
+"RGDH9951150024083050358",
+"RGDH9951150024080750193",
+"RGDH9951150024082150011",
+"RGDH9951150024082950167",
+"RGDH9951150024083050201",
+"RGDH9951150024082850048",
+"RGDH9951150024083150161",
+"RGDH9951150024083050300",
+"RGDH9951150024083150016",
+"RGDH9951150024083150101",
+"RGDH9951150024082850207",
+"RGDH9951150024083150144",
+"RGDH9951150024082750300",
+"RGDH9951150024083050230",
+"RGDH9951150024080750211",
+"RGDH9951150024082750379",
+"RGDH9951150024082850252",
+"RGDH9951150024083050204",
+"RGDH9951150024080750176",
+"RGDH9951150024080750190",
+"RGDH9951150024083150027",
+"RGDH9951150024082850308",
+"RGDH9951150024082850070",
+"RGDH9951150024082950068",
+"RGDH9951150024083050002",
+"RGDH9951150024083050130",
+"RGDH9951150024083050060",
+"RGDH9951150024082950282",
+"RGDH9951150024082950320",
+"RGDH9951150024082850312",
+"RGDH9951150024083150040",
+"RGDH9951150024080750202",
+"RGDH9951150024083150216",
+"RGDH9951150024082750156",
+"RGDH9951150024082850224",
+"RGDH9951150024083150238",
+"RGDH9951150024083050327",
+"RGDH9951150024082950090",
+"RGDH9951150024083150131",
+"RGDH9951150024080750187",
+"RGDH9951150024082350072",
+"RGDH9951150024080750177",
+"RGDH9951150024082950010",
+"RGDH9951150024082850263",
+"RGDH9951150024082850087",
+"RGDH9951150024083050234",
+"RGDH9951150024083150098",
+"RGDH9951150024083050166",
+"RGDH9951150024082850339",
+"RGDH9951150024083150157",
+"RGDH9951150024080150214",
+"RGDH9951150024083150149",
+"RGDH9951150024083150264",
+"RGDH9951150024080750200",
+"RGDH9951150024083150116",
+"RGDH9951150024082950188",
+"RGDH9951150024083050148",
+"RGDH9951150024082750338",
+"RGDH9951150024082950268",
+"RGDH9951150024083050337",
+"RGDH9951150024082250263",
+"RGDH9951150024080750196",
+"RGDH9951150024080750192",
+"RGDH9951150024082850272",
+"RGDH9951150024082650290",
+"RGDH9951150024083150117",
+"RGDH9951150024080750207",
+"RGDH9951150024080750201",
+"RGDH9951150024080750188",
+"RGDH9951150024083050011",
+"RGDH9951150024083050067",
+"RGDH9951150024083050193",
+"RGDH9951150024082850242",
+"RGDH9951150024082950121",
+"RGDH9951150024080750222",
+"RGDH9951150024082950280",
+"RGDH9951150024080750205",
+"RGDH9951150024083050334",
+"RGDH9951150024083150235",
+"RGDH9951150024082950156",
+"RGDH9951150024080750220",
+"RGDH9951150024082750209",
+"RGDH9951150024083150046",
+"RGDH9951150024080750214",
+"RGDH9951150024082850116",
+"RGDH9951150024083050082",
+"RGDH9951150024083150118",
+"RGDH9951150024082950338",
+"RGDH9951150024082950359",
+"RGDH9951150024083150156",
+"RGDH9951150024083150072",
+"RGDH9951150024082150001",
+"RGDH9951150024082850186",
+"RGDH9951150024082750377",
+"RGDH9951150024083150166",
+"RGDH9951150024083050255",
+"RGDH9951150024083050190",
+"RGDH9951150024080750175",
+"RGDH9951150024083050184",
+"RGDH9951150024083050021",
+"RGDH9951150024082850317",
+"RGDH9951150024082950146",
+"RGDH9951150024083150172",
+"RGDH9951150024083050354",
+"RGDH9951150024082850305",
+"RGDH9951150024082850351",
+"RGDH9951150024082950340",
+"RGDH9951150024083150273",
+"RGDH9951150024080750208",
+"RGDH9951150024083150053",
+"RGDH9951150024082850291",
+"RGDH9951150024082950104",
+"RGDH9951150024082850247",
+"RGDH9951150024082850320",
+"RGDH9951150024083050285",
+"RGDH9951150024082850011",
+"RGDH9951150024083050174",
+"RGDH9951150024083150212",
+"RGDH9951150024083050323",
+"RGDH9951150024080750224",
+"RGDH9951150024083150244",
+"RGDH9951150024080750199",
+"RGDH9951150024082850269",
+"RGDH9951150024082850053",
+"RGDH9951150024082950342",
+"RGDH9951150024082950046",
+"RGDH9951150024082950194"
+        };
+        _logger.LogWarning($"推送数据共:{provinceNos.Count}");
 
-        var steps = await _workflowStepRepository.Queryable()
-            .LeftJoin<Order>((ws, d) => ws.ExternalId == d.Id)
-            .Where((ws, d) => d.Status == EOrderStatus.Handling && ws.NextStepCode == "end" && ws.Status == EWorkflowStepStatus.Handled && ws.StepType == EStepType.Start)
+        var unpublishOrders = await _orderRepository.Queryable()
+            .Where(d => provinceNos.Contains(d.ProvinceNo) &&
+                        !string.IsNullOrEmpty(d.ProvinceNo) &&
+                        d.Status >= EOrderStatus.Filed)
             .ToListAsync(HttpContext.RequestAborted);
 
-        _logger.LogInformation($"取到数据 {steps.Count} 条");
-        foreach (var item in steps)
+        _logger.LogWarning($"准备开始推送:{unpublishOrders.Count}");
+
+        foreach (var order in unpublishOrders)
         {
-            ///组装数据
-            //Workflow workflow
-            Workflow workflow = await _workflowDomainService.GetWorkflowAsync(item.WorkflowId, withDefine: true, withSteps: true,
-                cancellationToken: HttpContext.RequestAborted);
-            //WorkflowStep startStep
-            var startStep = workflow.Steps.FirstOrDefault(x => x.StepType == EStepType.Start);
-            if (startStep is null) continue;
-            //BasicWorkflowDto dto
-            BasicWorkflowDto dto = new BasicWorkflowDto
-            {
-                NextStepCode = "end",
-                NextStepName = "结束",
-                BackToCountersignEnd = false,
-                FlowDirection = null,
-                HandlerType = 0,
-                StepType = 0,
-                NextHandlers = new List<FlowStepHandler>(),
-                IsSms = false,
-                NextMainHandler = "",
-                IsStartCountersign = false,
-                External = new External
-                {
-                    TimeLimit = null,
-                    TimeLimitUnit = null,
-                    IsPoliceReturn = false,
-                    IsResolved = false,
-                },
-                BusinessType = EBusinessType.File,
-                ReviewResult = 0,
-                Remark = null,
-                Opinion = startStep.Opinion,
-                Files = new List<Share.Dtos.File.FileDto>()
-            };
-            //ISessionContext current
-            ISessionContext current = new ProvinceSessionContext
+            var trace = await _workflowTraceRepository.Queryable()
+                .FirstAsync(d => d.WorkflowId == order.WorkflowId && d.StepType == EStepType.End,
+                    HttpContext.RequestAborted);
+            var orderFlowDto = new OrderFlowDto
             {
-                //UserId = startStep.HandlerId,
-                //UserName = startStep.HandlerName,
-                OrgId = startStep.HandlerOrgId,
-                OrgName = startStep.HandlerOrgName,
-                OrgAreaCode = startStep.HandlerOrgAreaCode,
-                OrgAreaName = startStep.HandlerOrgAreaName,
-                OrgLevel = 1
+                Order = _mapper.Map<OrderDto>(order),
+                WorkflowTrace = _mapper.Map<WorkflowTraceDto>(trace)
             };
 
-            //StepDefine firstStepDefine
-            StepDefine firstStepDefine = workflow.WorkflowDefinition.FindStepDefine(startStep.NextStepCode);
-            //FlowAssignInfo flowAssignInfo
-            ////如果发起会签需检查是否支持发起会签
-            //var startStepDefine = workflow.WorkflowDefinition.FindStartStepDefine();
-
-            //下一节点是否为动态节点
-            var isNextDynamic = false;
-
-            FlowAssignInfo flowAssignInfo =
-                await _workflowApplication.GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, HttpContext.RequestAborted);
-            //DateTime? expiredTime
-            DateTime? expiredTime = startStep.StepExpiredTime;
-
-            ///
-            await _mediator.Publish(
-                new StartWorkflowNotify(workflow, dto, flowAssignInfo, startStep.WorkflowTrace), HttpContext.RequestAborted);
-
-            //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
-            workflow.UpdateActualStepWhenHandle(startStep,
-                current.RequiredUserId, current.UserName,
-                current.RequiredOrgId, current.OrgName,
-                current.OrgAreaCode, current.OrgAreaName,
-                current.OrgLevel);
-
-            workflow.UpdateCurrentStepWhenHandle(startStep,
-                current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-
-            var endTrace = await _workflowDomainService.EndAsync(workflow, dto, firstStepDefine,
-                startStep, current, expiredTime, HttpContext.RequestAborted);
-
-
-        }
-
-        _logger.LogInformation($"处理完成");
-    }
-
-    [HttpGet("order_participle")]
-    [AllowAnonymous]
-    public async Task OrderParticiple()
-    {
-        var tels = new List<Tel>();
-        for (int i = 5001; i <= 5010; i++)
-        {
-            tels.Add(new Tel
+            if (order.SourceChannelCode == AppDefaults.SourceChannel.DianHua &&
+                !string.IsNullOrEmpty(order.CallId))
             {
-                No = i.ToString()
-            });
-        }
+                if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
+                {
+                    var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, HttpContext.RequestAborted);
+                    if (callRecord != null)
+                    {
+                        orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
+                    }
+                }
+                else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
+                {
+                    var call = await _callApplication.GetCallAsync(order.CallId, HttpContext.RequestAborted);
+                    if (call is not null)
+                        orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(call);
+                }
+            }
 
-        for (int i = 8001; i <= 9069; i++)
-        {
-            tels.Add(new Tel
-            {
-                No = i.ToString()
-            });
+            //这里需要判断是否是警情退回
+            orderFlowDto.IsNonPoliceReturn = false;
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: HttpContext.RequestAborted);
+            _logger.LogWarning($"推送完成: {order.ProvinceNo}");
         }
-        
-        await _telRepository.AddRangeAsync(tels, HttpContext.RequestAborted);
-        
+
+        _logger.LogWarning($"推送完成");
     }
 }

+ 19 - 20
src/Hotline.Api/Controllers/WebPortalController.cs

@@ -1,32 +1,26 @@
-using DotNetCore.CAP;
+using Hotline.Application.Bulletin;
+using Hotline.Application.Orders;
 using Hotline.Article;
+using Hotline.Caching.Interfaces;
 using Hotline.Orders;
+using Hotline.Push.Notifies;
+using Hotline.Settings;
 using Hotline.Settings.Hotspots;
-using Hotline.Share.Dtos.Push.FWMessage;
-using Hotline.Share.Dtos.Push;
+using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.WebPortal;
 using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Push;
 using Hotline.WebPortal;
 using MapsterMapper;
+using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Cache;
 using XF.Domain.Filters;
 using XF.Domain.Repository;
-using XF.Domain.Cache;
-using Hotline.Push.Notifies;
-using Hotline.Share.Enums.Push;
-using StackExchange.Redis;
-using MediatR;
-using XF.Domain.Constants;
-using Hotline.Caching.Interfaces;
-using Hotline.Application.Orders;
-using XF.Domain.Authentications;
-using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
-using Hotline.Share.Dtos.Order;
-using Org.BouncyCastle.Ocsp;
-using System.Threading;
-using Hotline.Settings;
 
 namespace Hotline.Api.Controllers
 {
@@ -47,7 +41,7 @@ namespace Hotline.Api.Controllers
         private readonly IOrderApplication _orderApplication;
         private readonly ISessionContext _sessionContext;
         private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
-
+        private readonly IBulletinApplication _bulletinApplication;
 
         public WebPortalController(IMapper mapper,
             IMediator mediator,
@@ -63,7 +57,8 @@ namespace Hotline.Api.Controllers
            IRepository<OrderVisit> orderVisitRepository,
            IOrderApplication orderApplication,
            ISessionContext sessionContext,
-            IRepository<OrderVisitDetail> orderVisitDetailRepository
+            IRepository<OrderVisitDetail> orderVisitDetailRepository,
+            IBulletinApplication bulletinApplication
             )
         {
             _mapper = mapper;
@@ -81,6 +76,7 @@ namespace Hotline.Api.Controllers
             _orderApplication = orderApplication;
             _sessionContext = sessionContext;
             _orderVisitDetailRepository = orderVisitDetailRepository;
+            _bulletinApplication = bulletinApplication;
         }
 
         #region 通知
@@ -183,6 +179,9 @@ namespace Hotline.Api.Controllers
                     WNED_VideoUrl = "",
                     NoticeContent = data.Content
                 };
+
+                if (data != null && !string.IsNullOrEmpty(data.Content))
+                    data.Content = _bulletinApplication.GetSiteUrls(data.Content);
             }
             else
                 detailsDto = new();
@@ -654,7 +653,7 @@ namespace Hotline.Api.Controllers
         [HttpPost("getorderid")]
         public async Task<OpenResponse> GetOrderId([FromBody] GetOrderCodePwd dto)
         {
-            var data = await _orderRepository.GetAsync(p => p.No == dto.OrderNo && p.Password == dto.Pwd, HttpContext.RequestAborted);
+            var data = await _orderRepository.GetAsync(p => p.No == dto.OrderNo && p.Password == dto.Pwd && p.Status > EOrderStatus.Published, HttpContext.RequestAborted);
             return OpenResponse.Ok(WebPortalDeResponse<string>.Success(data?.Id));
         }
 

+ 6 - 0
src/Hotline.Api/Program.cs

@@ -11,6 +11,12 @@ try
 
     var builder = WebApplication.CreateBuilder(args);
 
+    builder.WebHost.ConfigureKestrel(serverOptions =>
+    {
+        serverOptions.Limits.MaxConcurrentConnections = 5000;
+        serverOptions.Limits.MaxConcurrentUpgradedConnections = 5000;
+    });
+
     builder.Host
         .ConfigureAppConfiguration((hostBuilderContext, configBuilder) =>
         {

+ 11 - 9
src/Hotline.Api/StartupExtensions.cs

@@ -27,12 +27,8 @@ using Hotline.CallCenter.Calls;
 using Swashbuckle.AspNetCore.SwaggerUI;
 using Hotline.Configurations;
 using Hotline.DI;
-using Hotline.WeChat;
-using Senparc.Weixin.RegisterServices;
-using Senparc.Weixin.AspNet;
 using Hotline.Share.Tools;
-using Hotline.Users;
-using Hotline.Snapshot.Test;
+using Hotline.Settings.TimeLimitDomain.ExpireTimeSupplier;
 
 
 namespace Hotline.Api;
@@ -62,10 +58,11 @@ internal static class StartupExtensions
         var callCenterConfiguration = callCenterConfigurationSection.Get<CallCenterConfiguration>();
         services.Configure<CallCenterConfiguration>(d => callCenterConfigurationSection.Bind(d));
 
-        //services.Configure<SendSmsConfiguration>(d => configuration.GetSection("SendSms").Bind(d));
+        services.Configure<CityBaseConfiguration>(d => configuration.GetSection(nameof(CityBaseConfiguration)).Bind(d));
+		//services.Configure<SendSmsConfiguration>(d => configuration.GetSection("SendSms").Bind(d));
 
-        // Add services to the container.
-        services
+		// Add services to the container.
+		services
             .BatchInjectServices(d =>
             {
                 var attr = d.GetCustomAttribute(typeof(InjectionAttribute)) as InjectionAttribute;
@@ -76,6 +73,7 @@ internal static class StartupExtensions
             .RegisterRepository()
             .AddApplication()
             .AddScoped(typeof(IPasswordHasher<>), typeof(PasswordHasher<>))
+            .AddHttpClient()
             ;
 
         //cache
@@ -186,13 +184,17 @@ internal static class StartupExtensions
 
         services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
         services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
+        services.AddScoped<ExpireTimeFactory>();
+        services.AddScoped<IExpireTimeSupplier, DaySupplier>();
+        services.AddScoped<IExpireTimeSupplier, WorkDaySupplier>();
+        services.AddScoped<IExpireTimeSupplier, HourSupplier>();
 
         services.AddScoped<IThirdIdentiyService, WeChatService>();
 
         services.AddSenparcWeixin(configuration);
 
         //services.AddScoped<LogFilterAttribute>();
-        ServiceLocator.Instance = services.BuildServiceProvider();
+        // ServiceLocator.Instance = services.BuildServiceProvider();
         return builder.Build();
     }
 

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

@@ -256,14 +256,7 @@ namespace Hotline.Api
                 d.MaxBatchSize = 3;
 
                 //load send order job
-                var autoSendOrderKey = new JobKey(nameof(SendOrderJob), "send order task");
-                d.AddJob<SendOrderJob>(autoSendOrderKey);
-                d.AddTrigger(t => t
-                    .WithIdentity("task-send-order-trigger")
-                    .ForJob(autoSendOrderKey)
-                    .StartNow()
-                    .WithCronSchedule("0 10 9 * * ?")
-                );
+                
 
                 //即将超期和超期短信
                 var autoSendOverTimeSmsKey = new JobKey(nameof(SendOverTimeSmsJob), "send overtime order task");
@@ -285,6 +278,15 @@ namespace Hotline.Api
                         .ForJob(aiVisitStatusKey)
                         .StartNow()
                         .WithCronSchedule("0 0/5 * * * ? *"));
+
+                        var autoSendOrderKey = new JobKey(nameof(SendOrderJob), "send order task");
+                        d.AddJob<SendOrderJob>(autoSendOrderKey);
+                        d.AddTrigger(t => t
+                            .WithIdentity("task-send-order-trigger")
+                            .ForJob(autoSendOrderKey)
+                            .StartNow()
+                            .WithCronSchedule("0 10 9 * * ?")
+                        );
                         break;
                     default:
                         break;

+ 34 - 2
src/Hotline.Api/config/appsettings.Development.json

@@ -1,7 +1,39 @@
 {
+  "CityBaseConfiguration": {
+    "CityProvince": {
+      "UserId": "03aba148-e7b1-cd03-bf00-3a1177930508",
+      "UserName": "省12345平台",
+      "OrgId": "001171",
+      "OrgName": "省12345平台"
+    },
+    "CityProvinceAssign": {
+      "UserId": "",
+      "UserName": "",
+      "OrgId": "001178",
+      "OrgName": "省12345交办"
+    },
+    "PublicSecurity": {
+      "UserId": "e90501d7-c453-e18a-f1fa-3a1177930699",
+      "UserName": "市公安局110",
+      "OrgId": "001180",
+      "OrgName": "市公安局110"
+    },
+    "CityEnterprise": {
+      "UserId": "ce42562c-afc1-764b-1dc8-3a1177930346",
+      "UserName": "联系服务企业",
+      "OrgId": "001181",
+      "OrgName": "联系服务企业"
+    },
+    "ComprehensiveTreatment": {
+      "UserId": "d4cb7151-41fa-a810-6c1e-3a117792fc0c",
+      "UserName": "综治平台",
+      "OrgId": "001143",
+      "OrgName": "综治平台"
+    }
+  },
   "AllowedHosts": "*",
   "AppConfiguration": {
-    "AppScope": "YiBin",
+    "AppScope": "ZiGong",
     "YiBin": {
       "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
       //智能回访
@@ -123,7 +155,7 @@
   "FwClient": {
     "ClientId": "hotline",
     "ClientSecret": "08db29cc-0da0-4adf-850c-1b2689bd535d"
-  },
+  }
   //"ConfigCenter": {
   //  "ServerAddresses": [ "http://110.188.24.28:8848" ],
   //  "Namespace": "17503980-9b0d-4d3e-8e35-c842c41fb888", //debug

+ 27 - 0
src/Hotline.Application.Tests/Application/ExpireTimeHandlerTest.cs

@@ -0,0 +1,27 @@
+using Hotline.Settings.TimeLimitDomain;
+using Hotline.Share.Dtos.Settings;
+using Shouldly;
+
+namespace Hotline.Application.Tests.Application;
+public class ExpireTimeHandlerTest
+{
+    private readonly IExpireTimeHandler _expireTimeHandler;
+
+    public ExpireTimeHandlerTest(IExpireTimeHandler expireTimeHandler)
+    {
+        _expireTimeHandler = expireTimeHandler;
+    }
+
+    [Theory]
+    [InlineData("2024/09/04", false)]
+    [InlineData("2024/09/05", false)]
+    [InlineData("2024/09/06", false)]
+    [InlineData("2024/09/07", true)]
+    public async Task Test_GetExpireTime(string time, bool work)
+    {
+        var dateTime = DateTime.Parse(time);
+        var result = await _expireTimeHandler.NotWorkDay(dateTime);
+        result.ShouldBe(work);
+    }
+
+}

+ 98 - 0
src/Hotline.Application.Tests/Application/OrderApplicationTest.cs

@@ -0,0 +1,98 @@
+using Hotline.Application.Orders;
+using Hotline.Caching.Interfaces;
+using Hotline.Orders;
+using Hotline.Settings;
+using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Order;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Application;
+public class OrderApplicationTest
+{
+    private readonly IOrderApplication _orderApplication;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+    private readonly IRepository<OrderVisit> _orderVisitRepository;
+    private readonly IRepository<Order> _orderRepository;
+
+    public OrderApplicationTest(IOrderApplication orderApplication, IRepository<OrderVisit> orderVisitRepository, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager)
+    {
+        _orderApplication = orderApplication;
+        _orderVisitRepository = orderVisitRepository;
+        _orderRepository = orderRepository;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+    }
+
+    [Theory]
+    [InlineData(1)]
+    [InlineData(2)]
+    public async Task VisitPushSMS_Test(int count)
+    {
+        var orderVisit = await _orderVisitRepository.Queryable()
+            .Where(m => m.VisitState == EVisitState.WaitForVisit)
+            .OrderByDescending(m => m.CreationTime)
+            .FirstAsync();
+        var dto = new VisitSmsInDto
+        {
+            Ids = new List<string> { orderVisit.Id }
+        };
+        await _orderApplication.VisitPushSMSAsync(dto, new CancellationToken());
+        var visit = await _orderVisitRepository.Queryable().Where(m => m.Id == orderVisit.Id).FirstAsync();
+        visit.VisitState.ShouldBe(EVisitState.SMSVisiting);
+        visit.VisitType.ShouldBe(EVisitType.SmsVisit);
+    }
+
+    [Theory]
+    [InlineData("08dcd937-5800-4e44-81d7-68a318dbc251", "沟通地点", "张三", "13666666666", "63344B7C-D2CB-4B40-8B13-009923393573")]
+    public async Task SaveOrderWorkflowInfo_Test(string workflowId,
+        string realCommunicationAddress,
+        string realHandlerName,
+        string realHandlerPhone,
+        string transpondCityId
+        )
+    {
+        await _orderRepository.Updateable()
+            .SetColumns(m => m.RealCommunicationAddress == null)
+            .Where(m => m.WorkflowId == workflowId)
+            .ExecuteCommandAsync();
+        var time = DateTime.Now;
+        var dicSystem = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity).First();
+        var dto = new NextWorkflowDto
+        {
+            RealCommunicationAddress = realCommunicationAddress,
+            WorkflowId = workflowId,
+            RealHandlerName = realHandlerName,
+            RealHandlerPhone = realHandlerPhone,
+            RealCommunicationMode = ERealCommunicationMode.Locale,
+            RealCommunicationTime = time,
+            RealIsContacted = true,
+            RealContactLocale = true,
+            IsOther = true,
+            OtherRemark = "备注",
+            TranspondCityId = dicSystem.Id,
+            TranspondCityName = dicSystem.DicDataName,
+            TranspondCityValue = dicSystem.DicDataValue,
+        };
+        var order = await _orderApplication.SaveOrderWorkflowInfo(dto, new CancellationToken());
+        order = await _orderRepository.GetAsync(order.Id);
+        order.RealCommunicationAddress.ShouldBe(realCommunicationAddress);
+        order.RealHandlerPhone.ShouldBe(realHandlerPhone);
+        order.RealHandlerName.ShouldBe(realHandlerName);
+        order.RealCommunicationMode.ShouldBe(ERealCommunicationMode.Locale);
+        order.RealCommunicationTime.Value.ToString("yyyy-MM-dd hh:mm:ss").ShouldBe(time.ToString("yyyy-MM-dd hh:mm:ss"));
+        order.RealIsContacted.ShouldBe(true);
+        order.RealContactLocale.ShouldBe(true);
+        order.IsOther.ShouldBe(true);
+        order.OtherRemark.ShouldBe("备注");
+        order.TranspondCityId.ShouldBe(dicSystem.Id);
+        order.TranspondCityName.ShouldBe(dicSystem.DicDataName);
+        order.TranspondCityValue.ShouldBe(dicSystem.DicDataValue);
+    }
+}

+ 3 - 3
src/Hotline.Application.Tests/DefaultHttpContextAccessor.cs

@@ -14,11 +14,11 @@ public class DefaultHttpContextAccessor : IHttpContextAccessor, ISessionContext
     private HttpContext GetContext()
     { 
         var context = new DefaultHttpContext();
-        var openId = new Claim(AppClaimTypes.OpenId, "测试生成的OpenId");
+        //var openId = new Claim(AppClaimTypes.OpenId, "测试生成的OpenId");
         var id = new ClaimsIdentity("身份");
-        id.AddClaim(openId);
+        //id.AddClaim(openId);
         context.User = new ClaimsPrincipal(id);
-        OpenId = context.User.FindFirstValue(AppClaimTypes.OpenId);
+        //OpenId = context.User.FindFirstValue(AppClaimTypes.OpenId);
         return context;
 
     }

+ 43 - 0
src/Hotline.Application.Tests/Domain/LuZhouExpireTimeTest.cs

@@ -0,0 +1,43 @@
+using Hotline.Settings.TimeLimitDomain;
+using Hotline.Settings;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+using Hotline.Orders;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Enums.Settings;
+using Shouldly;
+
+namespace Hotline.Application.Tests.Domain;
+public class LuZhouExpireTimeTest
+{
+    private readonly LuZhouExpireTimeLimit _calcExpireTime;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly IRepository<TimeLimitSetting> _timeLimitSettingRepository;
+
+    public LuZhouExpireTimeTest(IRepository<TimeLimitSetting> timeLimitSettingRepository, IRepository<Order> orderRepository, LuZhouExpireTimeLimit calcExpireTime)
+    {
+        _timeLimitSettingRepository = timeLimitSettingRepository;
+        _orderRepository = orderRepository;
+        _calcExpireTime = calcExpireTime;
+    }
+
+    [Theory]
+    [InlineData("2024-09-04 14:00:00", 2, "10", "2024-09-06 14:00:00", "2024/9/6 10:24:00", "2024/9/5 14:00:00", "2个工作日")]
+    [InlineData("2024-09-04 14:01:01", 3, "10", "2024-09-09 14:01:01", "2024/9/6 17:37:01", "2024/9/6 9:31:01", "3个工作日")]
+    public async Task CalcEndTime_Test(string begin, int count, string busCode, string expiredTime, string nearlyExpiredTime, string nearlyExpiredTimeOne, string timeText)
+    {
+        var beginTime = DateTime.Parse(begin);
+        var result = await _calcExpireTime.CalcEndTime(beginTime, new TimeConfig(count, ETimeType.WorkDay), busCode);
+        result.ShouldNotBeNull();
+        result.ExpiredTime.ShouldBe(DateTime.Parse(expiredTime));
+        result.NearlyExpiredTime.ShouldBe(DateTime.Parse(nearlyExpiredTime));
+        result.NearlyExpiredTimeOne.ShouldBe(DateTime.Parse(nearlyExpiredTimeOne));
+        result.Count.ShouldBe(count);
+        result.TimeText.ShouldBe(timeText);
+    }
+}
+

+ 100 - 0
src/Hotline.Application.Tests/Domain/YiBinExpireTimeTest.cs

@@ -0,0 +1,100 @@
+using Hotline.Configurations;
+using Hotline.Orders;
+using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Settings;
+using Hotline.Share.Tools;
+using Mapster;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Domain;
+public class YiBinExpireTimeTest
+{
+    private readonly YiBinExpireTimeLimit _calcExpireTime;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly IRepository<TimeLimitSetting> _timeLimitSettingRepository;
+
+    public YiBinExpireTimeTest(YiBinExpireTimeLimit calcExpireTime, IRepository<Order> orderRepository, IRepository<TimeLimitSetting> timeLimitSettingRepository)
+    {
+        _calcExpireTime = calcExpireTime;
+        _orderRepository = orderRepository;
+        _timeLimitSettingRepository = timeLimitSettingRepository;
+    }
+
+    [Theory]
+    [InlineData("2024-09-23 15:07:40", 5, "15", "2024-09-29 15:07:40", "5个工作日")]
+    public async Task CalcEndTimeWorkDay_Test(string begin, int count, string busCode, string expiredTime, string timeText)
+    {
+        var beginTime = DateTime.Parse(begin);
+        var result = await _calcExpireTime.CalcEndTime(beginTime, ETimeType.WorkDay, count, busCode);
+        result.ShouldNotBeNull();
+        result.EndTime.ShouldBe(DateTime.Parse(expiredTime));
+    }
+
+    [Theory]
+    [InlineData("2024-09-25 13:16:33", 5, "15", "2024-09-29 15:07:40", "5个工作日")]
+    public async Task CalcEndTimeWorkDayDelay_Test(string begin, int count, string busCode, string expiredTime, string timeText)
+    {
+        var beginTime = DateTime.Parse(begin);
+        var result = await _calcExpireTime.CalcEndTime(beginTime, ETimeType.WorkDay, count, 0, 0);
+        result.ShouldNotBeNull();
+        result.EndTime.ShouldBe(DateTime.Parse(expiredTime));
+    }
+
+
+    [Theory]
+    [InlineData("2024-09-04 14:00:00", 2, "10", "2024-09-06 14:00:00", "2024/9/6 10:24:00", "2024/9/5 14:00:00", "2个工作日")]
+    [InlineData("2024-09-04 14:01:01", 3, "10", "2024-09-09 14:01:01", "2024/9/6 17:37:01", "2024/9/6 9:31:01", "3个工作日")]
+    public async Task CalcEndTime_Test(string begin, int count, string busCode, string expiredTime, string nearlyExpiredTime, string nearlyExpiredTimeOne, string timeText)
+    {
+        var beginTime = DateTime.Parse(begin);
+        var result = await _calcExpireTime.CalcEndTime(beginTime, new TimeConfig(count, ETimeType.WorkDay), busCode);
+        result.ShouldNotBeNull();
+        result.ExpiredTime.ShouldBe(DateTime.Parse(expiredTime));
+        result.NearlyExpiredTime.ShouldBe(DateTime.Parse(nearlyExpiredTime));
+        result.NearlyExpiredTimeOne.ShouldBe(DateTime.Parse(nearlyExpiredTimeOne));
+        result.Count.ShouldBe(count);
+        result.TimeText.ShouldBe(timeText);
+    }
+
+    [Theory]
+    [InlineData("2024-09-04 14:00:00", "CenterToOrg", "08dccc8f-37b0-40d8-8112-1afb2230c5a3", "2024-09-05 14:00:00")]
+    public async Task CalcExpiredTime_Test(string beginTxt, string flowTxt, string orderId, string expected)
+    {
+        var beginTime = DateTime.Parse(beginTxt);
+        if (orderId.Equals("08dccc8f-37b0-40d8-8112-1afb2230c5a3"))
+            await InitOrderData(orderId);
+        var order = await _orderRepository.Queryable().Where(m => m.Id == orderId).FirstAsync();
+        Enum.TryParse(flowTxt, out EFlowDirection flow);
+        var time = await _calcExpireTime.CalcExpiredTime(beginTime, flow, order.Adapt<OrderTimeClacInfo>());
+        time.ShouldNotBeNull();
+        time.ExpiredTime.ShouldBe(DateTime.Parse(expected));
+    }
+
+    public async Task InitOrderData(string orderId)
+    {
+        var order = await _orderRepository.Queryable().Where(m => m.Id == orderId).FirstAsync();
+        if (order.Is24HoursComplete) return;
+        order.Is24HoursComplete = true;
+        await _orderRepository.UpdateAsync(order);
+    }
+
+    [Fact]
+    public async Task InitExpireTime_Test()
+    {
+        var entity = new TimeLimitSetting() { BusCode = "YQ", BusName = "疫情", TimeType = ETimeType.WorkDay, TimeValue = 2, Percentage = 80, PercentageOne = 50 };
+        if (await _timeLimitSettingRepository.Queryable().Where(m => m.BusCode == entity.BusCode).FirstAsync() == null)
+            await _timeLimitSettingRepository.AddAsync(entity);
+        entity = new TimeLimitSetting() { BusCode = "24", BusName = "24小时", TimeType = ETimeType.Hour, TimeValue = 24, Percentage = 80, PercentageOne = 50 };
+        if (await _timeLimitSettingRepository.Queryable().Where(m => m.BusCode == entity.BusCode).FirstAsync() == null)
+            await _timeLimitSettingRepository.AddAsync(entity);
+    }
+}

+ 135 - 0
src/Hotline.Application.Tests/Domain/ZiGongExpireTimeTest.cs

@@ -0,0 +1,135 @@
+using Hotline.Orders;
+using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain;
+using Hotline.Settings.TimeLimitDomain.Repository;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Settings;
+using Mapster;
+using Shouldly;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Domain;
+public class ZiGongExpireTimeTest
+{
+    private readonly ZiGongExpireTimeLimit _ziGongExpireTimeLimit;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly ITimeLimitSettingAttributeRepository _timeLimitSettingAttributeRepository;
+    private readonly ITimeLimitSettingInventoryRepository _timeLimitSettingInventoryRepository;
+
+    public ZiGongExpireTimeTest(ZiGongExpireTimeLimit ziGongExpireTimeLimit, IRepository<Order> orderRepository, ITimeLimitSettingAttributeRepository timeLimitSettingAttributeRepository, ITimeLimitSettingInventoryRepository timeLimitSettingInventoryRepository)
+    {
+        _ziGongExpireTimeLimit = ziGongExpireTimeLimit;
+        _orderRepository = orderRepository;
+        _timeLimitSettingAttributeRepository = timeLimitSettingAttributeRepository;
+        _timeLimitSettingInventoryRepository = timeLimitSettingInventoryRepository;
+    }
+
+    //[Theory]
+    //// 24小时件
+    //[InlineData("24小时件", "2024-09-04 14:00:00", "CenterToOrg", "08dccc8f-37b0-40d8-8112-1afb2230c5a3", "2024-09-05 14:00:00")]
+    //// 疫情件
+    //[InlineData("疫情件", "2024-09-05 14:01:01", "CenterToOrg", "08dccd5c-9bda-4e7d-8d63-82039dcfbde7", "2024-09-09 14:01:01")]
+    //public async Task CalcExpiredTime_Test(string tip, string beginTxt, string flowTxt, string orderId, string expected)
+    //{
+    //    var beginTime = DateTime.Parse(beginTxt);
+    //    if (orderId.Equals("08dccc8f-37b0-40d8-8112-1afb2230c5a3"))
+    //        await InitOrderData(orderId);
+    //    var order = await _orderRepository.Queryable().Where(m => m.Id == orderId).FirstAsync();
+    //    Enum.TryParse(flowTxt, out EFlowDirection flow);
+    //    var time = await _ziGongExpireTimeLimit.CalcExpiredTime(beginTime, flow, order.Adapt<OrderTimeClacInfo>());
+    //    time.ShouldNotBeNull();
+    //    time.ExpiredTime.ShouldBe(DateTime.Parse(expected), $"{tip} 期满时间错误");
+    //}
+
+    [Theory]
+    [InlineData("企业咨询件单元测试", "2024-09-04 14:00:00", "CenterToOrg", "2024-09-05 14:00:00")]
+    [InlineData("企业建议件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-09 14:00:00")]
+    [InlineData("企业求助件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-09 14:00:00")]
+    [InlineData("企业表扬件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-09 14:00:00")]
+    [InlineData("企业举报件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-09 14:00:00")]
+    [InlineData("企业投诉件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-09 14:00:00")]
+    [InlineData("四川省12345咨询件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-06 14:00:00")]
+    [InlineData("四川省12345建议件单元测试", "2024-09-05 14:00:00", "CenterToOrg", "2024-09-10 14:00:00")]
+    [InlineData("中心到中心24小时", "2024-09-12 14:00:00", "CenterToCenter", "2024-09-13 14:00:00")]
+    public async Task CalcExpiredTime_Test(string title, string beginTxt, string flowTxt, string expected)
+    {
+        var beginTime = DateTime.Parse(beginTxt);
+        var order = await _orderRepository.Queryable().Where(m => m.Title == title).FirstAsync();
+        order.ShouldNotBeNull($"{title} 测试数据不存在");
+        Enum.TryParse(flowTxt, out EFlowDirection flow);
+        var time = await _ziGongExpireTimeLimit.CalcExpiredTime(beginTime, flow, order.Adapt<OrderTimeClacInfo>());
+        time.ShouldNotBeNull();
+        time.ExpiredTime.ShouldBe(DateTime.Parse(expected), $"{title} 期满时间错误 AcceptTypeCode:{order.AcceptTypeCode}");
+        time.TimeText.ShouldBe(order.Content, $"{title} 内容结果比对失败 AcceptTypeCode:{order.AcceptTypeCode}");
+    }
+
+    [Theory]
+    [InlineData("求助三个工作日", "2024-09-12 22:01:28", "CenterToOrg", "2024-09-20 08:30:00")]
+    public async Task CalcExpiredTime_Release_Test(string title, string beginTxt, string flowTxt, string expected)
+    {
+        var beginTime = DateTime.Parse(beginTxt);
+        var order = await _orderRepository.Queryable().Where(m => m.Title == title).FirstAsync();
+        order.ShouldNotBeNull($"{title} 测试数据不存在");
+        Enum.TryParse(flowTxt, out EFlowDirection flow);
+        var time = await _ziGongExpireTimeLimit.CalcExpiredTime(beginTime, flow, order.Adapt<OrderTimeClacInfo>());
+        time.ShouldNotBeNull();
+        time.ExpiredTime.ShouldBe(DateTime.Parse(expected), $"{title} 期满时间错误 AcceptTypeCode:{order.AcceptTypeCode}");
+    }
+
+    public async Task InitOrderData(string orderId)
+    {
+        var order = await _orderRepository.Queryable().Where(m => m.Id == orderId).FirstAsync();
+        if (order.Is24HoursComplete) return;
+        order.Is24HoursComplete = true;
+        await _orderRepository.UpdateAsync(order);
+    }
+
+    [Theory]
+    [InlineData("", "Is24HoursComplete", "true", false)]
+    [InlineData("", "HotspotSpliceName", "疫情", false)]
+    [InlineData("10", "IdentityType", "Enterprise", false)]
+    [InlineData("15", "IdentityType", "Enterprise", false)]
+    [InlineData("20", "IdentityType", "Enterprise", false)]
+    public async Task InitTimeLimitData_Test(string busCode, string name, string value, bool isCommon)
+    {
+        var attributeEntity = new TimeLimitSettingAttribute { BusCode = busCode, Name = name, Value = value, IsCommon = isCommon };
+        var dataEntity = await _timeLimitSettingAttributeRepository.GetAsync(attributeEntity.BusCode, attributeEntity.Name, attributeEntity.Value);
+        if (dataEntity is null) await _timeLimitSettingAttributeRepository.AddAsync(attributeEntity);
+    }
+
+    [Theory]
+    [InlineData("", "Is24HoursComplete", "true", "Hour", 24, "24小时件")]
+    [InlineData("", "HotspotSpliceName", "疫情", "WorkDay", 2, "疫情类2个工作日")]
+    [InlineData("10", "IdentityType", "Enterprise", "WorkDay", 1, "企业 '咨询' 件1个工作日")] 
+    [InlineData("",   "IdentityType", "Enterprise", "WorkDay", 2, "企业 '非咨询' 件2个工作日")] 
+
+    [InlineData("10", "SourceChannel", "四川省12345", "WorkDay", 1, "四川省12345 '咨询' 件1个工作日")] 
+    [InlineData("", "SourceChannel", "四川省12345", "WorkDay", 3, "四川省12345 '非咨询' 件3个工作日")]
+
+    [InlineData("10", "SourceChannel", "省政民互动", "WorkDay", 1, "省政民互动 '咨询' 件1个工作日")]
+    [InlineData("", "SourceChannel", "省政民互动", "WorkDay", 3, "省政民互动 '非咨询' 件3个工作日")]
+
+    [InlineData("10", "SourceChannel", "国家政务平台", "WorkDay", 1, "国家政务平台 '咨询' 件1个工作日")]
+    [InlineData("", "SourceChannel", "国家政务平台", "WorkDay", 3, "国家政务平台 '非咨询' 件3个工作日")]
+
+    [InlineData("10", "SourceChannel", "天府通办", "WorkDay", 1, "天府通办 '咨询' 件1个工作日")]
+    [InlineData("", "SourceChannel", "天府通办", "WorkDay", 3, "天府通办 '非咨询' 件3个工作日")]
+
+    [InlineData("10", "SourceChannel", "中国政府网", "WorkDay", 1, "中国政府网 '咨询' 件1个工作日")]
+    [InlineData("", "SourceChannel", "中国政府网", "WorkDay", 3, "中国政府网 '非咨询' 件3个工作日")]
+    public async Task InitTimeLimitInventory_Test(string busCode, string name, string value, string timeType, int timeValue, string remark)
+    {
+        var attributeEntity = new TimeLimitSettingAttribute { BusCode = busCode, Name = name, Value = value, IsCommon = false };
+        var dataEntity = await _timeLimitSettingAttributeRepository.GetAsync(attributeEntity.BusCode, attributeEntity.Name, attributeEntity.Value);
+        if (dataEntity is null) await _timeLimitSettingAttributeRepository.AddAsync(attributeEntity);
+
+        var attribute = await _timeLimitSettingAttributeRepository.GetAsync(busCode, name, value);
+        attribute.ShouldNotBeNull($"{name} 属性未初始化");
+        Enum.TryParse(timeType, out ETimeType eTimeType);
+        var entity = new TimeLimitSettingInventory { Code = attribute.Code.ToString(), TimeType = eTimeType, TimeValue = timeValue, Percentage = 80, PercentageOne = 50 , Remark = remark};
+        var m = await _timeLimitSettingInventoryRepository.GetByCode(entity.Code);
+        if (m is null) await _timeLimitSettingInventoryRepository.AddAsync(entity);
+    }
+
+}

+ 1 - 0
src/Hotline.Application.Tests/Hotline.Application.Tests.csproj

@@ -39,6 +39,7 @@
     <ProjectReference Include="..\Hotline.Api\Hotline.Api.csproj" />
     <ProjectReference Include="..\Hotline.Application\Hotline.Application.csproj" />
     <ProjectReference Include="..\Hotline.Repository.SqlSugar\Hotline.Repository.SqlSugar.csproj" />
+    <ProjectReference Include="..\Tr.Sdk\Tr.Sdk.csproj" />
     <ProjectReference Include="..\Hotline.WeChat\Hotline.WeChat.csproj" />
     <ProjectReference Include="..\XF.Domain.Repository\XF.Domain.Repository.csproj" />
     <ProjectReference Include="..\XF.Domain\XF.Domain.csproj" />

+ 44 - 0
src/Hotline.Application.Tests/Mock/MediatorMock.cs

@@ -0,0 +1,44 @@
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Tests.Mock;
+public class MediatorMock : IMediator
+{
+    public IAsyncEnumerable<TResponse> CreateStream<TResponse>(IStreamRequest<TResponse> request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public IAsyncEnumerable<object?> CreateStream(object request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public Task Publish(object notification, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public async Task Publish<TNotification>(TNotification notification, CancellationToken cancellationToken = default) where TNotification : INotification
+    {
+    }
+
+    public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public Task Send<TRequest>(TRequest request, CancellationToken cancellationToken = default) where TRequest : IRequest
+    {
+        throw new NotImplementedException();
+    }
+
+    public Task<object?> Send(object request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+}

+ 3 - 0
src/Hotline.Application.Tests/ReadME.md

@@ -0,0 +1,3 @@
+## 运行测试
+dotnet test --filter CalcEndTime_Test
+dotnet test --filter ZiGongExpireTimeTest.CalcExpiredTime_Test

+ 58 - 0
src/Hotline.Application.Tests/Repository/OrderVisitRepositoryTest.cs

@@ -0,0 +1,58 @@
+using Hotline.Orders;
+using Hotline.Push.FWMessage;
+using Hotline.Share.Dtos.Push;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Repository;
+public class OrderVisitRepositoryTest
+{
+    private readonly IOrderVisitRepository _orderVisitRepository;
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+
+    public OrderVisitRepositoryTest(IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository)
+    {
+        _orderVisitRepository = orderVisitRepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+    }
+
+    [Theory]
+    [InlineData("4", "SMSUnsatisfied", "2" , "不满意")]
+    [InlineData("1", "Visited", "5", "非常满意")]
+    public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey,  string orgResuktValue)
+    {
+        var visit = await _orderVisitRepository.Queryable()
+            .Where(m => m.VisitState == EVisitState.SMSVisiting)
+            .OrderByDescending(m => m.CreationTime)
+            .FirstAsync();
+
+        var dto = new PushReceiveMessageDto { ExternalId = visit.Id, IsSmsReply = true, SmsReplyContent = content };
+        var message = new Message();
+        await _orderVisitRepository.UpdateSmsReplyAsync(dto, message);
+        visit = _orderVisitRepository.Get(visit.Id);
+        visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
+        visit.NowEvaluate.Key.ShouldBe(content);
+        visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
+
+        if (content == "4" || content == "5")
+            visit.VisitType.ShouldBeNull();
+
+        await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
+            .FirstAsync()
+            .Then(async org =>
+            {
+                org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
+                org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
+                org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
+                org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
+            });
+    }
+}

+ 36 - 6
src/Hotline.Application.Tests/Startup.cs

@@ -1,4 +1,5 @@
 using Microsoft.AspNetCore.Hosting;
+using Tr.Sdk;
 using Hotline.Repository.SqlSugar.Extensions;
 using Microsoft.AspNetCore.TestHost;
 using Microsoft.Extensions.Configuration;
@@ -39,9 +40,17 @@ using XF.Utility.MQ;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using DotNetCore.CAP;
 using XF.Domain.Options;
-using Hotline.WeChat;
-using Hotline.Snapshot;
-using Hotline.Repository.SqlSugar.Snapshot;
+using Hotline.Settings.TimeLimitDomain;
+using Hotline.Settings.TimeLimitDomain.ExpireTimeSupplier;
+using Microsoft.AspNetCore.WebSockets;
+using Hotline.CallCenter.Configs;
+using MediatR;
+using Hotline.Application.Tests.Mock;
+using Hotline.Repository.SqlSugar.Ts;
+using Hotline.Application.CallCenter;
+using Hotline.Application.CallCenter.Calls;
+using Hotline.CallCenter.Configs;
+using Tr.Sdk;
 
 namespace Hotline.Application.Tests;
 public class Startup
@@ -81,10 +90,15 @@ public class Startup
             var appConfigurationSection = configuration.GetRequiredSection(nameof(AppConfiguration));
             var appConfiguration = appConfigurationSection.Get<AppConfiguration>();
             if (appConfiguration is null) throw new ArgumentNullException(nameof(appConfiguration));
-            services.Configure<AppConfiguration>(d => appConfigurationSection.Bind(d));
+
+            var callCenterConfigurationSection = configuration.GetRequiredSection(nameof(CallCenterConfiguration));
+            var callCenterConfiguration = callCenterConfigurationSection.Get<CallCenterConfiguration>();
+
+			services.Configure<AppConfiguration>(d => appConfigurationSection.Bind(d));
             services.Configure<IdentityConfiguration>(d => configuration.GetSection(nameof(IdentityConfiguration)).Bind(d));
+            services.Configure<CityBaseConfiguration>(d => configuration.GetSection(nameof(CityBaseConfiguration)).Bind(d));
 
-            services.RegisterMapper();
+			services.RegisterMapper();
 
             //sqlsugar
             services.AddSqlSugar(configuration);
@@ -107,6 +121,12 @@ public class Startup
             });
             services.AddScoped(typeof(IPasswordHasher<>), typeof(PasswordHasher<>));
             services.AddScoped(typeof(ITypedCache<>), typeof(DefaultTypedCache<>));
+            services.AddScoped(typeof(IRepositoryTextSearch<>), typeof(BaseRepositoryTextSearch<>));
+            services.AddScoped<ICallApplication, TianRunCallApplication>();
+            services.AddScoped<ITrApplication, TrApplication>();
+            services.AddTrSdk(callCenterConfiguration.TianRun.Address,
+                        callCenterConfiguration.TianRun.Username,
+                        callCenterConfiguration.TianRun.Password);
             services.RegisterMediatR(appConfiguration);
 
             services.AddSenparcWeixinServices(configuration);
@@ -122,7 +142,17 @@ public class Startup
             services.AddScoped<IThirdIdentiyService, ThirdTestService>();
             // services.AddScoped<IThirdIdentiyService, WeChatService>();
 
-            services.AddScoped<IThirdAccountRepository, ThirdAccountRepository>();
+            //services.AddScoped<IThirdAccountRepository, ThirdAccountRepository>();
+            services.AddApplication();
+            services.AddScoped<IExpireTimeSupplier, DaySupplier>();
+            services.AddScoped<IExpireTimeSupplier, WorkDaySupplier>();
+            services.AddScoped<IExpireTimeSupplier, HourSupplier>();
+            services.AddScoped<ExpireTimeFactory>();
+            services.AddScoped<YiBinExpireTimeLimit>();
+            services.AddScoped<ZiGongExpireTimeLimit>();
+            services.AddScoped<LuZhouExpireTimeLimit>();
+            services.AddScoped<IMediator, MediatorMock>();
+
             ServiceLocator.Instance = services.BuildServiceProvider();
         }
 

+ 2 - 0
src/Hotline.Application/ApplicationStartupExtensions.cs

@@ -1,5 +1,6 @@
 using Hotline.Application.Contracts;
 using Hotline.Application.Mappers;
+using Hotline.Application.Systems;
 using Mapster;
 using Microsoft.Extensions.DependencyInjection;
 
@@ -9,6 +10,7 @@ namespace Hotline.Application
     {
         public static IServiceCollection AddApplication(this IServiceCollection services)
         {
+            services.AddScoped<BaseDataApplication>();
             TypeAdapterConfig.GlobalSettings.Scan(typeof(MapperConfigs).Assembly);
             return services.AddAppContracts();
         }

+ 67 - 0
src/Hotline.Application/Bulletin/BulletinApplication.cs

@@ -0,0 +1,67 @@
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
+using System.Text;
+using System.Text.RegularExpressions;
+using XF.Domain.Dependency;
+
+namespace Hotline.Application.Bulletin
+{
+    public class BulletinApplication : IBulletinApplication, IScopeDependency
+    {
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+
+        public BulletinApplication(IOptionsSnapshot<AppConfiguration> appOptions)
+        {
+            _appOptions = appOptions;
+        }
+
+        /// <summary>
+        /// 处理通知公告图片附件路径
+        /// </summary>
+        /// <param name="sHtmlText"></param>
+        /// <returns></returns>
+        public string GetSiteUrls(string sHtmlText)
+        {
+            sHtmlText = sHtmlText.Replace("&lt;", "<").Replace("&gt;", ">");
+
+            //临时内容
+            System.Text.StringBuilder sb = new StringBuilder();
+            sb.Append(sHtmlText);
+            // 定义正则表达式用来匹配 img 标签
+            Regex regImg = new Regex(@"<img\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);
+            // 搜索匹配的字符串
+            MatchCollection matches = regImg.Matches(sHtmlText);
+
+            // 定义正则表达式用来匹配 video 标签
+            Regex regvideo = new Regex(@"<video\b[^<>]*?\bsrc[\s\t\r\n]*=[\s\t\r\n]*[""']?[\s\t\r\n]*(?<imgUrl>[^\s\t\r\n""'<>]*)[^<>]*?/?[\s\t\r\n]*>", RegexOptions.IgnoreCase);
+            // 搜索匹配的字符串
+            MatchCollection matchesvideo = regvideo.Matches(sHtmlText);
+
+
+            // 获取服务器地址配置 
+            string strSiteUrl = _appOptions.Value.OldFilesUrls;
+         
+            // 取得匹配项列表 视频
+            foreach (Match match in matchesvideo)
+            {
+                if (-1 == match.Groups["imgUrl"].Value.IndexOf("http"))
+                {
+                    sb.Replace(match.Groups["imgUrl"].Value, strSiteUrl + match.Groups["imgUrl"].Value);
+                    sb.Replace(strSiteUrl + strSiteUrl + match.Groups["imgUrl"].Value, strSiteUrl + match.Groups["imgUrl"].Value);
+                }
+            }
+
+            // 取得匹配项列表
+            foreach (Match match in matches)
+            {
+                if (-1 == match.Groups["imgUrl"].Value.IndexOf("http"))
+                {
+                    sb.Replace(match.Groups["imgUrl"].Value, strSiteUrl + match.Groups["imgUrl"].Value);
+                    sb.Replace(strSiteUrl + strSiteUrl + match.Groups["imgUrl"].Value, strSiteUrl + match.Groups["imgUrl"].Value);
+                }
+            }
+
+            return sb.ToString();
+        }
+    }
+}

+ 18 - 0
src/Hotline.Application/Bulletin/IBulletinApplication.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Bulletin
+{
+    public interface IBulletinApplication
+    {
+        /// <summary>
+        /// 处理通知公告图片附件路径
+        /// </summary>
+        /// <param name="sHtmlText"></param>
+        /// <returns></returns>
+        string GetSiteUrls(string sHtmlText);
+    }
+}

+ 415 - 71
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -30,6 +30,8 @@ using Hotline.Share.Dtos.File;
 using Microsoft.Extensions.Logging;
 using System.Text;
 using System.Diagnostics;
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
 using NPOI.SS.Formula.Functions;
 
 namespace Hotline.Application.FlowEngine;
@@ -56,8 +58,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     private readonly IMapper _mapper;
     private readonly IFileRepository _fileRepository;
     private readonly ILogger<WorkflowApplication> _logger;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+    private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
-    public WorkflowApplication(
+	public WorkflowApplication(
         IDefinitionDomainService definitionDomainService,
         IWorkflowDomainService workflowDomainService,
         IOrderDomainService orderDomainService,
@@ -75,7 +79,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         ISessionContext sessionContext,
         IMapper mapper,
         IFileRepository fileRepository,
-        ILogger<WorkflowApplication> logger)
+        ISystemSettingCacheManager systemSettingCacheManager,
+		ILogger<WorkflowApplication> logger,
+        IOptions<CityBaseConfiguration> cityBaseConfiguration)
     {
         _definitionDomainService = definitionDomainService;
         _workflowDomainService = workflowDomainService;
@@ -95,7 +101,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         _mapper = mapper;
         _fileRepository = fileRepository;
         _logger = logger;
-    }
+        _systemSettingCacheManager = systemSettingCacheManager;
+        _cityBaseConfiguration = cityBaseConfiguration;
+	}
 
     public async Task<string> StartWorkflowAsync(StartWorkflowDto dto, ISessionContext current, string externalId,
         DateTime? expiredTime, CancellationToken cancellationToken = default)
@@ -292,7 +300,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// 工单退回(返回前一节点)
     /// </summary>
     public async Task<EFlowDirection> PreviousAsync(PreviousWorkflowDto dto, string applicantId, string applicantOrgId, string[] applicantRoleIds,
-		ISessionContext current, CancellationToken cancellationToken)
+        ISessionContext current, CancellationToken cancellationToken)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
             withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
@@ -324,8 +332,27 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var targetStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
         if (targetStepDefine.StepType is EStepType.End)
             throw UserFriendlyException.SameMessage("结束节点不支持撤回");
-        //var isStartCountersign = targetStepDefine.CouldPrevStartCountersign(dto.NextHandlers.Count);
-        var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.HandlerType, dto.IsStartCountersign,
+		//var isStartCountersign = targetStepDefine.CouldPrevStartCountersign(dto.NextHandlers.Count);
+		var targetStep = workflow.Steps.FirstOrDefault(d => d.Code == dto.NextStepCode && d.IsOrigin);
+		if (targetStep is null)
+			throw UserFriendlyException.SameMessage("该流程尚未流转至该节点");
+
+		///退回到派单组 没有下一步办理人 获取之前节点办理人
+		if (!dto.NextHandlers.Any())
+		{
+			dto.NextHandlers.Add(new FlowStepHandler()
+			{
+				UserId = targetStep.HandlerId,
+				Username = targetStep.HandlerName,
+				OrgId = targetStep.HandlerOrgId,
+				OrgName = targetStep.HandlerOrgName,
+				Key = targetStep.HandlerId,
+				Value = targetStep.HandlerName,
+				RoleId = targetStep.RoleId,
+				RoleName = targetStep.RoleName
+			});
+		}
+		var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.HandlerType, dto.IsStartCountersign,
             dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList(), cancellationToken);
 
         //var stepHandlers = await GetNextStepHandlersAsync(workflow, targetStepDefine, dto, cancellationToken);
@@ -435,8 +462,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
             !_workflowDomainService.DynamicShouldTerminal(startStepDefine, _sessionContext.OrgLevel))
         {
-            var nextStepOption = await GetDynamicStepAsync(startStepDefine.InstancePolicy.Value,
-                   startStepDefine.StepType, startStepDefine.BusinessType, cancellationToken);
+	        var settingHandle = _systemSettingCacheManager.GetSetting(SettingConstants.RoleJingBanRen);
+	        var settingLead = _systemSettingCacheManager.GetSetting(SettingConstants.RoleLingDao);
+			var nextStepOption = await GetDynamicStepAsync(startStepDefine.InstancePolicy.Value,
+                   startStepDefine.StepType, startStepDefine.BusinessType, settingHandle?.SettingValue[0], settingLead?.SettingValue[0], cancellationToken);
             return new NextStepsDto<NextStepOption>
             {
                 Steps = new List<NextStepOption> { nextStepOption }
@@ -500,9 +529,11 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (currentStep.InstanceMode is EInstanceMode.Dynamic &&
             !_workflowDomainService.DynamicShouldTerminal(currentStepDefine, _sessionContext.OrgLevel))
         {
-            //动态生成下一步
-            var nextStepOption = await GetDynamicStepAsync(currentStep.InstancePolicy.Value, currentStep.StepType,
-                currentStep.BusinessType, cancellationToken);
+	        var settingHandle = _systemSettingCacheManager.GetSetting(SettingConstants.RoleJingBanRen);
+	        var settingLead = _systemSettingCacheManager.GetSetting(SettingConstants.RoleLingDao);
+			//动态生成下一步
+			var nextStepOption = await GetDynamicStepAsync(currentStep.InstancePolicy.Value, currentStep.StepType,
+                currentStep.BusinessType, settingHandle?.SettingValue[0], settingLead?.SettingValue[0], cancellationToken);
             dto.Steps = new List<NextStepOption> { nextStepOption };
             return dto;
         }
@@ -1008,16 +1039,29 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         };
     }
 
+    /// <summary>
+    /// 动态策略
+    /// </summary>
+    /// <returns></returns>
+    /// <exception cref="ArgumentOutOfRangeException"></exception>
     private async Task<NextStepOption> GetDynamicStepAsync(
         EDynamicPolicy policy, EStepType stepType,
-        EBusinessType currentBusinessType, CancellationToken cancellationToken)
+        EBusinessType currentBusinessType,string handleRoleCode,string leadRoleCode, CancellationToken cancellationToken)
     {
         int orgLevel;
         List<FlowStepHandler> items;
         string upperOrgId;
         EBusinessType businessType;
         EFlowDirection? flowDirection = null;
-        switch (policy)
+        bool isLead = false;
+        bool isSkip = false;
+		string roleId = string.Empty;
+        string roleName = string.Empty;
+        string handleRoleName = "经办人";
+        string leadRoleName = "领导";
+        EHandlerType handlerType = EHandlerType.OrgLevel;
+
+		switch (policy)
         {
             case EDynamicPolicy.OrgUpCenterTop:
                 orgLevel = _sessionContext.OrgLevel - 1;
@@ -1080,7 +1124,208 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     })
                     .ToListAsync(cancellationToken);
                 break;
-            case EDynamicPolicy.OrgDownCenterTop:
+			case EDynamicPolicy.OrgUpHandleCenterTop:
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel < 0) orgLevel = 0;
+
+				if (orgLevel == 0)
+				{
+					businessType = EBusinessType.Send;
+					if (currentBusinessType == EBusinessType.Department)
+						flowDirection = EFlowDirection.OrgToCenter;
+
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.IsCenter)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+				else
+				{
+					businessType = EBusinessType.Department;
+					handlerType = EHandlerType.AssignedOrgOrRole;
+					roleName = handleRoleName;
+					//上级部门Id
+					upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.Id == upperOrgId)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name,
+							RoleId = handleRoleCode,
+							RoleName = handleRoleName,
+						})
+						.ToListAsync(cancellationToken);
+				}
+
+				break;
+			case EDynamicPolicy.OrgUpHandle:
+				businessType = _sessionContext.OrgIsCenter
+					? EBusinessType.Send
+					: _sessionContext.RequiredOrgId.CalcOrgLevel() == 1
+						? EBusinessType.Send
+						: EBusinessType.Department;
+				orgLevel = _sessionContext.OrgLevel - 1;
+				handlerType = EHandlerType.AssignedOrgOrRole;
+				if (orgLevel <= 0) orgLevel = 1;
+                roleName = handleRoleName;
+				//上级部门Id
+				upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+				items = await _organizeRepository.Queryable()
+					.Where(d => d.Id == upperOrgId)
+					.Select(d => new FlowStepHandler
+					{
+						Key = d.Id,
+						Value = d.Name,
+						OrgId = d.Id,
+						OrgName = d.Name,
+						RoleId = handleRoleCode,
+						RoleName = handleRoleName,
+					})
+					.ToListAsync(cancellationToken);
+				break;
+			case EDynamicPolicy.OrgUpLeadCenterTop:
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel < 0) orgLevel = 0;
+
+				if (orgLevel == 0)
+				{
+					businessType = EBusinessType.Send;
+					if (currentBusinessType == EBusinessType.Department)
+						flowDirection = EFlowDirection.OrgToCenter;
+
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.IsCenter)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+				else
+				{
+					businessType = EBusinessType.Department;
+					handlerType = EHandlerType.AssignedOrgOrRole;
+					upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(_sessionContext.OrgLevel);
+					isLead = _sessionContext.Roles.Any(x => x == leadRoleCode);
+                    if (!isLead)
+                    {
+	                    isSkip = await _userRepository.Queryable().AnyAsync(x => x.OrgId == _sessionContext.RequiredOrgId && x.Roles.Any(r => r.Name == leadRoleCode), cancellationToken);
+	                    if (isSkip)
+	                    {
+		                    roleId = leadRoleCode;
+		                    roleName = leadRoleName;
+	                    }
+                    }
+					if (isLead || !isSkip)
+                    {
+	                    //上级部门Id
+	                    upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+	                    roleId = handleRoleCode;
+	                    roleName = handleRoleName;
+                    }
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.Id == upperOrgId)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name,
+							RoleId = roleId,
+							RoleName = roleName
+						})
+						.ToListAsync(cancellationToken);
+				}
+
+				break;
+			case EDynamicPolicy.OrgUpLead:
+				businessType = _sessionContext.OrgIsCenter
+					? EBusinessType.Send
+					: _sessionContext.RequiredOrgId.CalcOrgLevel() == 1
+						? EBusinessType.Send
+						: EBusinessType.Department;
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel <= 0) orgLevel = 1;
+				handlerType = EHandlerType.AssignedOrgOrRole;
+				upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(_sessionContext.OrgLevel);
+				isLead = _sessionContext.Roles.Any(x => x == leadRoleCode);
+				if (!isLead)
+				{
+					isSkip = await _userRepository.Queryable().AnyAsync(x => x.OrgId == _sessionContext.RequiredOrgId && x.Roles.Any(r => r.Name == leadRoleCode), cancellationToken);
+					if (isSkip)
+					{
+						roleId = leadRoleCode;
+						roleName = leadRoleName;
+					}
+				}
+				if (isLead || !isSkip)
+				{
+					//上级部门Id
+					upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+					roleId = handleRoleCode;
+					roleName = handleRoleName;
+				}
+				items = await _organizeRepository.Queryable()
+					.Where(d => d.Id == upperOrgId)
+					.Select(d => new FlowStepHandler
+					{
+						Key = d.Id,
+						Value = d.Name,
+						OrgId = d.Id,
+						OrgName = d.Name,
+						RoleId = roleId,
+						RoleName = roleName
+					})
+					.ToListAsync(cancellationToken);
+				break;
+			case EDynamicPolicy.ArriveCenter:
+				businessType = _sessionContext.OrgIsCenter
+					? EBusinessType.Send
+					: _sessionContext.RequiredOrgId.CalcOrgLevel() == 1
+						? EBusinessType.Send
+						: EBusinessType.Department;
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel <= 0) orgLevel = 1;
+				items = await _organizeRepository.Queryable()
+					.Where(d =>  d.IsCenter)
+					.Select(d => new FlowStepHandler
+					{
+						Key = d.Id,
+						Value = d.Name,
+						OrgId = d.Id,
+						OrgName = d.Name
+					})
+					.ToListAsync(cancellationToken);
+				break;
+            case EDynamicPolicy.ArriveOneOrg:
+	            businessType = _sessionContext.OrgIsCenter? EBusinessType.Send: EBusinessType.Department;
+                orgLevel = _sessionContext.OrgIsCenter ? 0 : 1;
+				//上级部门Id
+				upperOrgId = _sessionContext.OrgIsCenter ? _sessionContext.RequiredOrgId.Substring(0,3) : _sessionContext.RequiredOrgId.Substring(0, 6);
+				items = await _organizeRepository.Queryable()
+		            .Where(d => d.Id == upperOrgId)
+		            .Select(d => new FlowStepHandler
+		            {
+			            Key = d.Id,
+			            Value = d.Name,
+			            OrgId = d.Id,
+			            OrgName = d.Name
+		            })
+		            .ToListAsync(cancellationToken);
+	            break;
+			case EDynamicPolicy.OrgDownCenterTop:
                 businessType = EBusinessType.Department;
                 if (_sessionContext.OrgIsCenter)
                 {
@@ -1134,19 +1379,158 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         return new NextStepOption
         {
             Key = orgLevel.ToString(),
-            Value = orgLevel == 0 ? "市民热线服务中心" : $"{orgLevel.ToChinese()}级部门",
+            Value = orgLevel == 0 ? "市民热线服务中心" : $"{orgLevel.ToChinese()}级部门 {roleName}",
             FlowDirection = flowDirection,
             StepType = stepType,
             BusinessType = businessType,
-            HandlerType = EHandlerType.OrgLevel, //目前所有动态策略均属于部门等级
+            HandlerType = handlerType, //目前所有动态策略均属于部门等级
             Items = items
         };
     }
 
     /// <summary>
-    /// 查询下一节点办理对象类型(user or org)及实际办理对象
+    /// 会签 动态策略
     /// </summary>
-    public async Task<FlowAssignInfo> GetNextStepFlowAssignInfoAsync(Workflow workflow, WorkflowStep currentStep,
+    /// <returns></returns>
+
+	private async Task<NextStepOption> GetDynamicStepAsync(
+		EDynamicPolicyCountersign policy, EStepType stepType,
+		EBusinessType currentBusinessType, CancellationToken cancellationToken)
+	{
+		int orgLevel;
+		List<FlowStepHandler> items;
+		string upperOrgId;
+		EBusinessType businessType;
+		EFlowDirection? flowDirection = null;
+		switch (policy)
+		{
+			case EDynamicPolicyCountersign.OrgUpCenterTop:
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel < 0) orgLevel = 0;
+
+				if (orgLevel == 0)
+				{
+					businessType = EBusinessType.Send;
+					if (currentBusinessType == EBusinessType.Department)
+						flowDirection = EFlowDirection.OrgToCenter;
+
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.IsCenter)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+				else
+				{
+					businessType = EBusinessType.Department;
+
+					//上级部门Id
+					upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+					items = await _organizeRepository.Queryable()
+						.Where(d => d.Id == upperOrgId)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+
+				break;
+			case EDynamicPolicyCountersign.OrgUp:
+				businessType = _sessionContext.OrgIsCenter
+					? EBusinessType.Send
+					: _sessionContext.RequiredOrgId.CalcOrgLevel() == 1
+						? EBusinessType.Send
+						: EBusinessType.Department;
+				orgLevel = _sessionContext.OrgLevel - 1;
+				if (orgLevel <= 0) orgLevel = 1;
+				//上级部门Id
+				upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
+				items = await _organizeRepository.Queryable()
+					.Where(d => d.Id == upperOrgId)
+					.Select(d => new FlowStepHandler
+					{
+						Key = d.Id,
+						Value = d.Name,
+						OrgId = d.Id,
+						OrgName = d.Name
+					})
+					.ToListAsync(cancellationToken);
+				break;
+			case EDynamicPolicyCountersign.OrgDownCenterTop:
+				businessType = EBusinessType.Department;
+				if (_sessionContext.OrgIsCenter)
+				{
+					orgLevel = 1;
+					items = await _organizeRepository.Queryable()
+						.Where(d => !d.IsCenter && d.Level == orgLevel)
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+				else
+				{
+					orgLevel = _sessionContext.OrgLevel + 1;
+					items = await _organizeRepository.Queryable()
+						.Where(d => !d.IsCenter && d.Level == orgLevel &&
+									d.Id.StartsWith(_sessionContext.RequiredOrgId))
+						.Select(d => new FlowStepHandler
+						{
+							Key = d.Id,
+							Value = d.Name,
+							OrgId = d.Id,
+							OrgName = d.Name
+						})
+						.ToListAsync(cancellationToken);
+				}
+
+				break;
+			case EDynamicPolicyCountersign.OrgDown:
+				businessType = EBusinessType.Department;
+				orgLevel = _sessionContext.OrgLevel + 1;
+				items = await _organizeRepository.Queryable()
+					.Where(d => d.Level == orgLevel && d.Id.StartsWith(_sessionContext.RequiredOrgId))
+					.Select(d => new FlowStepHandler
+					{
+						Key = d.Id,
+						Value = d.Name,
+						OrgId = d.Id,
+						OrgName = d.Name
+					})
+					.ToListAsync(cancellationToken);
+				break;
+			default:
+				throw new ArgumentOutOfRangeException(nameof(policy), policy, null);
+		}
+
+		return new NextStepOption
+		{
+			Key = orgLevel.ToString(),
+			Value = orgLevel == 0 ? "市民热线服务中心" : $"{orgLevel.ToChinese()}级部门",
+			FlowDirection = flowDirection,
+			StepType = stepType,
+			BusinessType = businessType,
+			HandlerType = EHandlerType.OrgLevel, //目前所有动态策略均属于部门等级
+			Items = items
+		};
+	}
+	/// <summary>
+	/// 查询下一节点办理对象类型(user or org)及实际办理对象
+	/// </summary>
+	public async Task<FlowAssignInfo> GetNextStepFlowAssignInfoAsync(Workflow workflow, WorkflowStep currentStep,
         BasicWorkflowDto dto, StepDefine nextStepDefine, bool isNextDynamic, CancellationToken cancellationToken)
     {
         if (nextStepDefine.StepType is EStepType.End) return new();
@@ -1168,19 +1552,17 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         {
             if (currentStep.IsCountersignEndStep)
             {
+                //汇总节点(非顶级)
                 if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
                 {
-                    //汇总节点(非顶级)
-                    //var csStartStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
-                    //if (csStartStep is null)
-                    //    throw new UserFriendlyException("未查询到会签开始节点");
-                    var csStartStep = GetCsLoopStartStep(workflow, currentStep);
-
-                    var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == csStartStep.PrevStepId);
-                    if (prevStep is null)
-                        throw new UserFriendlyException("未查询到目标节点的前一节点");
-
-                    return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
+                    if (dto.BackToCountersignEnd)
+                    {
+                        var csStartStep = GetCsLoopStartStep(workflow, currentStep);
+                        var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == csStartStep.PrevStepId);
+                        if (prevStep is null)
+                            throw new UserFriendlyException("未查询到目标节点的前一节点");
+                        return FlowAssignInfo.Create(prevStep.FlowAssignType.Value, prevStep.Handlers, isStartCountersign);
+                    }
                 }
             }
             else
@@ -1208,46 +1590,6 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             cancellationToken);
     }
 
-    //private async ValueTask<List<WorkflowStepHandler>> GetNextStepHandlersAsync(Workflow workflow,
-    //    StepDefine nextStepDefine, BasicWorkflowDto dto, CancellationToken cancellationToken)
-    //{
-    //    var assignType = FlowAssignInfo.GetAssignType(dto.HandlerType);
-    //    //var assignType = AssignInfo.GetAssignType(nextStepDefine.HandlerType, dto.NextHandlers.Any());
-    //    switch (assignType)
-    //    {
-    //        case EFlowAssignType.Org:
-    //            return dto.NextHandlers.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
-    //                assignType, orgId: d.Key, orgName: d.Value)).ToList();
-    //        case EFlowAssignType.User:
-    //            if (!dto.NextHandlers.Any() && dto.HandlerType is EHandlerType.Role)
-    //            {
-    //                var stepOption = await GetConfigStepAsync(EFlowType.Handle, nextStepDefine, cancellationToken);
-    //                var uIds = stepOption.Items.Select(d => d.Key).ToList();
-    //                var users1 = await _userRepository.Queryable()
-    //                    .Includes(d => d.Organization)
-    //                    .Where(d => uIds.Contains(d.Id))
-    //                    .ToListAsync(cancellationToken);
-    //                return users1.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
-    //                        assignType, d.Id, d.Name, d.OrgId, d.Organization.Name))
-    //                    .ToList();
-    //            }
-    //            var userIds = dto.NextHandlers.Select(d => d.Key).ToList();
-    //            var users = await _userRepository.Queryable()
-    //                .Includes(d => d.Organization)
-    //                .Where(d => userIds.Contains(d.Id))
-    //                .ToListAsync(cancellationToken);
-    //            return users.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
-    //                    assignType, d.Id, d.Name, d.OrgId, d.Organization.Name))
-    //                .ToList();
-    //        //case EFlowAssignType.Role:
-    //        //    handlers = dto.NextHandlers.Select(d => WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
-    //        //        assignType, roleId: d.Key, roleName: d.Value)).ToList();
-    //        //    break;
-    //        default:
-    //            throw new ArgumentOutOfRangeException();
-    //    }
-    //}
-
     /// <summary>
     /// 按流程模板配置创建下一步办理对象
     /// </summary>
@@ -1279,6 +1621,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
             case EHandlerType.AssignedUser:
                 return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
+            case EHandlerType.AssignedOrgOrRole:
+	            return FlowAssignInfo.Create(EFlowAssignType.OrgOrRole, handlers, isStartCountersign);
 
             default:
                 throw new ArgumentOutOfRangeException();
@@ -1354,8 +1698,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
             cancellationToken: cancellationToken);
         var step = workflow.Steps.FirstOrDefault(d =>
-            //d.StepHandlers.Any(d => d.OrgId == "001171" || d.OrgId == "001178"));
-            d.HandlerOrgId == "001171" || d.HandlerOrgId == "001178");
+			//d.StepHandlers.Any(d => d.OrgId == _cityBaseConfiguration.Value.CityProvince.OrgId || d.OrgId == _cityBaseConfiguration.Value.CityProvinceAssign.OrgId));
+			d.HandlerOrgId == _cityBaseConfiguration.Value.CityProvince.OrgId || d.HandlerOrgId == _cityBaseConfiguration.Value.CityProvinceAssign.OrgId);
         if (step is not null)
         {
             step.FileJson = await _fileRepository.AddFileAsync(files, workflow.ExternalId, step.Id, cancellationToken);

+ 27 - 6
src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs

@@ -2,6 +2,7 @@
 using Hotline.Application.JudicialManagement;
 using Hotline.Application.Quality;
 using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.EventBus;
 using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
@@ -11,19 +12,23 @@ using Hotline.KnowledgeBase;
 using Hotline.Orders;
 using Hotline.Push.Notifies;
 using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain;
 using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Push;
 using Hotline.Share.Enums.Quality;
 using Hotline.Share.Mq;
 using Hotline.Users;
+using Mapster;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
 using XF.Domain.Authentications;
 using XF.Domain.Entities;
 using XF.Domain.Repository;
@@ -33,6 +38,8 @@ namespace Hotline.Application.Handlers.FlowEngine;
 public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
 {
     private readonly IOrderDomainService _orderDomainService;
+    private readonly ICalcExpireTime _expireTime;
+    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
     private readonly IOrderRepository _orderRepository;
     private readonly ICapPublisher _capPublisher;
     private readonly IMapper _mapper;
@@ -46,7 +53,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     private readonly Publisher _publisher;
 
-    public WorkflowNextHandler(
+	public WorkflowNextHandler(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         ICapPublisher capPublisher,
@@ -59,7 +66,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
         IRepository<User> userRepository,
         IMediator mediator,
         ISystemSettingCacheManager systemSettingCacheManager,
-        Publisher publisher)
+        Publisher publisher,
+        IOptionsSnapshot<AppConfiguration> appOptions,
+        ICalcExpireTime expireTime)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -74,6 +83,8 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
         _mediator = mediator;
         _systemSettingCacheManager = systemSettingCacheManager;
         _publisher = publisher;
+        _appOptions = appOptions;
+        _expireTime = expireTime;
     }
 
     /// <summary>Handles a notification</summary>
@@ -105,6 +116,14 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                     order.UpdateHandlingStatus(workflow.IsInCountersign);
                     _mapper.Map(workflow, order);
 
+                    if (_appOptions.Value.IsZiGong && data.FlowDirection is EFlowDirection.CenterToOrg)
+                    {
+                        var expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToOrg , order.Adapt<OrderTimeClacInfo>());
+                        order.CenterToOrg(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
+                            expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime
+                            , expiredTimeConfig.NearlyExpiredTimeOne, notification.Dto.Opinion,notification.Trace.HandlerId, notification.Trace.HandlerName,true);
+                    }
+
                     //var expiredTimeChanged = false;
                     //if (data.FlowDirection.HasValue
                     //    && data.External.TimeLimit.HasValue                   
@@ -138,7 +157,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
 
                     //    expiredTimeChanged = true;
                     //}
-                    await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
+                    if (data.FlowDirection is EFlowDirection.CenterToOrg)
+                        order.SendBackAuditEndTime = await _expireTime.WorkDay_ZG(DateTime.Now);
+					await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
                     //await _orderRepository.UpdateAsync(order, cancellationToken);
 
                     //司法行政监督管理-推诿工单
@@ -182,7 +203,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                                     }
                                     break;
                                 case EFlowAssignType.User:
-                                    var userCodes = notification.Trace.NextHandlers.Select(x=>x.UserId); //notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
+                                    var userCodes = notification.Trace.NextHandlers.Select(x => x.UserId); //notification.FlowAssignInfo.HandlerObjects.Select(x => x.Key);
                                     var userList = await _userRepository.Queryable()
                                         .Where(x => userCodes.Contains(x.Id) && !string.IsNullOrEmpty(x.PhoneNo))
                                         .ToListAsync(cancellationToken);
@@ -219,9 +240,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                         HandlerOrgLevel = notification.HandlerOrgId.CalcOrgLevel()
                     }, cancellationToken: cancellationToken);
                     if (data.FlowDirection is EFlowDirection.CenterToOrg)
-	                    await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, cancellationToken);
+                        await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, cancellationToken);
 
-					break;
+                    break;
                 case WorkflowModuleConsts.KnowledgeAdd:
                 case WorkflowModuleConsts.KnowledgeUpdate:
                 case WorkflowModuleConsts.KnowledgeDelete:

+ 1 - 1
src/Hotline.Application/Jobs/SendOverTimeSmsJob.cs

@@ -25,7 +25,7 @@ namespace Hotline.Application.Jobs
 
         public async Task Execute(IJobExecutionContext context)
         {
-            Console.WriteLine($"{nameof(SendOrderJob)} 执行, {DateTime.Now}");
+            Console.WriteLine($"{nameof(SendOverTimeSmsJob)} 执行, {DateTime.Now}");
             await _orderDomainService.SendOverTimeSms(context.CancellationToken);
         }
     }

+ 22 - 0
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -8,6 +8,12 @@ using MapsterMapper;
 using Microsoft.Extensions.Logging;
 using XF.Domain.Repository;
 using XingTang.Sdk;
+using DotNetCore.CAP;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.CallCenter;
+using System.Dynamic;
+using Hotline.Share.Dtos.CallCenter;
 
 namespace Hotline.Application.Jobs
 {
@@ -19,6 +25,7 @@ namespace Hotline.Application.Jobs
         private readonly IRepository<CallNative> _callRepository;
         private readonly IRepository<User> _userRepository;
         private readonly ICallApplication _callApplication;
+        private readonly ICapPublisher _capPublisher;
         private readonly IMapper _mapper;
         private readonly ILogger<XingTangCallsSyncJob> _logger;
         private readonly ISqlSugarClient _db;
@@ -28,12 +35,14 @@ namespace Hotline.Application.Jobs
             IRepository<CallNative> callRepository,
             IRepository<User> userRepository,
             ICallApplication callApplication,
+            ICapPublisher capPublisher,
             IMapper mapper,
             ILogger<XingTangCallsSyncJob> logger)
         {
             _callRepository = callRepository;
             _userRepository = userRepository;
             _callApplication = callApplication;
+            _capPublisher = capPublisher;
             _mapper = mapper;
             _logger = logger;
             _db = uow.Db;
@@ -80,6 +89,19 @@ namespace Hotline.Application.Jobs
                 }
 
                 await _callRepository.AddRangeAsync(calls, context.CancellationToken);
+
+                //推省上
+                if (calls.Any())
+                {
+                    var callIns = _mapper.Map<List<CallNativeDto>>(calls);
+                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallAdd, callIns);
+                }
+                ////todo
+                //var callIns = calls.Where(d => d.Direction == ECallDirection.In).ToList();
+                //if (callIns.Any())
+                //{
+                //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallAdd, callIns);
+                //}
             }
             catch (Exception e)
             {

+ 0 - 2
src/Hotline.Application/JudicialManagement/EnforcementApplication.cs

@@ -266,8 +266,6 @@ namespace Hotline.Application.JudicialManagement
         /// <returns></returns>
         public ISugarQueryable<VisitAndOrgSatisfactionStatisticsDto> GetVisitAndOrgSatisfactionStatisticsAsync(DateTime StartTime, DateTime EndTime, int TypeId)
         {
-            EndTime = EndTime.AddDays(1).AddSeconds(-1);
-
             return _judicialManagementOrdersRepository.Queryable()
                  .LeftJoin<OrderVisit>((x, o) => x.Id == o.OrderId)
                  .LeftJoin<OrderVisitDetail>((x, o, p) => o.Id == p.VisitId)

+ 3 - 5
src/Hotline.Application/JudicialManagement/JudicialManagementOrderNotifyHandler.cs

@@ -1,6 +1,5 @@
 using Hotline.Caching.Interfaces;
 using Hotline.DI;
-using Hotline.EventBus;
 using Hotline.JudicialManagement;
 using Hotline.JudicialManagement.Notifies;
 using Hotline.Settings;
@@ -89,7 +88,6 @@ namespace Hotline.Application.JudicialManagement
             //需要添加
             if (isAdd)
             {
-
                 var orderData = await _judicialManagementOrdersRepository.GetAsync(p => p.Id == order.Id, cancellationToken);
                 if (orderData == null)
                 {
@@ -103,7 +101,7 @@ namespace Hotline.Application.JudicialManagement
                     orderData.OrderSoure = EOrderSoure.Hotline;
                     List<Kv> kvs = new()
                     {
-                        new Kv { Key = order.OrgLevelOneName, Value = order.OrgLevelOneCode }
+                        new Kv { Key = order.ActualHandleOrgName, Value = order.ActualHandleOrgCode }
                     };
                     orderData.EnforcementOrdersHandler = kvs;
                     await _judicialManagementOrdersRepository.AddAsync(orderData, cancellationToken);
@@ -114,8 +112,8 @@ namespace Hotline.Application.JudicialManagement
                         OrderId = order.Id,
                         OrderNo = order.No,
                         OrderSoure = EOrderSoure.Hotline,
-                        OrgCode = order.OrgLevelOneCode,
-                        OrgName = order.OrgLevelOneName
+                        OrgCode = order.ActualHandleOrgCode,
+                        OrgName = order.ActualHandleOrgName
                     };
                     await _enforcementOrdersHandlerRepository.AddAsync(enforcementOrdersHandler, cancellationToken);
                 }

+ 3 - 1
src/Hotline.Application/Mappers/CallMapperConfigs.cs

@@ -111,6 +111,7 @@ namespace Hotline.Application.Mappers
                 .Map(d => d.Duration, s => s.Duration)
                 .Map(d => d.TelNo, s => s.TelNo)
                 .Map(d => d.RecordingFileUrl, s => s.AudioFile)
+                .Map(d => d.OtherAccept, s => s.Id)
                 ;
 
             config.ForType<TrCallRecord, TrCallDtoNew>()
@@ -123,7 +124,8 @@ namespace Hotline.Application.Mappers
                 .Map(d => d.FromNo, s => s.CPN)
                 .Map(d => d.ToNo, s => s.CDPN)
                 .Map(d => d.EndRingTime, s => s.EndRingTimg)
-                .Map(d => d.AudioFile, s => s.RecordingAbsolutePath);
+                .Map(d => d.AudioFile, s => s.RecordingAbsolutePath)
+                .Map(d => d.BeginIvrTime, s => s.CreatedTime);
 
         }
 

+ 21 - 0
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -9,6 +9,8 @@ using Hotline.Share.Dtos.JudicialManagement;
 using Hotline.Share.Dtos.OrderExportWord;
 using Hotline.Share.Dtos.Org;
 using Hotline.Share.Dtos.Push.FWMessage;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.Order;
 using Hotline.Snapshot;
@@ -21,6 +23,25 @@ namespace Hotline.Application.Mappers
     {
         public void Register(TypeAdapterConfig config)
         {
+            config.ForType<SystemDicData, SystemDicDataOutDto>()
+                .Map(m => m.Id, n => n.Id)
+                .Map(m => m.DicDataName, n => n.DicDataName)
+                .Map(m => m.DicDataValue, n => n.DicDataValue);
+
+            config.ForType<Tr.Sdk.Tels.QueryTelResponse, TelOutDto>()
+                .Map(m => m.TelPwd, x => x.Password)
+                .Map(m =>m.Queue, x => x.QueueId);
+
+            config.ForType<TimeLimitSettingInventory, TimeConfig>()
+                .Map(d => d.Count, m => m.TimeValue);
+            config.ForType<TimeResult, ExpiredTimeWithConfig>()
+                .Map(d => d.ExpiredTime, x => x.EndTime)
+                .Map(d => d.NearlyExpiredTime, x => x.NearlyExpiredTime)
+                .Map(d => d.NearlyExpiredTimeOne, x => x.NearlyExpiredTimeOne);
+                
+            config.ForType<TimeLimitSetting, TimeConfig>()
+                .Map(d => d.Count, x => x.TimeValue);
+
             config.ForType<ThirdAccount, SnapshotUserInfoOutDto>();
             config.ForType<ThirdTokenOutDto, ThirdAccount>()
                 .Map(d => d.WXOpenId, m => m.OpenId);

+ 2 - 2
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -52,7 +52,7 @@ public class OrderMapperConfigs : IRegister
             .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.ReTransactNum)
             .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.HotspotSpliceName)
             .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.OrgLevelOneName)
-            .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.ActualHandleOrgName)
+            .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.CurrentHandleOrgName)
             .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.Title)
             .IgnoreIf((s, d) => s.OrderVisit.Employee == null, d => d.VisitUser)
             .IgnoreIf((s, d) => s.OrderVisit.Order == null, d => d.Content)
@@ -64,7 +64,7 @@ public class OrderMapperConfigs : IRegister
             .Map(d => d.ReTransactNum, s => s.OrderVisit.Order.ReTransactNum)
             .Map(d => d.HotspotSpliceName, s => s.OrderVisit.Order.HotspotSpliceName)
             .Map(d => d.OrgLevelOneName, s => s.OrderVisit.Order.OrgLevelOneName)
-            .Map(d => d.ActualHandleOrgName, s => s.OrderVisit.Order.ActualHandleOrgName)
+            .Map(d => d.CurrentHandleOrgName, s => s.OrderVisit.Order.CurrentHandleOrgName)
             .Map(d => d.Title, s => s.OrderVisit.Order.Title)
             .Map(d => d.VisitUser, s => s.OrderVisit.Employee.Name)
             .Map(d => d.VisitType, s => s.OrderVisit.VisitType)

+ 2 - 2
src/Hotline.Application/Mappers/WebPortalMapperConfigs.cs

@@ -25,7 +25,7 @@ namespace Hotline.Application.Mappers
                .Map(d => d.ConTypeName, x => x.Order.HotspotName)
                .Map(d => d.FlowAddDate, x => x.Order.StartTime)
                .Map(d => d.PubDate, x => x.CreationTime)
-               .Map(d => d.RSFlagName, x => x.Order.Status < EOrderStatus.Filed ? "办理中" : "办理完成")
+               .Map(d => d.RSFlagName, x => x.Order.Status <= EOrderStatus.Filed ? "办理中" : "办理完成")
           ;
 
             //办件摘编详情
@@ -45,7 +45,7 @@ namespace Hotline.Application.Mappers
             .Map(d => d.FlowBMID, x => x.ActualHandleOrgCode)
             .Map(d => d.FlowBMName, x => x.ActualHandleOrgName)
             .Map(d => d.FlowLKName, x => x.FromName)
-            .Map(d => d.FlowRSFlagName, x => x.Status < EOrderStatus.Filed ? "办理中" : "办理完成")
+            .Map(d => d.FlowRSFlagName, x => x.Status <= EOrderStatus.Filed ? "办理中" : "办理完成")
        ;
 
             //注册用户数据

+ 29 - 0
src/Hotline.Application/Mappers/WorkflowMapperConfigs.cs

@@ -1,9 +1,11 @@
 using Hotline.FlowEngine.Definitions;
 using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Definition;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Tools;
 using Mapster;
 
 namespace Hotline.Application.Mappers;
@@ -79,6 +81,33 @@ public class WorkflowMapperConfigs : IRegister
             .Map(d => d.RealContactLocale, s => s.RealContactLocale)
             .IgnoreNonMapped(true);
 
+        config.ForType<NextWorkflowDto, Order>()
+            .Map(src => src.RealCommunicationAddress, dest => dest.RealCommunicationAddress)
+            .IgnoreIf((src, dest) => src.RealCommunicationAddress.IsNullOrEmpty(), dest => dest.RealCommunicationAddress)
+            .Map(src => src.RealHandlerPhone , dest => dest.RealHandlerPhone)
+            .IgnoreIf((src, dest) => src.RealHandlerPhone.IsNullOrEmpty(), dest => dest.RealHandlerPhone)
+            .Map(src => src.RealHandlerName, dest => dest.RealHandlerName)
+            .IgnoreIf((src, dest) => src.RealHandlerName.IsNullOrEmpty(), dest => dest.RealHandlerName)
+            .Map(src => src.RealCommunicationMode, dest => dest.RealCommunicationMode)
+            .IgnoreIf((src, dest) => src.RealCommunicationMode == null, dest => dest.RealCommunicationMode)
+            .Map(src => src.RealCommunicationTime, dest => dest.RealCommunicationTime)
+            .IgnoreIf((src, dest) => src.RealCommunicationTime == null, dest => dest.RealCommunicationTime)
+            .Map(src => src.RealIsContacted, dest => dest.RealIsContacted)
+            .IgnoreIf((src, dest) => src.RealIsContacted == null, dest => dest.RealIsContacted)
+            .Map(src => src.RealContactLocale, dest => dest.RealContactLocale)
+            .IgnoreIf((src, dest) => src.RealContactLocale == null, dest => dest.RealContactLocale)
+            .Map(src => src.IsOther, dest => dest.IsOther)
+            .IgnoreIf((src, dest) => src.IsOther == null, dest => dest.IsOther)
+            .Map(src => src.OtherRemark, dest => dest.OtherRemark)
+            .IgnoreIf((src, dest) => src.OtherRemark.IsNullOrEmpty(), dest => dest.OtherRemark)
+            .Map(src => src.TranspondCityId, dest => dest.TranspondCityId)
+            .IgnoreIf((src, dest) => src.TranspondCityId.IsNullOrEmpty(), dest => dest.TranspondCityId)
+            .Map(src => src.TranspondCityName, dest => dest.TranspondCityName)
+            .IgnoreIf((src, dest) => src.TranspondCityName.IsNullOrEmpty(), dest => dest.TranspondCityName)
+            .Map(src => src.TranspondCityValue, dest => dest.TranspondCityValue)
+            .IgnoreIf((src, dest) => src.TranspondCityValue.IsNullOrEmpty(), dest => dest.TranspondCityValue)
+            .IgnoreNonMapped(true);
+
         config.ForType<Workflow, WorkflowStep>()
             .Map(d => d.WorkflowId, s => s.Id)
             .Map(d => d.ExternalId, s => s.ExternalId)

+ 35 - 11
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -11,12 +11,14 @@ using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Bi;
 using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Requests;
 using MediatR;
+using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Entities;
@@ -74,6 +76,21 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         Task OrderVisitWeb(OrderVisitWebDto dto, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 回访保存
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task SaveOrderVisit(VisitDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 发送回访短信
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task VisitPushSMSAsync(VisitSmsInDto dto, CancellationToken cancellationToken);
+
         /// <summary>
         /// 回访来源统计
         /// </summary>
@@ -100,6 +117,13 @@ namespace Hotline.Application.Orders
 
         ISugarQueryable<Order> QueryOrders(QueryOrderDto dto);
 
+        /// <summary>
+        /// 保存工单办理时页面填写的数据
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<Order> SaveOrderWorkflowInfo(NextWorkflowDto dto, CancellationToken cancellationToken);
+
         #endregion
 
         /// <summary>
@@ -218,20 +242,20 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         ISugarQueryable<OrderBiCentreDataListVo> CentreDataList(ReportPagedRequest dto);
 
-		/// <summary>
-		/// 热点受理类型统计
+        /// <summary>
+        /// 热点受理类型统计
         /// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		Task<(List<SystemDicData> acceptTypes, object items)> HotspotAndAcceptTypeStatistics(HotspotAndAcceptTypeStatisticsReq dto);
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<(List<SystemDicData> acceptTypes, object items)> HotspotAndAcceptTypeStatistics(HotspotAndAcceptTypeStatisticsReq dto);
 
 
-		/// <summary>
-		/// 热点受理类型统计--导出
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		Task<DataTable> HotspotAndAcceptTypeStatisticsExport(HotspotAndAcceptTypeStatisticsReq dto);
+        /// <summary>
+        /// 热点受理类型统计--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<DataTable> HotspotAndAcceptTypeStatisticsExport(HotspotAndAcceptTypeStatisticsReq dto);
 
         /// <summary>
         /// 热点受理类型明细

+ 390 - 136
src/Hotline.Application/Orders/OrderApplication.cs

@@ -54,12 +54,28 @@ using XF.Domain.Entities;
 using Hotline.Settings.TimeLimitDomain;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.SeedData;
+using Hotline.Share.Enums.Push;
+using Hotline.Push.Notifies;
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
+using Hotline.Share.Dtos.Push;
+using Mapster;
+using Hotline.Share.Tools;
+using Hotline.EventBus;
+using Hotline.Orders.Notifications;
+using Hotline.OrderTranspond;
 
 namespace Hotline.Application.Orders;
 
 public class OrderApplication : IOrderApplication, IScopeDependency
 {
 
+    private readonly IMediator _mediator;
+    private readonly IRepository<TranspondCityRawData> _transpondCityRawDataRepository;
+    private readonly Publisher _publisher;
+    private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
+    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+    private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
     private readonly IOrderDomainService _orderDomainService;
     private readonly IWorkflowDomainService _workflowDomainService;
     private readonly IOrderRepository _orderRepository;
@@ -86,9 +102,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<OrderScreen> _orderScreenRepository;
     private readonly IRepository<OrderSendBackAudit> _orderSendBackAuditRepository;
     private readonly ICalcExpireTime _expireTime;
+    private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
 
-    public OrderApplication(
+	public OrderApplication(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         IWorkflowDomainService workflowDomainService,
@@ -114,7 +131,14 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IRepository<OrderPublish> orderPublishRepository,
         IRepository<OrderScreen> orderScreenRepository,
         IRepository<OrderSendBackAudit> orderSendBackAuditRepository,
-        ICalcExpireTime expireTime)
+        ICalcExpireTime expireTime,
+        IMediator mediator,
+        IRepository<OrderVisitDetail> orderVisitedDetailRepository,
+        IOptionsSnapshot<AppConfiguration> appOptions,
+        IOptions<CityBaseConfiguration> cityBaseConfiguration,
+        ISystemDicDataCacheManager sysDicDataCacheManager,
+        Publisher publisher,
+        IRepository<TranspondCityRawData> transpondCityRawDataRepository)
     {
         _orderDomainService = orderDomainService;
         _workflowDomainService = workflowDomainService;
@@ -142,7 +166,14 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _orderPublishRepository = orderPublishRepository;
         _orderSendBackAuditRepository = orderSendBackAuditRepository;
         _expireTime = expireTime;
-    }
+        _mediator = mediator;
+        _orderVisitedDetailRepository = orderVisitedDetailRepository;
+        _appOptions = appOptions;
+        _sysDicDataCacheManager = sysDicDataCacheManager;
+        _publisher = publisher;
+        _transpondCityRawDataRepository = transpondCityRawDataRepository;
+        _cityBaseConfiguration = cityBaseConfiguration;
+	}
 
     /// <summary>
     /// 更新工单办理期满时间(延期调用,其他不调用)
@@ -233,14 +264,14 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 order.ProcessType is EProcessType.Zhiban)
             : 0;
         var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
-                    ? 
+                    ?
                     // _timeLimitDomainService.CalcWorkTime(
                     await _expireTime.CalcWorkTime(
                         order.CreationTime, now,
                     order.ProcessType is EProcessType.Zhiban)
                     : 0;
         var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
-            ? 
+            ?
             // _timeLimitDomainService.CalcWorkTime(
             await _expireTime.CalcWorkTime(
                 order.CenterToOrgTime.Value, now,
@@ -269,6 +300,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var IsCenter = _sessionContext.OrgIsCenter;
 
         return _orderRepository.Queryable(canView: !IsCenter).Includes(d => d.OrderDelays)
+            .Where(d => SqlFunc.Subqueryable<WorkflowStep>()
+                .Where(step => step.ExternalId == d.Id &&
+                               ((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))))
+                .Any())
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
@@ -445,6 +482,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             case ESource.ZHYB:
             case ESource.ZZPT:
             case ESource.WLLZ:
+            case ESource.YBS:
                 return ReceiveOrderFromOtherPlatformAsync(dto, dto.Files, current, cancellationToken);
             case ESource.Hotline:
             case ESource.HotlineImport:
@@ -481,15 +519,15 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var query = _orderRepository.Queryable()
             .Includes(order => order.OrderPublish)
             .LeftJoin<User>((order, user) => order.WaitForPublisherId == user.Id)
-            .Where((order, user) => order.FiledTime >= dto.StartTime && order.FiledTime <= dto.EndTime && !string.IsNullOrEmpty(order.WaitForPublisherId))
+            .Where((order, user) => order.CreationTime >= dto.StartTime && order.CreationTime <= dto.EndTime && !string.IsNullOrEmpty(order.WaitForPublisherId))
             .WhereIF(dto.ProcessType != null, (order, user) => order.ProcessType == dto.ProcessType)
             .GroupBy((order, user) => new { order.WaitForPublisherId, user.Name })
             .Select((order, user) => new PublishedOrderStatisticsDto
             {
                 Id = order.WaitForPublisherId,
                 Name = user.Name,
-                TotalCount = SqlFunc.AggregateCount(order.Id),
-                WaitCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish == null, 1, 0)),
+                //TotalCount = SqlFunc.AggregateCount(order.Id),
+                WaitCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.Status == EOrderStatus.Filed, 1, 0)),
                 PublicCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish.PublishState == true, 1, 0)),
                 PrivateCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish.PublishState == false, 1, 0))
             });
@@ -516,19 +554,20 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <exception cref="UserFriendlyException"></exception>
     public async Task<(int, IList<PublishedOrderStatisticsDto>)> QueryPublishedOrderDepartmentAsync(QueryOrderPublishStatisticsAllDto dto, bool isFull)
     {
+
         var total = 0;
         var items = new List<PublishedOrderStatisticsDto>();
 
         var query = _orderRepository.Queryable()
            .Includes(order => order.OrderPublish)
-           .Where(order => order.FiledTime >= dto.StartTime && order.FiledTime <= dto.EndTime && order.ActualHandleOrgName != null)
+           .Where(order => order.CreationTime >= dto.StartTime && order.CreationTime <= dto.EndTime && order.ActualHandleOrgName != null)
            .GroupBy(order => new { Name = order.ActualHandleOrgName, PublishTime = order.CreationTime.ToString("YYYY-MM-DD") })
            .Select(order => new PublishedOrderStatisticsDto
            {
                Name = order.ActualHandleOrgName,
                PublishTime = order.CreationTime.ToString("YYYY-MM-DD"),
-               TotalCount = SqlFunc.AggregateCount(order.Id),
-               // WaitCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish == null, 1, 0)),
+               // TotalCount = SqlFunc.AggregateCount(order.Id),
+               WaitCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.Status == EOrderStatus.Filed, 1, 0)),
                PublicCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish.PublishState == true, 1, 0)),
                PrivateCount = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderPublish.PublishState == false, 1, 0))
            });
@@ -541,7 +580,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize);
         }
 
-        items.ForEach(m => m.WaitCount = m.TotalCount - m.PublicCount - m.PrivateCount);
         return (total, items);
     }
 
@@ -630,6 +668,248 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         }
     }
 
+    /// <summary>
+    /// 保存工单办理时页面填写的数据
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public async Task<Order> SaveOrderWorkflowInfo(NextWorkflowDto dto, CancellationToken cancellationToken)
+    {
+        var order = await _orderRepository.Queryable()
+            .FirstAsync(d => d.WorkflowId == dto.WorkflowId, cancellationToken)
+            ?? throw UserFriendlyException.SameMessage("无效工单编号");
+        if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == order.Id && x.State == ESendBackAuditState.Apply,
+                cancellationToken))
+        {
+            throw UserFriendlyException.SameMessage("该工单存在正在审核中的退回,不能办理");
+        }
+
+        ExpiredTimeWithConfig? expiredTimeConfig = null;
+        if (dto.NextHandlers.Any(d => d.Key == "001171" || d.Key == "001178"))
+        {
+            var timeResult = await _expireTime.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 45, 80, 50);
+            expiredTimeConfig = new ExpiredTimeWithConfig
+            {
+                Count = 45,
+                TimeType = ETimeType.WorkDay,
+                TimeText = "45个工作日",
+                ExpiredTime = timeResult.EndTime,
+                NearlyExpiredTime = timeResult.NearlyExpiredTime,
+                NearlyExpiredTimeOne = timeResult.NearlyExpiredTimeOne
+            };
+            var canUpdateOrderSender = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CanUpdateOrderSender).SettingValue[0]);
+            order.CenterToOrg(
+                expiredTimeConfig.TimeText, expiredTimeConfig.Count,
+                expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime,
+                expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne, dto.Opinion,
+                _sessionContext.RequiredUserId, _sessionContext.UserName,
+                canUpdateOrderSender);
+            //TODO发送短信即将超期
+            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+        }
+        else if (dto.FlowDirection is EFlowDirection.CenterToOrg)
+        {
+            expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToOrg, order.Adapt<OrderTimeClacInfo>());
+            var canUpdateOrderSender = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CanUpdateOrderSender).SettingValue[0]);
+            order.CenterToOrg(
+                expiredTimeConfig.TimeText, expiredTimeConfig.Count,
+                expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime,
+                expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne, dto.Opinion,
+                _sessionContext.RequiredUserId, _sessionContext.UserName,
+                canUpdateOrderSender);
+            //TODO发送短信即将超期
+            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+
+        }
+        else if (dto.FlowDirection is EFlowDirection.CenterToCenter)
+        {
+            if (_appOptions.Value.IsZiGong == false)
+            {
+                expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToCenter, order.Adapt<OrderTimeClacInfo>());
+                order.CenterToCenter(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
+                    expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne);
+                //TODO发送短信即将超期
+                //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+            }
+        }
+
+        if (expiredTimeConfig is not null)
+            _mapper.Map(expiredTimeConfig, order);
+
+        if (dto.LeaderSMSKey != null)
+        {
+            var dic = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LeaderSMS).First(m => m.Id == dto.LeaderSMSKey);
+            _capPublisher.Publish(EventNames.HotlineLeaderSMS, new PublishLeaderSMSDto(order.Id, dic.DicDataName, dic.DicDataValue));
+        }
+
+        _mapper.Map(dto, order);
+        await _orderRepository.UpdateAsync(order, cancellationToken);
+
+        if (_appOptions.Value.IsZiGong && dto.Transpond.HasValue && dto.Transpond.Value == true)
+        {
+            var count = await _transpondCityRawDataRepository.Queryable()
+                .Where(m => m.OrderCode == order.No && m.CityName == order.TranspondCityName
+                && m.Direction == ETranspondDirection.Out)
+                .CountAsync();
+            //处理市州互转
+            if (count == 0)
+                await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll, cancellationToken);
+        }
+        return order;
+    }
+
+    /// <summary>
+    /// 回访保存
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    public async Task SaveOrderVisit(VisitDto dto, CancellationToken cancellationToken)
+    {
+        var visit = await _orderVisitRepository.Queryable()
+            .Includes(d => d.Order)
+            .Includes(d => d.OrderVisitDetails)
+            .FirstAsync(d => d.Id == dto.Id, cancellationToken);
+        if (visit is null)
+            throw UserFriendlyException.SameMessage("未知回访信息");
+
+        if (_appOptions.Value.IsYiBin && visit.VisitState == EVisitState.Visited)
+            throw UserFriendlyException.SameMessage("已回访,不能重复回访");
+
+        var first = dto.VisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
+
+        visit.IsPutThrough = dto.IsPutThrough;
+        visit.AgainState = dto.IsAgain ? EAgainState.NeedAgain : EAgainState.NoAgain;
+        visit.EmployeeId = _sessionContext.UserId;
+        visit.CallId = dto.CallId;
+        if (first != null)
+        {
+            visit.NowEvaluate = first.OrgProcessingResults;
+        }
+
+        visit.VisitState = Share.Enums.Order.EVisitState.Visited;
+        visit.VisitTime = DateTime.Now;
+        if (!string.IsNullOrEmpty(visit.CallId))
+        {
+            visit.VisitType = EVisitType.CallVisit;
+        }
+
+        if (visit.VisitType is null)
+        {
+            visit.VisitType = EVisitType.ArtificialVisit;
+        }
+
+        if (first != null)
+        {
+            visit.Order.Visited(first.OrgProcessingResults.Key, first.OrgProcessingResults.Value);
+        }
+
+        visit.OrgJudge = dto.OrgJudge;
+        visit.SeatJudge = dto.SeatJudge;
+
+        if (visit.OrgJudge == true || visit.SeatJudge == true)
+        {
+            visit.JudgeState = EJudgeState.Judging;
+        }
+
+        for (int i = 0;i < visit.OrderVisitDetails.Count;i++)
+        {
+            var detail = visit.OrderVisitDetails[i];
+            var detaildto = dto.VisitDetails.FirstOrDefault(x => x.Id == detail.Id);
+            if (detaildto != null)
+            {
+                if (visit.Order.SourceChannelCode != "RGDH" && detaildto.VisitTarget == EVisitTarget.Seat)
+                {
+                    detaildto.SeatEvaluate = ESeatEvaluate.DefaultSatisfied;
+                }
+
+                _mapper.Map(detaildto, visit.OrderVisitDetails[i]);
+            }
+        }
+
+        await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+        await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
+        await _orderRepository.UpdateAsync(visit.Order, cancellationToken);
+        var orderDto = _mapper.Map<OrderDto>(visit.Order);
+        if (first != null)
+        {
+            //推省上
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
+                new PublishVisitDto()
+                {
+                    Order = orderDto,
+                    No = visit.No,
+                    VisitType = visit.VisitType,
+                    VisitName = visit.CreatorName,
+                    VisitTime = visit.VisitTime,
+                    VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
+                    AreaCode = visit.Order.AreaCode!,
+                    SubjectResultSatifyCode = first.OrgProcessingResults.Key,
+                    FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
+                    ClientGuid = ""
+                }, cancellationToken: cancellationToken);
+
+            //推门户
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
+            {
+                Id = visit.Id,
+                Order = orderDto,
+                OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(visit.OrderVisitDetails),
+                VisitName = _sessionContext.UserName,
+                VisitTime = visit.VisitTime,
+                VisitType = visit.VisitType,
+                VisitState = visit.VisitState,
+                PublishTime = visit.PublishTime,
+            }, cancellationToken: cancellationToken);
+        }
+
+        if (first != null)
+        {
+            //写入质检
+            await _qualityApplication.AddQualityAsync(EQualitySource.Visit, visit.Order.Id, visit.Id,
+                cancellationToken);
+        }
+    }
+
+    /// <summary>
+    /// 发送回访短信
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    /// <exception cref="NotImplementedException"></exception>
+    public async Task VisitPushSMSAsync(VisitSmsInDto dto, CancellationToken cancellationToken)
+    {
+        var orderVisitList = await _orderVisitRepository.Queryable()
+            .Includes(d => d.Order)
+            .Where(d => dto.Ids.Contains(d.Id) && d.VisitState == EVisitState.WaitForVisit)
+            .Select(d => new { d.Id, d.Order.SourceChannelCode, d.Order.Contact, d.Order.Password, d.No, d.OrderId, d.Order.Title, d.Order.FromName })
+            .ToListAsync(cancellationToken);
+
+        foreach (var item in orderVisitList)
+        {
+            var code = "1013";
+            if (item.SourceChannelCode == "ZGSSP") code = "1012";
+            var messageDto = new Share.Dtos.Push.MessageDto
+            {
+                PushBusiness = EPushBusiness.VisitSms,
+                ExternalId = item.Id,
+                OrderId = item.OrderId,
+                PushPlatform = EPushPlatform.Sms,
+                Remark = item.Title,
+                Name = item.FromName,
+                TemplateCode = code,
+                Params = new List<string>() { item.No, item.Password },
+                TelNumber = item.Contact,
+            };
+            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+            await _orderVisitRepository.Updateable()
+                .Where(m => m.Id == item.Id)
+                .SetColumns(m => m.VisitState == EVisitState.SMSVisiting)
+                .SetColumns(m => m.VisitType == EVisitType.SmsVisit)
+                .ExecuteCommandAsync();
+        }
+    }
+
     public ISugarQueryable<Order> QueryOrders(QueryOrderDto dto)
     {
         var isCenter = _sessionContext.OrgIsCenter;
@@ -648,31 +928,34 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 
         return query
             .Includes(x => x.OrderScreens)
-            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) //标题
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
             .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType)//受理类型
-                                                                                                    //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
+            //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel)
             //.WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
             //.WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone == dto.TransferPhone!) //转接号码
-                                                                                                           //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
-                                                                                                           //.WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
-            .WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId)//接办部门
+            //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
+            //.WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
+            //.WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId)//接办部门
+            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName),d=>d.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName),d=>d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
             .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
             .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
             .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
-                                                                                               //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
+            //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
             .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
             .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo!) //联系电话
-            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
+            //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
+            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), x => x.OrderPushTypes.Any(opt => opt.PushTypeCode == dto.PushTypeCode))//推送分类
             .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
             .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
-                                                                                            //.WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
+            //.WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
             .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)//工单状态
-                                                                      //.WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
+            //.WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
             .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName == dto.ActualHandlerName) //接办人
             .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
             .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
@@ -683,8 +966,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
             .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
             .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName == dto.FromName) //来电人姓名
-                                                                                           //.WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
-            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode)//区域
+            //.WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
+            //.WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode)//区域
+            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode) && dto.AreaCode.LastIndexOf("00")>0,d=>d.AreaCode.StartsWith(SqlFunc.Substring(dto.AreaCode,0,4)))
+            .WhereIF(!string.IsNullOrEmpty(dto.AreaCode) && dto.AreaCode.LastIndexOf("00")<=0,d=>d.AreaCode.StartsWith(dto.AreaCode))
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.Source == ESource.ProvinceStraight)
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.Source != ESource.ProvinceStraight)
             .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), d => SqlFunc.JsonArrayAny(d.Sensitive, dto.SensitiveWord))
@@ -706,8 +991,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order, WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto)
     {
-        if (dto.EndTime.HasValue)
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var IsCenter = _sessionContext.OrgIsCenter;
         return _orderRepository.Queryable()
             .LeftJoin<WorkflowStep>((x, ws) => x.Id == ws.ExternalId)
@@ -729,13 +1012,11 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order> QueryOrderSource(QueryOrderSourceRequest dto)
     {
-        if (dto.EndTime.HasValue)
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         return _orderRepository.Queryable()
             .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
-                .WhereIF(dto.TypeId != null && dto.TypeId == 1, x => x.IdentityType == EIdentityType.Citizen)
-                .WhereIF(dto.TypeId != null && dto.TypeId == 2, x => x.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(dto.TypeId != null && dto.TypeId == 1, x => x.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeId != null && dto.TypeId == 2, x => x.IdentityType == EIdentityType.Enterprise)
             .Where(d => d.SourceChannel != null && d.SourceChannel != "");
     }
 
@@ -841,8 +1122,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
 	public ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListDetailRequest dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
         var quer = _orderRepository.Queryable()
             .InnerJoin<SystemOrganize>((x, so) => x.ActualHandleOrgCode == so.Id && so.Level == 1)
             .Where((x, so) => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
@@ -882,7 +1161,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListAllDetailRequest dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         bool IsCenter = _sessionContext.OrgIsCenter;
 
         var quer = _orderRepository.Queryable()
@@ -921,11 +1199,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<OrderReTransactVo> OrderReTransact(QueryOrderReTransactRequest dto)
     {
-
         return _orderSpecialDetailRepository.Queryable()
             .Includes(x => x.OrderSpecial)
             .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
-            .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
+            .Where(x => x.OrderSpecial.SpecialType == ESpecialType.ReTransact)
             .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
             .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime)
             .GroupBy(x => new { Time = x.OrderSpecial.CreationTime.ToString("yyyy-MM-dd"), x.OrgId, x.OrgName })
@@ -948,13 +1225,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     {
         if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
             throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         return _orderSpecialDetailRepository.Queryable()
             .Includes(x => x.OrderSpecial, s => s.Order)
             .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.OrgName.Contains(dto.OrgName!))
             .WhereIF(!string.IsNullOrEmpty(dto.ErrorName), x => x.ErrorName.Contains(dto.ErrorName!))
             .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderSpecial!.Order!.No!.Contains(dto.No!))
-            .Where(x => x.OrderSpecial.ESpecialType == ESpecialType.ReTransact)
+            .Where(x => x.OrderSpecial.SpecialType == ESpecialType.ReTransact)
             .Where(x => x.OrderSpecial.CreationTime >= dto.StartTime)
             .Where(x => x.OrderSpecial.CreationTime <= dto.EndTime);
     }
@@ -964,8 +1240,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto)
     {
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         bool IsCenter = _sessionContext.OrgIsCenter;
 
         var list = _orderVisitDetailRepository.Queryable()
@@ -1059,8 +1333,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto)
     {
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         bool IsCenter = _sessionContext.OrgIsCenter;
 
         var list = await _systemOrganizeRepository.Queryable().Where(x => x.Id.StartsWith(dto.OrgCode))
@@ -1108,7 +1380,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         return list;
     }
 
-    
+
 
     /// <summary>
     /// 热点区域统计
@@ -1117,7 +1389,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<(List<SystemArea> area, object items)> HotspotAndAreaStatistics(HotspotAndAreaStatisticsReq dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         var areaList = _systemAreaRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == 6 && x.Id != "510000").OrderBy(x => x.Id).MergeTable();
 
         var endIndex = (2 * dto.HotspotLevel).ToString();
@@ -1186,7 +1457,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<DataTable> HotspotAndAreaStatisticsExport(HotspotAndAreaStatisticsReq dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         var areaList = _systemAreaRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == 6 && x.Id != "510000").OrderBy(x => x.Id).MergeTable();
 
         var endIndex = (2 * dto.HotspotLevel).ToString();
@@ -1407,8 +1677,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<List<VisitAndHotspotSatisfactionStatisticsDto>> VisitAndHotspotSatisfactionStatistics(VisitAndHotspotPagedKeywordRequest dto)
     {
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         bool IsCenter = _sessionContext.OrgIsCenter;
 
         var list = _orderVisitDetailRepository.Queryable()
@@ -1476,7 +1744,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<OrderVisitDetail> VisitAndHotspotSatisfactionDetail(VisitAndHotspotPagedKeywordRequest dto)
     {
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         bool IsCenter = _sessionContext.OrgIsCenter;
         var key = string.Empty;
         if (!string.IsNullOrEmpty(dto.TitleCode))
@@ -1524,8 +1791,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     {
         if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         var query = _orderRepository.Queryable(false, false, false)
             .WhereIF(dto.StartTime.HasValue, it => it.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, it => it.CreationTime <= dto.EndTime)
@@ -1582,7 +1847,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<(List<SystemDicData> acceptTypes, object items)> HotspotAndAcceptTypeStatistics(HotspotAndAcceptTypeStatisticsReq dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         var dicList = _systemDicDataRepository.Queryable().Where(x => x.DicTypeCode == "AcceptType").OrderBy(x => x.Sort).MergeTable();
         var endIndex = (2 * dto.HotspotLevel).ToString();
         var hotspotList = _hotspotRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == int.Parse(endIndex))
@@ -1644,7 +1908,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<DataTable> HotspotAndAcceptTypeStatisticsExport(HotspotAndAcceptTypeStatisticsReq dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         var dicList = _systemDicDataRepository.Queryable().Where(x => x.DicTypeCode == "AcceptType").OrderBy(x => x.Sort).MergeTable();
         var endIndex = (2 * dto.HotspotLevel).ToString();
         var hotspotList = _hotspotRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == int.Parse(endIndex))
@@ -1706,7 +1969,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order> HotspotAndAcceptTypeStatisticsDetail(HotspotAndAcceptTypeStatisticsDetailReq dto)
     {
-        dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
         var query = _orderRepository.Queryable()
             .Where(x => x.HotspotId.StartsWith(dto.HotspotId) && x.CreationTime >= dto.StartTime && x.CreationTime < dto.EndTime)
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.AcceptTypeCode.StartsWith(dto.AcceptTypeCode))
@@ -1720,8 +1982,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
 	public ISugarQueryable<OrderScreenApplyVo> OrderScreenApply(OrderScreenApplyPagedRequest dto)
     {
-        if (dto.EndTime.HasValue)
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var query = _orderScreenRepository.Queryable()
             .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
             .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), x => x.CreatorName == dto.ApplyUserName)
@@ -1743,22 +2003,20 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<OrderScreenAuditVo> OrderScreenAudit(OrderScreenAuditPagedRequest dto)
     {
-	    if (dto.EndTime.HasValue)
-		    dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-	    var query = _workflowTraceRepository.Queryable()
-		    .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.HandleTime >= dto.StartTime && x.HandleTime <= dto.EndTime)
-		    .WhereIF(!string.IsNullOrEmpty(dto.AuditUserName), x => x.HandlerName == dto.AuditUserName)
-            .Where(x=> x.HandlerName != null && x.HandlerName != "" )
-            .WhereIF(dto.AuditType is 1,x=>x.Name == "班长审批")
-		    .WhereIF(dto.AuditType is 2, x => x.Name == "中心领导")
-			.GroupBy(x => new { x.HandlerName })
-		    .Select(x => new OrderScreenAuditVo
-			{
-			  AuditName = x.HandlerName,
-              AuditNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType  ==  EWorkflowTraceType.Normal, 1, 0)),
-              AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF( x.TraceType == EWorkflowTraceType.Previous , 1, 0)),
-			});
-	    return query;
+        var query = _workflowTraceRepository.Queryable()
+            .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.HandleTime >= dto.StartTime && x.HandleTime <= dto.EndTime)
+            .WhereIF(!string.IsNullOrEmpty(dto.AuditUserName), x => x.HandlerName == dto.AuditUserName)
+            .Where(x => x.HandlerName != null && x.HandlerName != "")
+            .WhereIF(dto.AuditType is 1, x => x.Name == "班长审批")
+            .WhereIF(dto.AuditType is 2, x => x.Name == "中心领导")
+            .GroupBy(x => new { x.HandlerName })
+            .Select(x => new OrderScreenAuditVo
+            {
+                AuditName = x.HandlerName,
+                AuditNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType == EWorkflowTraceType.Normal, 1, 0)),
+                AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType == EWorkflowTraceType.Previous, 1, 0)),
+            });
+        return query;
     }
 
     /// <summary>
@@ -1768,8 +2026,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<OrderCenterAcceptVo> OrderCenterAccept(OrderCenterAcceptPagedRequest dto)
     {
-        if (dto.EndTime.HasValue)
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var sendBack = _orderSendBackAuditRepository.Queryable()
             .Where(x => x.State == ESendBackAuditState.End)
             .GroupBy(x => x.OrderId).Select(x => new { OrderId = x.OrderId });
@@ -1789,7 +2045,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 InvalidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType == "无效", 1, 0)),
                 HandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status >= EOrderStatus.Filed, 1, 0)),
                 NoHandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EOrderStatus.Filed, 1, 0)),
-                BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null &&  s.OrderId != "", 1, 0)),
+                BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null && s.OrderId != "", 1, 0)),
                 DutyDeskNum = SqlFunc.AggregateDistinctCount(d.AcceptorId)
             });
         return query;
@@ -1801,30 +2057,28 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<OrderCenterAcceptUserVo> OrderCenterAcceptUser(OrderCenterAcceptPagedRequest dto)
     {
-        if (dto.EndTime.HasValue)
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var sendBack = _orderSendBackAuditRepository.Queryable()
             .Where(x => x.State == ESendBackAuditState.End)
             .GroupBy(x => x.OrderId).Select(x => new { OrderId = x.OrderId });
 
-	    var query = _orderRepository.Queryable()
-		    .LeftJoin(sendBack, (d, s) => d.Id == s.OrderId)
-		    .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime)
-		    .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, d => d.IdentityType == EIdentityType.Citizen)
-		    .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, d => d.IdentityType == EIdentityType.Enterprise)
-		    .GroupBy(d => d.AcceptorName)
-		    .Select((d, s) => new OrderCenterAcceptUserVo
-			{
-			    AcceptUserName = d.AcceptorName,
-			    AcceptNum = SqlFunc.AggregateCount(1),
-			    ValidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType != "无效", 1, 0)),
-			    RepetitionNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.DuplicateIds == null || SqlFunc.JsonArrayLength(d.DuplicateIds) > 0, 1, 0)),
-			    InvalidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType == "无效", 1, 0)),
-			    HandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status >= EOrderStatus.Filed, 1, 0)),
-			    NoHandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EOrderStatus.Filed, 1, 0)),
-			    BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null && s.OrderId != "", 1, 0))
-		    });
-	    return query;
+        var query = _orderRepository.Queryable()
+            .LeftJoin(sendBack, (d, s) => d.Id == s.OrderId)
+            .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, d => d.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, d => d.IdentityType == EIdentityType.Enterprise)
+            .GroupBy(d => d.AcceptorName)
+            .Select((d, s) => new OrderCenterAcceptUserVo
+            {
+                AcceptUserName = d.AcceptorName,
+                AcceptNum = SqlFunc.AggregateCount(1),
+                ValidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType != "无效", 1, 0)),
+                RepetitionNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.DuplicateIds == null || SqlFunc.JsonArrayLength(d.DuplicateIds) > 0, 1, 0)),
+                InvalidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType == "无效", 1, 0)),
+                HandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status >= EOrderStatus.Filed, 1, 0)),
+                NoHandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EOrderStatus.Filed, 1, 0)),
+                BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null && s.OrderId != "", 1, 0))
+            });
+        return query;
     }
 
 
@@ -1916,7 +2170,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             //特提(撤回至发起)
             if (!string.IsNullOrEmpty(order.WorkflowId))
             {
-                current = SessionContextCreator.CreateSessionContext("province");
+                current = SessionContextCreator.CreateSessionContext("province",_cityBaseConfiguration.Value);
                 await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, "省工单重派", current, cancellationToken);
             }
         }
@@ -1948,32 +2202,32 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 NoSendOrderNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.HandlerId == null || x.HandlerId == "", 1, 0)),
             }).ToListAsync();
 
-            var items2 = await _workflowTraceRepository.Queryable()
-                .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
-                //.LeftJoin<WorkflowStepHandler>((x, w, wfsh) => x.StepId == wfsh.WorkflowStepId && wfsh.IsActualHandler == true)
-                .InnerJoin<SchedulingUser>((x, w, su) => x.HandlerId == su.UserId)
-                .Where((x, w, su) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.BusinessType == EBusinessType.Send && x.Status == EWorkflowStepStatus.Handled 
-                && !string.IsNullOrEmpty(x.NextMainHandler) && x.NextMainHandler != OrgSeedData.CenterId)
-                .Where((x, w, su) => x.CreationTime >= dto.StartTime.Value)
-                .Where((x, w, su) => x.CreationTime <= dto.EndTime.Value)
-                .GroupBy((x, w, su) => x.WorkflowId)
-                .Having((x, w, su) => SqlFunc.AggregateCount(x.WorkflowId) > 1)
-                .Select((x, w, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(x.CreationTime) })
-                .MergeTable()
-                .LeftJoin<WorkflowTrace>((a, wt) => a.Id == wt.WorkflowId)
-                .LeftJoin<Workflow>((a, wt, wf) => wt.WorkflowId == wf.Id)
-                //.LeftJoin<WorkflowStepHandler>((a, wt, wf, wsh) => wt.StepId == wsh.WorkflowStepId && wsh.CreationTime == a.CreationTime)
-                .InnerJoin<SchedulingUser>((a, wt, wf, su) => wt.HandlerId == su.UserId)
-                .WhereIF(!string.IsNullOrEmpty(dto.UserName), ((a, wt, wf, su) => su.UserName == dto.UserName))
-                .GroupBy((a, wt, wf, su) => new { su.UserId, su.UserName })
-                .Select((a, wt, wf, su) => new BiOrderSendVo
-                {
-                    UserId = su.UserId,
-                    UserName = su.UserName,
-                    SendOrderNum = 0,
-                    NoSendOrderNum = 0,
-                    ReSendOrderNum = SqlFunc.AggregateDistinctCount(wf.ExternalId),
-                }).ToListAsync();
+        var items2 = await _workflowTraceRepository.Queryable()
+            .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
+            //.LeftJoin<WorkflowStepHandler>((x, w, wfsh) => x.StepId == wfsh.WorkflowStepId && wfsh.IsActualHandler == true)
+            .InnerJoin<SchedulingUser>((x, w, su) => x.HandlerId == su.UserId)
+            .Where((x, w, su) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.BusinessType == EBusinessType.Send && x.Status == EWorkflowStepStatus.Handled
+            && !string.IsNullOrEmpty(x.NextMainHandler) && x.NextMainHandler != OrgSeedData.CenterId)
+            .Where((x, w, su) => x.CreationTime >= dto.StartTime.Value)
+            .Where((x, w, su) => x.CreationTime <= dto.EndTime.Value)
+            .GroupBy((x, w, su) => x.WorkflowId)
+            .Having((x, w, su) => SqlFunc.AggregateCount(x.WorkflowId) > 1)
+            .Select((x, w, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(x.CreationTime) })
+            .MergeTable()
+            .LeftJoin<WorkflowTrace>((a, wt) => a.Id == wt.WorkflowId)
+            .LeftJoin<Workflow>((a, wt, wf) => wt.WorkflowId == wf.Id)
+            //.LeftJoin<WorkflowStepHandler>((a, wt, wf, wsh) => wt.StepId == wsh.WorkflowStepId && wsh.CreationTime == a.CreationTime)
+            .InnerJoin<SchedulingUser>((a, wt, wf, su) => wt.HandlerId == su.UserId)
+            .WhereIF(!string.IsNullOrEmpty(dto.UserName), ((a, wt, wf, su) => su.UserName == dto.UserName))
+            .GroupBy((a, wt, wf, su) => new { su.UserId, su.UserName })
+            .Select((a, wt, wf, su) => new BiOrderSendVo
+            {
+                UserId = su.UserId,
+                UserName = su.UserName,
+                SendOrderNum = 0,
+                NoSendOrderNum = 0,
+                ReSendOrderNum = SqlFunc.AggregateDistinctCount(wf.ExternalId),
+            }).ToListAsync();
 
         var res = (from t1 in items
                    join t2 in items2 on t1.UserId equals t2.UserId into t1_t2
@@ -2007,23 +2261,23 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         {
             dto.EndTime = dto.EndTime?.AddDays(1).AddSeconds(-1);
         }
-       return _orderVisitRepository.Queryable()
-            .WhereIF(dto.StartTime.HasValue, x => x.VisitTime >= dto.StartTime)
-            .WhereIF(dto.EndTime.HasValue, x => x.VisitTime <= dto.EndTime)
-            .GroupBy(x => new { EmployeeId = x.EmployeeId, Name = x.Employee.Name })
-            .Select(x => new OrderVisitJudeStatisticsRep()
-            {
-                EmpId = x.EmployeeId,
-                EmpName = x.Employee.Name,
-                OrgJudeCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue, 1, 0)), //部门扭转总件
-                OrgJudeApprovalingCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.JudgeState == EJudgeState.Judging, 1, 0)),
-                OrgJudeSuccessCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.JudgeState == EJudgeState.Agreed, 1, 0)),
-                OrgJudeFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.JudgeState == EJudgeState.UnAgreed, 1, 0)),
-                SeatJudeCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue, 1, 0)),
-                SeatJudeApprovalingCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.JudgeState == EJudgeState.Judging, 1, 0)),
-                SeatJudeSuccessCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.JudgeState == EJudgeState.Agreed, 1, 0)),
-                SeatJudeFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.JudgeState == EJudgeState.UnAgreed, 1, 0))
-            });
+        return _orderVisitRepository.Queryable()
+             .WhereIF(dto.StartTime.HasValue, x => x.VisitTime >= dto.StartTime)
+             .WhereIF(dto.EndTime.HasValue, x => x.VisitTime <= dto.EndTime)
+             .GroupBy(x => new { EmployeeId = x.EmployeeId, Name = x.Employee.Name })
+             .Select(x => new OrderVisitJudeStatisticsRep()
+             {
+                 EmpId = x.EmployeeId,
+                 EmpName = x.Employee.Name,
+                 OrgJudeCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.OrgJudge == true && x.JudgeState != null, 1, 0)), //部门扭转总件
+                 OrgJudeApprovalingCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.OrgJudge == true && x.JudgeState == EJudgeState.Judging, 1, 0)),
+                 OrgJudeSuccessCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.OrgJudge == true && x.JudgeState == EJudgeState.Agreed, 1, 0)),
+                 OrgJudeFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.OrgJudge.HasValue && x.OrgJudge == true && x.JudgeState == EJudgeState.UnAgreed, 1, 0)),
+                 SeatJudeCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.SeatJudge == true && x.JudgeState != null, 1, 0)),
+                 SeatJudeApprovalingCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.SeatJudge == true && x.JudgeState == EJudgeState.Judging, 1, 0)),
+                 SeatJudeSuccessCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.SeatJudge == true && x.JudgeState == EJudgeState.Agreed, 1, 0)),
+                 SeatJudeFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.SeatJudge.HasValue && x.SeatJudge == true && x.JudgeState == EJudgeState.UnAgreed, 1, 0))
+             });
     }
 
     #endregion

+ 1 - 1
src/Hotline.Application/Orders/OrderScreenHandler/OrderScreenEndWorkflowHandler.cs

@@ -113,10 +113,10 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
 				}
 				else
 				{
-					await _orderRepository.OrderScreenRevisionVisit(screen.VisitId, true, cancellationToken);
 					screen.Status = EScreenStatus.Refuse;
 					screen.ReplyContent = workflow.ActualOpinion;
 				}
+				await _orderRepository.OrderScreenRevisionVisit(screen.VisitId, true, cancellationToken);
 				screen.NewestAuditTime = DateTime.Now;
 				await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
 				OrderScreenDetail detail = new OrderScreenDetail

+ 3 - 11
src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs

@@ -158,9 +158,9 @@ namespace Hotline.Application.Orders
                 var order = await _orderRepository.GetAsync(x => x.Id == model.OrderId, cancellationToken);
                 if (string.IsNullOrEmpty(order.WorkflowId))
                     throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程信息!");
-                var step = order.CounterSignType == ECounterSignType.Department ?
-                    await _workflowDomainService.FindTopHandleStepAsync(order.WorkflowId, cancellationToken) : await _workflowDomainService.FindLastHandleStepAsync(order.WorkflowId, model.ApplyOrgId, cancellationToken);
-                if (step == null)
+                string orgId = order.CounterSignType == ECounterSignType.Department ? model.ApplyOrgId.Substring(0, 6) : model.ApplyOrgId;
+				var step = await _workflowDomainService.FindLastHandleStepAsync(order.WorkflowId, orgId, cancellationToken);
+				if (step == null)
                     throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程节点!");
                 var recall = new RecallDto
                 {
@@ -322,8 +322,6 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         public ISugarQueryable<SecondaryHandlingVo> SecondaryHandlingReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
         {
-            if (dto.EndTime.HasValue)
-                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             return _orderSecondaryHandlingRepository.Queryable()
                 .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
                 .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
@@ -347,8 +345,6 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
         {
-            if (dto.EndTime.HasValue)
-                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             return _orderSecondaryHandlingRepository.Queryable()
                 .Includes(x => x.Order)
                 .Includes(x => x.Visit)
@@ -368,8 +364,6 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         public ISugarQueryable<SecondaryHandlingSatisfactionVo> SecondaryHandlingSatisfactionReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
         {
-            if (dto.EndTime.HasValue)
-                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             return _orderSecondaryHandlingRepository.Queryable()
                 .Includes(x => x.Order)
                 .Includes(x => x.Visit)
@@ -405,8 +399,6 @@ namespace Hotline.Application.Orders
         public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingSatisfactionDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
         {
             var key = string.Empty;
-            if (dto.EndTime.HasValue)
-                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             if (!string.IsNullOrEmpty(dto.Header))
             {
                 switch (dto.Header)

+ 0 - 1
src/Hotline.Application/StatisticalReport/CallReportApplication.cs

@@ -92,7 +92,6 @@ namespace Hotline.Application.StatisticalReport
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
                 throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
             return _trCallRecordRepository.Queryable()
                      .Includes(p => p.Order)

+ 0 - 14
src/Hotline.Application/StatisticalReport/OrderReportApplication.cs

@@ -106,7 +106,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public async Task<List<DepartmentalProcessingStatisticsDataDto>> DepartmentalProcessingStatisticsNew(DepartmentalProcessingStatisticsRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var IsCenter = _sessionContext.OrgIsCenter;
 
             //信件总量:信件总量=已办件数+在办件数+会签已办+会签待办
@@ -140,8 +139,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public async Task<List<DepartmentalProcessingStatisticsDataDto>> DepartmentalProcessingChildStatisticsNew(DepartmentalProcessingStatisticsRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             //信件总量:信件总量=已办件数+在办件数,工单需去重
             //已办件数:该部门已办理完成的工单总数(含参与会签的工单),若工单被部门多次办理,只统计一次
             //在办件数:该部门还未办理的工单数(若是一级部门,需包含中心向该部门发起回签的工单)。(特殊说明:部门或者中心发起了会签,会签中还未汇总,应算发起会签部门的在办里面)
@@ -177,8 +174,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public ISugarQueryable<SelectOrderId> GetDepartmentalProcessingStatisticsListNew(DepartmentalProcessingStatisticsRequest dto, CancellationToken cancellationToken)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             RefAsync<int> total = 0;
             ISugarQueryable<SelectOrderId> query = null;
             switch (dto.StatisticsType)
@@ -549,7 +544,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public ISugarQueryable<DepartmentalProcessingStatisticsDataDto> DepartmentalProcessingStatistics(DepartmentalProcessingStatisticsRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var IsCenter = _sessionContext.OrgIsCenter;
 
             //工单   已办=归完档的工单数+会签已办数量
@@ -1439,8 +1433,6 @@ namespace Hotline.Application.StatisticalReport
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             var IsCenter = _sessionContext.OrgIsCenter;
 
             return _orderDelayRepository.Queryable()
@@ -1476,8 +1468,6 @@ namespace Hotline.Application.StatisticalReport
         {
             if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
 
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             return _orderDelayRepository.Queryable()
                  .Includes(x => x.Order)
                  .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
@@ -1500,8 +1490,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public ISugarQueryable<DepartmentAcceptanceTypeStatisticsDto> DepartmentAcceptanceTypeStatistics(DepartmentKeyWordRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             var IsCenter = _sessionContext.OrgIsCenter;
 
             var orderData = _orderRepository.Queryable()
@@ -1576,7 +1564,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public ISugarQueryable<Order> DepartmentAcceptanceTypeOrderList(DepartmentKeyWordRequest dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             return _orderRepository.Queryable()
                  .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime && p.Status >= EOrderStatus.Filed)
                  .WhereIF(!string.IsNullOrEmpty(dto.OrgCode) && dto.OrgCode == "001", p => p.ActualHandleOrgCode == dto.OrgCode)
@@ -1600,7 +1587,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public ISugarQueryable<AcceptTypeStatisticsDto> AcceptTypeStatistics(AcceptTypeStatisticsReq dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var query = _orderRepository.Queryable()
                 .Where(x => x.CreationTime >= dto.StartTime && x.CreationTime < dto.EndTime)
                 .WhereIF(dto.TypeId != null && dto.TypeId == 1, x => x.IdentityType == EIdentityType.Citizen)

+ 198 - 18
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -1,9 +1,11 @@
 using DotNetCore.CAP;
+using Hotline.Application.CallCenter;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.Orders;
-using Hotline.Application.Quality;
 using Hotline.Authentications;
 using Hotline.Caching.Interfaces;
+using Hotline.Caching.Services;
+using Hotline.Configurations;
 using Hotline.ContingencyManagement;
 using Hotline.File;
 using Hotline.FlowEngine.WorkflowModules;
@@ -12,18 +14,20 @@ using Hotline.Orders;
 using Hotline.OrderTranspond;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
-using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.ContingencyManagement;
 using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.OrderTranspond;
+using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Mq;
 using MapsterMapper;
-using PanGu;
-using StackExchange.Redis;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
@@ -44,6 +48,7 @@ namespace Hotline.Application.Subscribers
         private readonly IRepository<OrderSendBack> _orderSendBackRepository;
         private readonly IWorkflowApplication _workflowApplication;
         private readonly IWorkflowDomainService _workflowDomainService;
+        private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IFileRepository _fileRepository;
         private readonly IRepository<OrderUrge> _orderUrgeRepository;
         private readonly IRepository<OrderSupervise> _orderSuperviseRepository;
@@ -59,8 +64,13 @@ namespace Hotline.Application.Subscribers
         private readonly IRepository<OrderWarning> _orderWarningRepository;
         private readonly IRepository<OrderRevoke> _orderRevokeRepository;
         private readonly IRepository<ContingencyManagementOrders> _contingencyManagementOrdersRepository;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+        private readonly ICallApplication _callApplication;
+        private readonly IRepository<OrderPublish> _orderPublishRepository;
+        private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
+        private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
-        public DataSharingSubscriber(
+		public DataSharingSubscriber(
             IRepository<OrderVisit> orderVisitRepository,
             IMapper mapper,
             IOrderRepository orderRepository,
@@ -70,6 +80,7 @@ namespace Hotline.Application.Subscribers
             IRepository<OrderSendBack> orderSendBackRepository,
             IWorkflowApplication workflowApplication,
             IWorkflowDomainService workflowDomainService,
+            IRepository<WorkflowTrace> workflowTraceRepository,
             IRepository<OrderUrge> orderUrgeRepository,
             IRepository<OrderSupervise> orderSuperviseRepository,
             IRepository<OrderVisitDetail> orderVisitedDetailRepository,
@@ -84,12 +95,17 @@ namespace Hotline.Application.Subscribers
             ISystemSettingCacheManager systemSettingCacheManager,
             IRepository<OrderWarning> orderWarningRepository,
              IRepository<OrderRevoke> orderRevokeRepository,
-             IRepository<ContingencyManagementOrders> contingencyManagementOrdersRepository
-            )
+             IRepository<ContingencyManagementOrders> contingencyManagementOrdersRepository,
+            IOptionsSnapshot<AppConfiguration> appOptions,
+            ICallApplication callApplication,
+            IRepository<OrderPublish> orderPublishRepository,
+            ISystemDicDataCacheManager sysDicDataCacheManager,
+            IOptions<CityBaseConfiguration> cityBaseConfiguration)
         {
             _orderSendBackRepository = orderSendBackRepository;
             _workflowApplication = workflowApplication;
             _workflowDomainService = workflowDomainService;
+            _workflowTraceRepository = workflowTraceRepository;
             _orderUrgeRepository = orderUrgeRepository;
             _orderSuperviseRepository = orderSuperviseRepository;
             _orderScreenRepository = orderScreenRepository;
@@ -111,7 +127,12 @@ namespace Hotline.Application.Subscribers
             _orderWarningRepository = orderWarningRepository;
             _orderRevokeRepository = orderRevokeRepository;
             _contingencyManagementOrdersRepository = contingencyManagementOrdersRepository;
-        }
+            _appOptions = appOptions;
+            _callApplication = callApplication;
+            _orderPublishRepository = orderPublishRepository;
+            _sysDicDataCacheManager = sysDicDataCacheManager;
+            _cityBaseConfiguration = cityBaseConfiguration;
+		}
 
         /// <summary>
         /// 接收工单退回结果
@@ -159,7 +180,7 @@ namespace Hotline.Application.Subscribers
                     //order.File(now, handleDuration, fileDuration, allDuration);
                     //await _orderRepository.UpdateAsync(order, cancellationToken);
 
-                    var current = SessionContextCreator.CreateSessionContext(dto.Source);
+                    var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
                     if (string.IsNullOrEmpty(order.WorkflowId))
                     {
                         var startDto = new StartWorkflowDto
@@ -219,7 +240,7 @@ namespace Hotline.Application.Subscribers
             };
             await _orderRevokeRepository.AddAsync(orderRevoke, cancellationToken);
 
-            var current = SessionContextCreator.CreateSessionContext(dto.Source);
+            var current = SessionContextCreator.CreateSessionContext(dto.Source,_cityBaseConfiguration.Value);
             if (string.IsNullOrEmpty(order?.WorkflowId))
             {
                 var startDto = new StartWorkflowDto
@@ -273,8 +294,11 @@ namespace Hotline.Application.Subscribers
             //        model.OrgName = org.Value;
             //    }
             //}
-            model.OrgId = order.CurrentHandleOrgId;
-            model.OrgName = order.CurrentHandleOrgName;
+            if (!string.IsNullOrEmpty(order.CurrentHandleOrgId) && !string.IsNullOrEmpty(order.CurrentHandleOrgName))
+            {
+                model.OrgId = order.CurrentHandleOrgId;
+                model.OrgName = order.CurrentHandleOrgName;
+            }
 
 
             if (dto.Files.Any())
@@ -315,8 +339,13 @@ namespace Hotline.Application.Subscribers
                 //        model.OrgName = org.Value;
                 //    }
                 //}
-                model.OrgId = order.CurrentHandleOrgId;
-                model.OrgName = order.CurrentHandleOrgName;
+                //model.OrgId = order.CurrentHandleOrgId;
+                //model.OrgName = order.CurrentHandleOrgName;
+                if (!string.IsNullOrEmpty(order.CurrentHandleOrgId) && !string.IsNullOrEmpty(order.CurrentHandleOrgName))
+                {
+                    model.OrgId = order.CurrentHandleOrgId;
+                    model.OrgName = order.CurrentHandleOrgName;
+                }
 
                 await _orderUrgeRepository.AddAsync(model, cancellationToken);
 
@@ -388,7 +417,7 @@ namespace Hotline.Application.Subscribers
                             x.Status == EScreenStatus.Approval)
                 .FirstAsync(cancellationToken);
 
-            var current = SessionContextCreator.CreateSessionContext(dto.Source);
+            var current = SessionContextCreator.CreateSessionContext(dto.Source,_cityBaseConfiguration.Value);
             await _workflowApplication.HandleToEndAsync(current,
                 orderScreen.WorkflowId, "省上推送甄别结果", null,
                 dto.ProvinceScreenResult.AuditResult
@@ -517,6 +546,83 @@ namespace Hotline.Application.Subscribers
                     }
                 }
             }
+            else
+            {
+                //处理省下行回访
+                var order = await _orderRepository.Queryable().Where(x => x.ProvinceNo == dto.ProvinceNo).FirstAsync();
+                if (order !=null)
+                {
+                    //判断是否有发布数据
+                    var orderPublish = await _orderPublishRepository.Queryable()
+                        .Includes(x => x.Order).
+                        Where(x => x.Order.ProvinceNo == dto.ProvinceNo).FirstAsync(cancellationToken);
+                    if (orderPublish == null)
+                    {
+                        orderPublish = new OrderPublish();
+                        orderPublish.OrderId = order.Id;
+                        orderPublish.No = order.No;
+                        orderPublish.PublishState = false;
+                        orderPublish.ArrangeTitle = order.Title;
+                        orderPublish.ArrangeContent = order.Content;
+                        orderPublish.ArrangeOpinion = order.FileOpinion;
+                        orderPublish.ProPublishState = false;
+                        orderPublish.FeedBackPhone = order.Contact;
+                        orderPublish.CreatorName = order.CenterToOrgHandlerId;
+                        await _orderPublishRepository.AddAsync(orderPublish);
+                        order.Publish(orderPublish.PublishState);
+                    }
+
+                    orderVisit = new OrderVisit();
+                    orderVisit.No = order.No;
+                    orderVisit.OrderId = order.Id;
+                    orderVisit.VisitState = EVisitState.WaitForVisit;
+                    orderVisit.PublishTime = DateTime.Now;
+                    orderVisit.IsCanHandle = true;
+                    orderVisit.EmployeeId = order.CenterToOrgHandlerId;
+                    orderVisit.VisitState = EVisitState.Visited;
+                    orderVisit.VisitTime = dto.VisitTime;
+                    orderVisit.VisitType = dto.VisitType;
+                    orderVisit.IsCanAiVisit = false;
+                    orderVisit.IsCanHandle = false;
+                    var VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction).Where(x => x.DicDataValue == dto.OrgProcessingResults).Select(m => new Kv { Key = m.DicDataValue, Value = m.DicDataName }).FirstOrDefault();
+                    var satisfy = VisitSatisfaction;
+                    orderVisit.NowEvaluate = satisfy;
+                    string visitId = await _orderVisitRepository.AddAsync(orderVisit);
+
+                    //新增回访信息
+                    var visitedDetail = new List<OrderVisitDetail>();
+
+                    //新增坐席回访
+                    var seatDetail = new OrderVisitDetail();
+                    seatDetail.VisitId = visitId;
+                    seatDetail.VisitTarget = EVisitTarget.Seat;
+                    seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
+                    seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
+                    visitedDetail.Add(seatDetail);
+
+                    //新增部门回访
+                    var orgDetail = new OrderVisitDetail();
+                    orgDetail.VisitId = visitId;
+                    orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
+                    orgDetail.VisitOrgName = order.ActualHandleOrgName;
+                    orgDetail.VisitTarget = EVisitTarget.Org;
+                    
+                    
+                    orgDetail.OrgProcessingResults = satisfy;
+
+                    visitedDetail.Add(orgDetail);
+                    //TODO 自贡办件态度
+
+
+                    await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail,cancellationToken);
+                    order.Visited(satisfy.Key,satisfy.Value);
+                    order.Status = EOrderStatus.Visited;
+                    await _orderRepository.UpdateAsync(order, cancellationToken);
+
+                }
+                
+                
+            }
         }
 
         /// <summary>
@@ -557,7 +663,7 @@ namespace Hotline.Application.Subscribers
                         orderDelay.FileJson = await _fileRepository.AddFileAsync(dto.Files, orderDelay.Id, orderDelay.WorkflowId, cancellationToken);
                     await _orderDelayRepository.UpdateAsync(orderDelay, cancellationToken);
 
-                    var current = SessionContextCreator.CreateSessionContext(dto.Source);
+                    var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
                     await _workflowApplication.HandleToEndAsync(current, orderDelay.WorkflowId, dto.Opinion, dto.Files,
                         dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed, cancellationToken);
                 }
@@ -583,7 +689,7 @@ namespace Hotline.Application.Subscribers
             //    await _orderRepository.FileAsync(order, cancellationToken);
             //}
 
-            var current = SessionContextCreator.CreateSessionContext(dto.Source);
+            var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
             switch (dto.FinishType)
             {
                 case "0":
@@ -696,7 +802,7 @@ namespace Hotline.Application.Subscribers
                     if (order is null)
                         throw new UserFriendlyException("无效省工单编号");
 
-                    order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, order.WorkflowId ?? string.Empty, cancellationToken);
+                    order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", cancellationToken);
                     await _orderRepository.UpdateAsync(order, cancellationToken);
                     break;
                 case EDsBisType.OrderPreviousResult:
@@ -837,5 +943,79 @@ namespace Hotline.Application.Subscribers
                 await _contingencyManagementOrdersRepository.UpdateAsync(data, cancellationToken);
             }
         }
+
+        /// <summary>
+        /// 处理每天办理完成未及时推送办理结果的数据
+        /// </summary>
+        /// <param name="provinceNos"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        [CapSubscribe(EventNames.HotlineFiledOrdersRepublish)]
+        public async Task RepublishFiledOrders(List<string> provinceNos, CancellationToken cancellationToken)
+        {
+            var unpublishOrders = await _orderRepository.Queryable()
+                .Where(d => provinceNos.Contains(d.ProvinceNo) &&
+                            !string.IsNullOrEmpty(d.ProvinceNo) &&
+                            d.Status >= EOrderStatus.Filed)
+                .ToListAsync(cancellationToken);
+
+            foreach (var order in unpublishOrders)
+            {
+                var trace = await _workflowTraceRepository.Queryable()
+                    .FirstAsync(d => d.WorkflowId == order.WorkflowId && d.StepType == EStepType.End, cancellationToken);
+                var orderFlowDto = new OrderFlowDto
+                {
+                    Order = _mapper.Map<OrderDto>(order),
+                    WorkflowTrace = _mapper.Map<WorkflowTraceDto>(trace)
+                };
+
+                if (order.SourceChannelCode == AppDefaults.SourceChannel.DianHua &&
+                    !string.IsNullOrEmpty(order.CallId))
+                {
+                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
+                    {
+                        var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, cancellationToken);
+                        if (callRecord != null)
+                        {
+                            orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
+                        }
+                    }
+                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
+                    {
+                        var call = await _callApplication.GetCallAsync(order.CallId, cancellationToken);
+                        if (call is not null)
+                            orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(call);
+                    }
+                }
+
+                //这里需要判断是否是警情退回
+                orderFlowDto.IsNonPoliceReturn = false;
+                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
+
+            }
+        }
+
+        /// <summary>
+        ///  随手拍网格员、回复办理结果
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        [CapSubscribe(EventNames.TianQueReceiverOpinion)]
+        public async Task TianQueReceiverOpinion(TianQueReceiverOpinionDto dto, CancellationToken cancellationToken)
+        {
+            //todo
+        }
+
+        /// <summary>
+        ///  天阙推送工单,返回信息
+        /// </summary>
+        /// <returns></returns>
+        [CapSubscribe(EventNames.TianQuePushOrderReceiver)]
+        public async Task TianQuePushOrderReceiver(TianQuePushOrderReceiverDto dto, CancellationToken cancellationToken)
+        {
+            //todo
+        }
     }
+
 }

+ 36 - 10
src/Hotline.Application/Subscribers/InternalCapSubscriber.cs

@@ -11,13 +11,14 @@ using Hotline.Share.Mq;
 using Hotline.Users;
 using MediatR;
 using Microsoft.AspNetCore.Http;
+using NPOI.SS.Formula.Functions;
 using StackExchange.Redis;
 using XF.Domain.Dependency;
 using XF.Domain.Repository;
 
 namespace Hotline.Application.Subscribers
 {
-    public class InternalCapSubscriber: ICapSubscribe, ITransientDependency
+    public class InternalCapSubscriber : ICapSubscribe, ITransientDependency
     {
         private readonly IOrderRepository _orderRepository;
         private readonly IMediator _mediator;
@@ -25,7 +26,7 @@ namespace Hotline.Application.Subscribers
         private readonly ICapPublisher _capPublisher;
         private readonly IRepository<BatchSmsTask> _batchSmsTaskRepository;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
-        public InternalCapSubscriber(IOrderRepository orderRepository,IMediator mediator,IRepository<User> userRepository,ICapPublisher capPublisher,IRepository<BatchSmsTask> batchSmsTaskRepository,ISystemSettingCacheManager systemSettingCacheManager)
+        public InternalCapSubscriber(IOrderRepository orderRepository, IMediator mediator, IRepository<User> userRepository, ICapPublisher capPublisher, IRepository<BatchSmsTask> batchSmsTaskRepository, ISystemSettingCacheManager systemSettingCacheManager)
         {
             _orderRepository = orderRepository;
             _mediator = mediator;
@@ -42,17 +43,17 @@ namespace Hotline.Application.Subscribers
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         [CapSubscribe(EventNames.HotlineOrderNearlyExpiredTimeSms)]
-        public async Task SendOrderNearlyExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto,CancellationToken cancellationToken)
+        public async Task SendOrderNearlyExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto, CancellationToken cancellationToken)
         {
             var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-            if (order!=null && order.Status< Share.Enums.Order.EOrderStatus.Filed && order.NearlyExpiredTime?.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
+            if (order != null && order.Status < Share.Enums.Order.EOrderStatus.Filed && order.NearlyExpiredTime?.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
             {
                 //当前办理人不为空发短信给个人
                 if (!string.IsNullOrEmpty(order.CurrentHandlerId))
                 {
                     //查询人员
                     var user = await _userRepository.GetAsync(order.CurrentHandlerId, cancellationToken);
-                    if(user!=null && !string.IsNullOrEmpty(user.PhoneNo))
+                    if (user != null && !string.IsNullOrEmpty(user.PhoneNo))
                     {
                         //发送短信
                         var messageDto = new Share.Dtos.Push.MessageDto
@@ -71,7 +72,7 @@ namespace Hotline.Application.Subscribers
                     }
                 }
                 //当前办理部门不为空,发短信给部门经办人
-                else if(!string.IsNullOrEmpty(order.CurrentHandleOrgId))
+                else if (!string.IsNullOrEmpty(order.CurrentHandleOrgId))
                 {
                     var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                     //查询部门经办人
@@ -111,7 +112,7 @@ namespace Hotline.Application.Subscribers
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         [CapSubscribe(EventNames.HotlineOrderExpiredTimeSms)]
-        public async Task SendOrderExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto,CancellationToken cancellationToken)
+        public async Task SendOrderExpiredTimeSms(PublishNearlyExpiredTimeSmsDto dto, CancellationToken cancellationToken)
         {
             var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
             if (order != null && order.Status < Share.Enums.Order.EOrderStatus.Filed && order.NearlyExpiredTime?.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
@@ -178,11 +179,11 @@ namespace Hotline.Application.Subscribers
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         [CapSubscribe(EventNames.HotlineBatchSmsTask)]
-        public async Task SendBatchSmsTask(PublishBatchSmsTaskDto dto,CancellationToken cancellationToken)
+        public async Task SendBatchSmsTask(PublishBatchSmsTaskDto dto, CancellationToken cancellationToken)
         {
             var task = await _batchSmsTaskRepository.Queryable()
-                .Includes(x=>x.BatchSmsTaskDetails)
-                .Where(x=> x.Id == dto.TaskId).FirstAsync();
+                .Includes(x => x.BatchSmsTaskDetails)
+                .Where(x => x.Id == dto.TaskId).FirstAsync();
             if (task != null && task.SmsTaskState == ESmsTaskState.WaitDo && task.PlanSendTime.ToString("yyyy-MM-dd hh:mm") == DateTime.Now.ToString("yyyy-MM-dd hh:mm"))
             {
                 foreach (var item in task.BatchSmsTaskDetails)
@@ -200,5 +201,30 @@ namespace Hotline.Application.Subscribers
                 }
             }
         }
+
+        /// <summary>
+        /// 批量发送短信
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        [CapSubscribe(EventNames.HotlineLeaderSMS)]
+        public async Task SendLeaderSMS(PublishLeaderSMSDto dto, CancellationToken cancellationToken)
+        {
+            //发送短信
+            var messageDto = new Share.Dtos.Push.MessageDto
+            {
+                PushBusiness = EPushBusiness.OrderSend,
+                ExternalId = dto.OrderId,
+                OrderId = dto.OrderId,
+                PushPlatform = EPushPlatform.Sms,
+                Remark = string.Empty,
+                Name = dto.Name,
+                TemplateCode = "1014",
+                Params = new(),
+                TelNumber = dto.TelNumber,
+            };
+            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+        }
     }
 }

+ 102 - 0
src/Hotline.Application/Systems/BaseDataApplication.cs

@@ -0,0 +1,102 @@
+using Hotline.Caching.Interfaces;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Order;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Application.Systems;
+public class BaseDataApplication : IScopeDependency
+{
+    private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
+
+    public BaseDataApplication(ISystemDicDataCacheManager sysDicDataCacheManager)
+    {
+        _sysDicDataCacheManager = sysDicDataCacheManager;
+    }
+
+    private ConcurrentDictionary<string, dynamic> _baseData = new ConcurrentDictionary<string, dynamic>();
+    //private ConcurrentDictionary<string, int> _baseType = new ConcurrentDictionary<string, int>();
+    //private ConcurrentDictionary<string, int> _enumType = new ConcurrentDictionary<string, int>();
+    #region 内部方法
+    private void Add(Type type)
+    {
+        var name = new StackTrace().GetFrame(1).GetMethod().Name;
+        var method = typeof(EnumExts).GetMethod("GetDescriptions", BindingFlags.Static | BindingFlags.Public);
+        var genericMethod = method.MakeGenericMethod(type);
+        var result = genericMethod.Invoke(null, null);
+        _baseData.TryAdd(name, result);
+    }
+
+    private void Add(string key)
+    {
+        var name = new StackTrace().GetFrame(1).GetMethod().Name;
+        var result = _sysDicDataCacheManager
+            .GetSysDicDataCache(key)
+            .Where(x => x.DicDataValue != "-1")
+            .Select(m => new { m.Id, m.DicDataName, m.DicDataValue });
+        _baseData.TryAdd(name, result);
+    }
+    #endregion
+
+    public BaseDataApplication Source()
+    {
+        Add(typeof(ESource));
+        return this;
+    }
+
+    public BaseDataApplication VisitType()
+    {
+        Add(typeof(EVisitType));
+        return this;
+    }
+
+    public Dictionary<string, dynamic> Build()
+    {
+        return new Dictionary<string, dynamic>(_baseData);
+    }
+
+    public BaseDataApplication VoiceEvaluate()
+    {
+        Add(typeof(EVoiceEvaluate));
+        return this;
+    }
+
+    public BaseDataApplication SeatEvaluate()
+    {
+        Add(typeof(ESeatEvaluate));
+        return this;
+    }
+
+    public BaseDataApplication VisitSatisfaction()
+    {
+        Add(SysDicTypeConsts.VisitSatisfaction);
+        return this;
+    }
+
+    public BaseDataApplication VisitManner()
+    {
+        Add(SysDicTypeConsts.VisitManner);
+        return this;
+    }
+
+    public BaseDataApplication VisitStateQuery()
+    {
+        Add(typeof(EVisitStateQuery));
+        return this;
+    }
+
+    public BaseDataApplication DissatisfiedReason()
+    {
+        Add(SysDicTypeConsts.DissatisfiedReason);
+        return this;
+    }
+}

+ 1 - 0
src/Hotline.Application/Tels/ITelApplication.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Share.Dtos.TrCallCenter;
 using Microsoft.AspNetCore.Http;
 
 namespace Hotline.Application.Tels

+ 9 - 5
src/Hotline.Application/Tels/TelApplication.cs

@@ -1,9 +1,12 @@
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Tels;
+using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
+using Tr.Sdk;
+using Tr.Sdk.Tels;
 using XF.Domain.Cache;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
@@ -24,7 +27,8 @@ public class TelApplication : ITelApplication, IScopeDependency
         ITelRestRepository telRestRepository,
         ITypedCache<Work> cacheWork,
         IWorkRepository workRepository,
-        IRepository<TelActionRecord> telActionRecordRepository)
+        IRepository<TelActionRecord> telActionRecordRepository
+        )
     {
         _userCacheManager = userCacheManager;
         _telRestRepository = telRestRepository;
@@ -52,7 +56,7 @@ public class TelApplication : ITelApplication, IScopeDependency
         await _workRepository.UpdateAsync(work, cancellationToken);
         _cacheWork.Remove(work.GetKey(KeyMode.UserId));
         _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
-        
+
         var list = await _telActionRecordRepository.Queryable().Where(x => x.TelNo == work.TelNo && !x.EndTime.HasValue).ToListAsync();
         foreach (var item in list)
         {
@@ -75,7 +79,7 @@ public class TelApplication : ITelApplication, IScopeDependency
         //}
     }
 
-    public async Task SignOutByTelNoAsync(string telNo,CancellationToken cancellationToken)
+    public async Task SignOutByTelNoAsync(string telNo, CancellationToken cancellationToken)
     {
         var work = _userCacheManager.GetWorkByTelNoExp(telNo);
         if (work is null) return;
@@ -95,7 +99,7 @@ public class TelApplication : ITelApplication, IScopeDependency
 
 
         var list = await _telActionRecordRepository.Queryable().Where(x => x.TelNo == work.TelNo && !x.EndTime.HasValue).ToListAsync();
-        foreach ( var item in list )
+        foreach (var item in list)
         {
             item.EndAction();
             await _telActionRecordRepository.UpdateAsync(item);
@@ -115,4 +119,4 @@ public class TelApplication : ITelApplication, IScopeDependency
         //    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
         //}
     }
-}
+  }

+ 1 - 12
src/Hotline.Repository.SqlSugar/CallCenter/TrCallRecordRepository.cs

@@ -125,15 +125,6 @@ namespace Hotline.Repository.SqlSugar.CallCenter
 
         public async Task<List<TrCallHourDto>?> GetCallHourList(DateTime beginDate, DateTime? endDate, int noConnectByeTimes, int effectiveTimes, int connectByeTimes, string source)
         {
-            //计算小时差
-            if (!endDate.HasValue)
-            {
-                endDate = beginDate.Date.AddDays(1).AddSeconds(-1);
-            }
-            else
-            {
-                endDate = endDate.Value.Date.AddDays(1).AddSeconds(-1);
-            }
             TimeSpan timeDifference = endDate.Value.Subtract(beginDate).Duration();
 
             int hourDiff = (int)(timeDifference.TotalHours);
@@ -194,7 +185,6 @@ namespace Hotline.Repository.SqlSugar.CallCenter
             {
                 endHourTo = startHourTo.Value.Add(new TimeSpan(1, 0, 0));
             }
-            endDate = endDate.Value.Date.AddDays(1).AddSeconds(-1);
             RefAsync<int> total = 0;
             var res = await Db.Queryable<TrCallRecord>()
                 .Where(x => x.CreatedTime >= beginDate && x.CreatedTime <= endDate)
@@ -225,9 +215,8 @@ namespace Hotline.Repository.SqlSugar.CallCenter
 
         public async Task<List<CallHotLineDto>> GetCallHotLineList(DateTime beginDate, DateTime endDate, string lineNum, int noConnectByeTimes, int effectiveTimes, int connectByeTimes, int ringTims)
         {
-            endDate = endDate.AddDays(1).AddSeconds(-1);
             var list = await Db.Queryable<TrCallRecord>()
-                .Where(x => x.CreatedTime >= beginDate && x.CreatedTime <= endDate)
+                .Where(x => x.CreatedTime >= beginDate && x.CreatedTime <= endDate && SqlFunc.Length(x.Gateway)>4)
                 .WhereIF(!string.IsNullOrEmpty(lineNum), x => x.Gateway == lineNum)
                 .GroupBy(x => x.Gateway)
                 .Select(x => new CallHotLineDto()

+ 28 - 0
src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingAttributeRepository.cs

@@ -0,0 +1,28 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain.Repository;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Repository.SqlSugar.ExpireTime;
+public class TimeLimitSettingAttributeRepository : BaseRepository<TimeLimitSettingAttribute>, ITimeLimitSettingAttributeRepository, IScopeDependency
+{
+    public TimeLimitSettingAttributeRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+
+    public async Task<TimeLimitSettingAttribute?> GetAsync(string busCode, string name, string value)
+        => await base.GetAsync(x => x.Name == name && x.Value == value && x.BusCode == busCode);
+
+    public async Task<TimeLimitSettingAttribute?> GetAsync(string name, string value)
+        => await GetAsync(m => m.Name == name && m.Value == value);
+
+    public async Task<TimeLimitSettingAttribute?> GetFuzzyAsync(string busCode, string name, string value)
+        => await base.GetAsync(m => m.Name == name && value.Contains(m.Value) && m.BusCode == busCode);
+}

+ 24 - 0
src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingInventoryRepository.cs

@@ -0,0 +1,24 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain.Repository;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.ExpireTime;
+public class TimeLimitSettingInventoryRepository : BaseRepository<TimeLimitSettingInventory>, ITimeLimitSettingInventoryRepository, IScopeDependency
+{
+    public TimeLimitSettingInventoryRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+
+    public async Task<TimeLimitSettingInventory?> GetByCode(string code)
+    {
+        return await base.Queryable().Where(m => m.Code == code).FirstAsync();
+    }
+}
+

+ 21 - 0
src/Hotline.Repository.SqlSugar/ExpireTime/TimeLimitSettingRepository.cs

@@ -0,0 +1,21 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Settings.TimeLimitDomain.Repository;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.ExpireTime;
+public class TimeLimitSettingRepository : BaseRepository<TimeLimitSetting>, ITimeLimitSettingRepository, IScopeDependency
+{
+    public TimeLimitSettingRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+
+    public async Task<TimeLimitSetting?> GetByBusCode(string busCode)
+        => await base.GetAsync(x => x.BusCode == busCode);
+}

+ 21 - 36
src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs

@@ -32,7 +32,7 @@ namespace Hotline.Repository.SqlSugar.Orders
         private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
         private readonly ISessionContext _sessionContext;
 
-		public OrderRepository(ISugarUnitOfWork<HotlineDbContext> uow,
+        public OrderRepository(ISugarUnitOfWork<HotlineDbContext> uow,
             IDataPermissionFilterBuilder dataPermissionFilterBuilder,
             IRepository<OrderSendBackAudit> orderSendBackAuditRepository,
             IRepository<OrderVisit> orderVisitRepository,
@@ -203,7 +203,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<object> OrderAreaTime(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new List<int>();
             for (int i = 0; i < 24; i++)
             {
@@ -257,7 +256,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> OrderAreaTimeExport(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
             {
@@ -311,7 +309,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<object> OrderHotspotTime(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new List<int>();
             for (int i = 0; i < 24; i++)
             {
@@ -365,7 +362,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> OrderHotspotTimeExport(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
             {
@@ -419,7 +415,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<object> OrderAcceptanceTime(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new List<int>();
             for (int i = 0; i < 24; i++)
             {
@@ -473,8 +468,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
             {
@@ -528,7 +521,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<object> OrderSourceTime(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new List<int>();
             for (int i = 0; i < 24; i++)
             {
@@ -586,7 +578,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> OrderSourceTimeExport(TimeSharingPagedKeywordRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             List<int> dts = new();
             for (int i = 0; i < 24; i++)
             {
@@ -639,7 +630,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<object> OrderSource(QueryOrderSourceRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             var listOrder = Db.Queryable<Order>()
                  .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime)
                  .WhereIF(dto.TypeId != null && dto.TypeId == 1, p => p.IdentityType == EIdentityType.Citizen)
@@ -676,7 +666,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> OrderSourceExport(QueryOrderSourceRequest dto)
         {
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             var listOrder = Db.Queryable<Order>()
                  .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime)
                  .WhereIF(dto.TypeId != null && dto.TypeId == 1, p => p.IdentityType == EIdentityType.Citizen)
@@ -782,7 +771,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public ISugarQueryable<HotspotAndAreaStatisticsDetailDto> HotspotAndAreaStatisticsDetail(HotspotAndAreaStatisticsDetailReq dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             var query = Db.Queryable<Order>()
                 //.Includes(x => x.OrderScreens.OrderByDescending(x => x.CreationTime).FirstOrDefault())
                 .Where(x => x.HotspotId.StartsWith(dto.HotspotId) && x.CreationTime >= dto.StartTime && x.CreationTime < dto.EndTime)
@@ -825,7 +813,7 @@ namespace Hotline.Repository.SqlSugar.Orders
                .Where(x => x.AcceptTypeCode == dto.AcceptTypeCode && x.CreationTime.ToString("yyyy-MM-dd") == Date)
                .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No == dto.No)
                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title))
-               .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), x => x.ActualHandleOrgName.Contains(dto.CurrentHandleOrgName))
+               .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.ActualHandleOrgName.Contains(dto.ActualHandleOrgName))
                .Select(x => new HotspotAndAreaStatisticsDetailDto
                {
                    Id = x.Id,
@@ -858,8 +846,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<(List<SystemDicData> acceptType, object items)> AcceptTypeStatisticsByDate(AcceptTypeStatisticsByDateReq dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             //处理时间
             var diffDays = (dto.EndTime - dto.StartTime).Days;
             List<string> dateList = new List<string>();
@@ -929,8 +915,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public async Task<DataTable> AcceptTypeStatisticsByDateExport(AcceptTypeStatisticsByDateReq dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
-
             //处理时间
             var diffDays = (dto.EndTime - dto.StartTime).Days;
             List<string> dateList = new List<string>();
@@ -1086,7 +1070,7 @@ namespace Hotline.Repository.SqlSugar.Orders
 		        .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.CreationTime >= dto.StartTime && d.CreationTime <= dto.EndTime)
 		        .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, d => d.IdentityType == EIdentityType.Citizen)
 		        .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, d => d.IdentityType == EIdentityType.Enterprise)
-		        .GroupBy(d => d.CreationTime)
+		        .GroupBy(d => d.CreationTime.Hour.ToString())
 		        .Select((d, s) => new OrderCenterAcceptHourVo
 				{
 			        Hour = d.CreationTime.Hour.ToString(),
@@ -1096,8 +1080,9 @@ namespace Hotline.Repository.SqlSugar.Orders
 			        InvalidNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.AcceptType == "无效", 1, 0)),
 			        HandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status >= EOrderStatus.Filed, 1, 0)),
 			        NoHandleNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EOrderStatus.Filed, 1, 0)),
-			        BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null && s.OrderId != "", 1, 0))
-		        });
+			        BackNum = SqlFunc.AggregateSum(SqlFunc.IIF(s.OrderId != null && s.OrderId != "", 1, 0)),
+			        DutyDeskNum = SqlFunc.AggregateDistinctCount(d.AcceptorId)
+				});
             var query = listHour.LeftJoin(data, (h, d) => h.ColumnName.ToString() == d.Hour)
                  .GroupBy((h,d)=> h.ColumnName)
                  .OrderBy((h, d) => h.ColumnName)
@@ -1110,8 +1095,9 @@ namespace Hotline.Repository.SqlSugar.Orders
                      InvalidNum = SqlFunc.AggregateSum(d.InvalidNum),
                      HandleNum = SqlFunc.AggregateSum(d.HandleNum),
                      NoHandleNum = SqlFunc.AggregateSum(d.NoHandleNum),
-                     BackNum = SqlFunc.AggregateSum(d.BackNum)
-                 });
+                     BackNum = SqlFunc.AggregateSum(d.BackNum),
+                     DutyDeskNum = SqlFunc.AggregateSum(d.DutyDeskNum)
+				 });
 			return query;
         }
 		public ISugarQueryable<SelectOrderId> OrderListUnionAll(ISugarQueryable<SelectOrderId> t1, ISugarQueryable<SelectOrderId> t2)
@@ -1158,8 +1144,9 @@ namespace Hotline.Repository.SqlSugar.Orders
                 .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), x => x.Contact == dto.PhoneNo!) //联系电话
                 .WhereIF(dto.IdentityType.HasValue, x => x.IdentityType == dto.IdentityType) //来电主体
                 .WhereIF(dto.FromGender.HasValue, x => x.FromGender == dto.FromGender) //来电性别
-                .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), x => x.PushTypeCode == dto.PushTypeCode)//推送分类
-                .WhereIF(dto.ExpiredStatus.HasValue && dto.ExpiredStatus == EExpiredStatusEx.Normal,x=> (x.ExpiredTime.HasValue && DateTime.Now < x.ExpiredTime && x.Status>= EOrderStatus.Filed) || (x.NearlyExpiredTime.HasValue && DateTime.Now < x.NearlyExpiredTime && x.Status< EOrderStatus.Filed)) //超期状态:正常
+                //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), x => x.PushTypeCode == dto.PushTypeCode)//推送分类
+                .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), x => x.OrderPushTypes.Any(opt=>opt.PushTypeCode  == dto.PushTypeCode))//推送分类
+				.WhereIF(dto.ExpiredStatus.HasValue && dto.ExpiredStatus == EExpiredStatusEx.Normal,x=> (x.ExpiredTime.HasValue && DateTime.Now < x.ExpiredTime && x.Status>= EOrderStatus.Filed) || (x.NearlyExpiredTime.HasValue && DateTime.Now < x.NearlyExpiredTime && x.Status< EOrderStatus.Filed)) //超期状态:正常
                 .WhereIF(dto.ExpiredStatus.HasValue && dto.ExpiredStatus == EExpiredStatusEx.GoingToExpired,x=> (x.Status< EOrderStatus.Filed && DateTime.Now> x.NearlyExpiredTime && DateTime.Now < x.ExpiredTime) || (x.Status >= EOrderStatus.Filed && x.FiledTime > x.NearlyExpiredTime && x.FiledTime< x.ExpiredTime)) // 超期状态:即将超期
                 .WhereIF(dto.ExpiredStatus.HasValue && dto.ExpiredStatus == EExpiredStatusEx.Expired,x=> (x.Status< EOrderStatus.Filed && DateTime.Now > x.ExpiredTime) || (x.Status>= EOrderStatus.Filed && x.FiledTime > x.ExpiredTime))
                 .Select(x => new OrderDataInventoryRep()
@@ -1273,35 +1260,34 @@ namespace Hotline.Repository.SqlSugar.Orders
                 .WhereIF(dto.CreationTimeEnd.HasValue, x => x.OrderVisit.Order.CreationTime <= dto.CreationTimeEnd) //受理时间结束
                 .WhereIF(dto.ActualHandleTimeStart.HasValue, x => x.OrderVisit.Order.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
                 .WhereIF(dto.ActualHandleTimeEnd.HasValue, x => x.OrderVisit.Order.ActualHandleTime <= dto.ActualHandleTimeEnd)//办结时间结束
-                .WhereIF(dto.VisitTimeStart.HasValue,x=>x.OrderVisit.VisitTime>= dto.VisitTimeStart) //回访时间
-                .WhereIF(dto.VisitTimeEnd.HasValue,x=>x.OrderVisit.VisitTime<dto.VisitTimeEnd) //回访时间
+                .WhereIF(dto.VisitTimeStart.HasValue, x => x.OrderVisit.VisitTime >= dto.VisitTimeStart) //回访时间
+                .WhereIF(dto.VisitTimeEnd.HasValue, x => x.OrderVisit.VisitTime < dto.VisitTimeEnd) //回访时间
                 .OrderByDescending(x => x.OrderVisit.VisitTime)
                 .Select(x => new OrgVisitDetailListResp()
                 {
                     Id = x.OrderVisit.Order.Id,
                     VisitId = x.OrderVisit.Id,
-                    No =  x.OrderVisit.No,
+                    No = x.OrderVisit.No,
                     ReTransactNum = x.OrderVisit.Order.ReTransactNum,
-                    OrderScreenStatus = SqlFunc.Subqueryable<OrderScreen>().Where(q => q.OrderId == x.OrderVisit.OrderId).OrderByDesc(q => q.CreationTime).Select(q => q.Status),
+                    OrderScreenStatus = SqlFunc.Subqueryable<OrderScreen>().Where(q => q.OrderId == x.OrderVisit.OrderId && q.VisitDetailId == x.Id).OrderByDesc(q => q.CreationTime).Select(q => q.Status),
                     VisitContent = x.VisitContent,
                     HotspotSpliceName = x.OrderVisit.Order.HotspotSpliceName,
                     OrgLevelOneName = x.OrderVisit.Order.OrgLevelOneName,
-                    ActualHandleOrgName = x.OrderVisit.Order.ActualHandleOrgName,
+                    CurrentHandleOrgName = x.OrderVisit.Order.CurrentHandleOrgName,
                     CreationTime = x.CreationTime,
                     Title = x.OrderVisit.Order.Title,
                     VisitUser = x.OrderVisit.Employee.Name,
                     VisitType = x.OrderVisit.VisitType,
                     VisitTime = x.OrderVisit.VisitTime,
-                    OrgProcessingResults = SqlFunc.JsonField(x.OrgProcessingResults,"Value"),
+                    OrgProcessingResults = SqlFunc.JsonField(x.OrgProcessingResults, "Value"),
                     Content = x.OrderVisit.Order.Content,
                     FileOpinion = x.OrderVisit.Order.FileOpinion,
                     FiledTime = x.OrderVisit.Order.FiledTime,
                     VisitOrgName = x.VisitOrgName
-                }); 
+                });
 
         }
 
-
         /// <summary>
         /// 部门满意度明细统计
         /// </summary>
@@ -1309,7 +1295,6 @@ namespace Hotline.Repository.SqlSugar.Orders
         /// <returns></returns>
         public ISugarQueryable<OrgVisitDetailListResp> VisitAndOrgSatisfactionDetail(VisitAndOrgSatisfactionDetailDto dto)
         {
-            dto.EndTime = dto.EndTime.AddDays(1).AddSeconds(-1);
             bool IsCenter = _sessionContext.OrgIsCenter;
             return _orderVisitDetailRepository.Queryable()
                 .Includes(x => x.OrderVisit, o => o.Order, d => d.CallRecord)
@@ -1332,11 +1317,11 @@ namespace Hotline.Repository.SqlSugar.Orders
                     VisitId = x.OrderVisit.Id,
                     No = x.OrderVisit.No,
                     ReTransactNum = x.OrderVisit.Order.ReTransactNum,
-                    OrderScreenStatus = SqlFunc.Subqueryable<OrderScreen>().Where(q => q.OrderId == x.OrderVisit.OrderId).OrderByDesc(q => q.CreationTime).Select(q => q.Status),
+                    OrderScreenStatus = SqlFunc.Subqueryable<OrderScreen>().Where(q => q.OrderId == x.OrderVisit.OrderId && q.VisitDetailId == x.Id).OrderByDesc(q => q.CreationTime).Select(q => q.Status),
                     VisitContent = x.VisitContent,
                     HotspotSpliceName = x.OrderVisit.Order.HotspotSpliceName,
                     OrgLevelOneName = x.OrderVisit.Order.OrgLevelOneName,
-                    ActualHandleOrgName = x.OrderVisit.Order.ActualHandleOrgName,
+                    CurrentHandleOrgName = x.OrderVisit.Order.CurrentHandleOrgName,
                     CreationTime = x.CreationTime,
                     Title = x.OrderVisit.Order.Title,
                     VisitUser = x.OrderVisit.Employee.Name,

+ 102 - 0
src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs

@@ -0,0 +1,102 @@
+using Hotline.Caching.Interfaces;
+using Hotline.Caching.Services;
+using Hotline.Orders;
+using Hotline.Push.FWMessage;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Push;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using Microsoft.Extensions.Logging;
+using SqlSugar;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Repository.SqlSugar.Orders;
+public class OrderVisitRepository : BaseRepository<OrderVisit>, IOrderVisitRepository, IScopeDependency
+{
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly ILogger<OrderVisitRepository> _logger;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+
+    public OrderVisitRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IRepository<OrderVisitDetail> orderVisitDetailRepository, ILogger<OrderVisitRepository> logger, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager) : base(uow, dataPermissionFilterBuilder)
+    {
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _logger = logger;
+        _orderRepository = orderRepository;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+    }
+
+    /// <summary>
+    /// 用户回访短信回复更新回访状态
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="data"></param>
+    /// <returns></returns>
+    public async Task UpdateSmsReplyAsync(PushReceiveMessageDto dto, Message data)
+    {
+        if (dto.IsSmsReply == false || dto.SmsReplyContent.IsNullOrEmpty() || dto.ExternalId.IsNullOrEmpty()) return;
+
+        var orderVisit = await GetAsync(dto.ExternalId)
+             ?? throw new UserFriendlyException($"回访单不存在, visitId: {dto.ExternalId} message: {data.ToJson()}");
+
+        Dictionary<string, string> dics = new()
+        {
+            { "1", $"非常满意|{EVisitState.Visited}|{ESeatEvaluate.VerySatisfied}|{EVoiceEvaluate.VerySatisfied}|5" },
+            { "2", $"满意|{EVisitState.Visited}|{ESeatEvaluate.Satisfied}|{EVoiceEvaluate.Satisfied}|4"},
+            { "3", $"一般|{EVisitState.Visited}|{ESeatEvaluate.Satisfied}|{EVoiceEvaluate.Normal}|4"},
+            { "4", $"不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.NoSatisfied}|2"},
+            { "5", $"非常不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.VeryNoSatisfied}|2"},
+        };
+
+        var replyTxt = dto.SmsReplyContent.Trim();
+        var result = dics[replyTxt];
+        if (result.IsNullOrEmpty()) throw new UserFriendlyException($"用户回复短信内容异常; reply: {replyTxt}");
+        var replySplit = result.Split("|");
+        if (new string[] { "4", "5" }.Contains(replyTxt))
+        {
+            // “短信不满意待回访”状态下,由其他方式再次进行回访,回访方式需更新为最新的回访方式
+            // 故在此置为空
+            orderVisit.VisitType = null;
+        }
+        var visitSatisfaction = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction)
+            .First(m => m.DicDataValue == replySplit[4]);
+        orderVisit.NowEvaluate = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
+
+        orderVisit.VisitTime = DateTime.Now;
+        orderVisit.VisitState = replySplit[1].ToEnum<EVisitState>();
+        await UpdateAsync(orderVisit, ignoreNullColumns: false);
+
+        if (orderVisit.VisitState == EVisitState.Visited)
+        {
+            await _orderRepository.GetAsync(orderVisit.OrderId)
+                .Then(async order =>
+                {
+                    order.Visited(replyTxt, replySplit[0]);
+                    await _orderRepository.UpdateAsync(order);
+                });
+
+        }
+        var detailOrg = await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Org)
+            .ToListAsync();
+        foreach (var item in detailOrg)
+        {
+            item.OrgProcessingResults = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
+            item.OrgHandledAttitude = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
+            await _orderVisitDetailRepository.UpdateAsync(item);
+        }
+
+        await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Seat)
+            .FirstAsync()
+            .Then(async detailSeat =>
+            {
+                detailSeat.SeatEvaluate ??= replySplit[2].ToEnum<ESeatEvaluate>();
+                detailSeat.VoiceEvaluate ??= replySplit[3].ToEnum<EVoiceEvaluate>();
+                await _orderVisitDetailRepository.UpdateAsync(detailSeat);
+            });
+    }
+}

+ 9 - 0
src/Hotline.Share/Dtos/CallCenter/BiQueryCallsDto.cs

@@ -20,4 +20,13 @@ public class BiQueryHourCallDto
     public DateTime StartTime { get; set; }
     public DateTime? EndTime { get; set; }
     public string Source {get; set; }
+}
+
+public class BiQueryGateWayDto
+{
+    public DateTime StartTime { get; set; }
+    
+    public DateTime EndTime { get; set; }
+    
+    public string gateway { get; set; }
 }

+ 23 - 0
src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/TianQuePushOrderReceiverDto.cs

@@ -0,0 +1,23 @@
+namespace Hotline.Share.Dtos.DataSharing.PusherHotlineDto
+{
+    /// <summary>
+    /// 天阙推送工单返回
+    /// </summary>
+    public class TianQuePushOrderReceiverDto
+    {
+        /// <summary>
+        /// 网格员编号
+        /// </summary>
+        public string? AppealNumber { get; set; }
+
+        /// <summary>
+        /// 区域id
+        /// </summary>
+        public string? OrgId { get; set; }
+
+        /// <summary>
+        /// 自动退回时间
+        /// </summary>
+        public DateTime? AutoBackTime { get; set; }
+    }
+}

+ 107 - 0
src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/TianQueReceiverOpinionDto.cs

@@ -0,0 +1,107 @@
+using Hotline.Share.Dtos.File;
+
+namespace Hotline.Share.Dtos.DataSharing.PusherHotlineDto
+{
+    public class TianQueReceiverOpinionDto
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 办理时间
+        /// </summary>
+        public DateTime? HandleTime { get; set; }
+
+        /// <summary>
+        /// 办理人
+        /// </summary>
+        public string? HandleUser { get; set; }
+
+        /// <summary>
+        /// 办理部门
+        /// </summary>
+        public string? HandleOrgName { get; set; }
+
+        /// <summary>
+        /// 办理状态 1,7:流转 2:办结 3:退回 4:网格员签收 5:消息推送 6: 超时自动退单
+        /// </summary>
+        public string? HandleType { get; set; }
+
+        /// <summary>
+        /// 是否属实
+        /// </summary>
+        public bool ISTrue { get; set; }
+
+        /// <summary>
+        /// 是否重复 
+        /// </summary>
+        public bool IsRepeat { get; set; }
+
+        /// <summary>
+        /// 重复工单号
+        /// </summary>
+        public string? RepeatNo { get; set; }
+
+        /// <summary>
+        /// 是否隐患
+        /// </summary>
+        public bool IsHiddenDanger { get; set; }
+
+        /// <summary>
+        /// 是否重大隐患 
+        /// </summary>
+        public bool IsMajorHidden { get; set; }
+
+        /// <summary>
+        /// 网格员姓名
+        /// </summary>
+        public string? MemberName { get; set; }
+
+        /// <summary>
+        /// 网格员电话
+        /// </summary>
+        public string? MemberMobile { get; set; }
+
+        /// <summary>
+        /// 网格化诉求编号
+        /// </summary>
+        public string? AppealNumber { get; set; }
+
+        /// <summary>
+        /// 办理内容
+        /// </summary>
+        public string? ReplyContent { get; set; }
+
+        /// <summary>
+        /// 区域id
+        /// </summary>
+        public string? AreaId { get; set; }
+
+        /// <summary>
+        /// 区域名称
+        /// </summary>
+        public string? AreaName { get; set; }
+
+        /// <summary>
+        /// 区域全称
+        /// </summary>
+        public string? AreaFullName { get; set; }
+
+        /// <summary>
+        /// 区域编码
+        /// </summary>
+        public string? DepartmentNo { get; set; }
+
+        /// <summary>
+        /// 区域上级Id
+        /// </summary>
+        public string? ParentAreaId { get; set; }
+
+        /// <summary>
+        /// 附件
+        /// </summary>
+        public List<FileDto> FileDtos { get; set; }
+    }
+}

+ 18 - 0
src/Hotline.Share/Dtos/DataSharingSearch/AcceptTypeList.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.DataSharingSearch
+{
+    /// <summary>
+    /// 受理类型
+    /// </summary>
+    public class AcceptTypeList
+    {
+        public string? Name { get; set; }
+
+        public string? Value { get; set; }
+    }
+}

+ 17 - 0
src/Hotline.Share/Dtos/DataSharingSearch/GetBulletinListDto.cs

@@ -0,0 +1,17 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.DataSharingSearch
+{
+    public record GetBulletinListDto : PagedRequest
+    {
+        /// <summary>
+        /// 发布范围
+        /// </summary>
+        public string PushRanges { get; set; } = "2";
+
+        /// <summary>
+        /// 公告类型
+        /// </summary>
+        public string? BulletinTypeId { get; set; }
+    }
+}

+ 61 - 0
src/Hotline.Share/Dtos/DataSharingSearch/GetOrderDetailDto.cs

@@ -0,0 +1,61 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.DataSharingSearch
+{
+    public class GetOrderDetailDto
+    {
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+    }
+
+    public record GetOrderList : PagedRequest
+    {
+        /// <summary>
+        /// 平台名称
+        /// </summary>
+        public string? SourceChannelCode { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 手机号
+        /// </summary>
+        public string Mobile { get; set; }
+
+        /// <summary>
+        /// 受理类型编码
+        /// </summary>
+        public string AcceptTypeCode { get; set; }
+
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public DateTime? StartTime { get; set; }
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 区域ID
+        /// </summary>
+        public string? AreaCode { get; set; }
+
+        /// <summary>
+        /// 工单办理状态Code  1:办理中,2:办理完成 ,其他查询全部
+        /// </summary>
+        public string? HandleStateCode { get; set; }
+    }
+}

+ 26 - 0
src/Hotline.Share/Dtos/DataSharingSearch/GetOrderNoPwdDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.DataSharingSearch
+{
+    public class GetOrderNoPwdDto
+    {
+        /// <summary>
+        /// 编号
+        /// </summary>
+        public string No {  get; set; }
+
+        /// <summary>
+        /// 密码
+        /// </summary>
+        public string Password {  get; set; }
+
+        /// <summary>
+        /// 平台名称
+        /// </summary>
+        public string? SourceChannelCode {  get; set; }
+    }
+}

+ 39 - 0
src/Hotline.Share/Dtos/DataSharingSearch/GridOperatorSendSmsDto.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.DataSharingSearch
+{
+    public class GridOperatorSendSmsDto
+    {
+        /// <summary>
+        /// 唯一标识/工单编号
+        /// </summary>
+        public string ReplyCode { get; set; }
+
+        /// <summary>
+        /// 网格员姓名
+        /// </summary>
+        public string? MemberName { get; set; }
+
+        /// <summary>
+        /// 网格员电话
+        /// </summary>
+        public string? MemberMobile { get; set; }
+
+        /// <summary>
+        /// 网格化诉求编号
+        /// </summary>
+        public string? AppealNumber { get; set; }
+
+        /// <summary>
+        /// 短信类型 1: 短信  2:超时提醒  
+        /// </summary>
+        public string SendType { get; set; }
+    }
+}

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/Definition/StepDefineBasic.cs

@@ -63,7 +63,7 @@ namespace Hotline.Share.Dtos.FlowEngine.Definition
         /// <summary>
         /// 会签策略
         /// </summary>
-        public EDynamicPolicy? CountersignPolicy { get; set; }
+        public EDynamicPolicyCountersign? CountersignPolicy { get; set; }
 
         #endregion
         

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

@@ -1,4 +1,5 @@
-using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Dtos.Settings;
+using Hotline.Share.Enums.FlowEngine;
 
 namespace Hotline.Share.Dtos.FlowEngine;
 
@@ -45,8 +46,32 @@ public class NextStepsWithOpinionDto<TSteps> : NextStepsDto<TSteps>
 {
     /// <summary>
     /// 宜宾需求:汇总节点办理前展示前一节点办理意见
+    /// 自贡需求: 临时保存的办理意见
     /// </summary>
     public string? Opinion { get; set; }
+
+    /// <summary>
+    /// 自贡需求: 选择某一部门后会给对应部门领导发短信
+    /// </summary>
+    public IList<Kv>? LeaderSMS { get; set; }
+
+    /// <summary>
+    /// 市州转办信息
+    /// </summary>
+    public List<SystemDicDataOutDto>? TranspondCity { get; set; }
+}
+
+public class StepTempInDto
+{
+    /// <summary>
+    /// 节点Id
+    /// </summary>
+    public string StepId { get; set; }
+
+    /// <summary>
+    /// 意见
+    /// </summary>
+    public string Opinion { get; set; }
 }
 
 

+ 60 - 2
src/Hotline.Share/Dtos/FlowEngine/NextWorkflowDto.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Enums.FlowEngine;
+using System.ComponentModel;
 
 namespace Hotline.Share.Dtos.FlowEngine;
 
@@ -49,15 +50,72 @@ public class NextWorkflowDto : BasicWorkflowDto
 
     /// <summary>
     /// 已与市民沟通
+    /// 已与市民电话联系,确认办理结果
     /// </summary>
+    [Description("已与市民电话联系,确认办理结果")]
     public bool? RealIsContacted { get; set; }
 
     /// <summary>
     /// 已与市民现场沟通
+    /// 已赴现场处置,将处理结果告知市民
     /// </summary>
+    [Description("已赴现场处置,将处理结果告知市民")]
     public bool? RealContactLocale { get; set; }
 
-   
+    #endregion
 
-	#endregion
+    #region task_298
+    /// <summary>
+    /// 其它
+    /// </summary>
+    [Description("其它")]
+    public bool? IsOther { get; set; }
+
+    /// <summary>
+    /// 其它原因
+    /// </summary>
+    [Description("其它原因")]
+    public string? OtherRemark { get; set; }
+
+    /// <summary>
+    /// 是否紧急
+    /// </summary>
+    public bool? IsUrgent { get; set; }
+
+    /// <summary>
+    /// 是否推诿
+    /// </summary>
+    public bool? IsEvasive { get; set; }
+
+    /// <summary>
+    /// 是否不积极
+    /// </summary>
+    public bool? IsInactively { get; set; }
+
+    /// <summary>
+    /// 领导短信Key
+    /// </summary>
+    public string? LeaderSMSKey { get; set; }
+
+    /// <summary>
+    /// 是否市州转办
+    /// </summary>
+    public bool? Transpond { get; set; }
+
+    /// <summary>
+    /// 市州转办信息
+    /// </summary>
+    public string? TranspondCityName { get; set; }
+
+    /// <summary>
+    /// 市州转办信息
+    /// </summary>
+    public string? TranspondCityId { get; set; }
+
+    /// <summary>
+    /// 市州转办信息
+    /// </summary>
+    public string? TranspondCityValue { get; set; }
+
+    #endregion
 }

+ 8 - 0
src/Hotline.Share/Dtos/FlowEngine/PreviousWorkflowDto.cs

@@ -12,4 +12,12 @@ public class PreviousWorkflowDto : EndWorkflowIdDto
     /// </summary>
     public DateTime? ExpiredTime { get; set; }
 
+    /// <summary>
+    /// 根据办理者类型不同,此字段为不同内容
+    /// <example>
+    /// 部门等级/分类为:depCodes, 角色为:userIds
+    /// </example>
+    /// </summary>
+    public List<FlowStepHandler> NextHandlers { get; set; } = new();
+
 }

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

@@ -13,6 +13,10 @@
         /// </summary>
         public string Title { get; set; }
 
+        /// <summary>
+        /// 是否转办
+        /// </summary>
+        public bool IsForwarded { get; set; }
     }
 
     public class StartWorkflowDto<TData>

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/Workflow/StepBasicDto.cs

@@ -136,7 +136,7 @@ namespace Hotline.Share.Dtos.FlowEngine.Workflow
         /// <summary>
         /// 会签策略
         /// </summary>
-        public EDynamicPolicy? CountersignPolicy { get; set; }
+        public EDynamicPolicyCountersign? CountersignPolicy { get; set; }
 
         #endregion
 

+ 1 - 1
src/Hotline.Share/Dtos/Order/OrderBiDto.cs

@@ -316,7 +316,7 @@ namespace Hotline.Share.Dtos.Order
 		/// <summary>
 		/// 办结部门
 		/// </summary>
-		public string ActualHandleOrgName { get; set; }
+		public string CurrentHandleOrgName { get; set; }
 
 		/// <summary>
 		/// 受理时间

+ 35 - 10
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -481,7 +481,12 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? DelayText => DelayingCount > 0 ? "是" : "否";
 
-        private string CalculateExpiredText()
+        /// <summary>
+        /// 特提次数
+        /// </summary>
+        public int SpecialNum { get; set; }
+
+		private string CalculateExpiredText()
         {
             //todo 完整处理方案:1.创建待过期表,Id,过期时间,即将过期时间等字段。2.延迟消息通知处理过期,删除子表数据,处理order过期状态字段。3.此处即可采用expiredStatus进行判断
             //todo 目前暂时采用过期时间计算
@@ -675,7 +680,12 @@ namespace Hotline.Share.Dtos.Order
         /// 是否退回审批中
         /// </summary>
         public bool IsReturnUnderApproval {  get; set; }
-    }
+
+        /// <summary>
+        /// 退回截至时间
+        /// </summary>
+        public DateTime? SendBackAuditEndTime { get; set; }
+	}
 
     public class UpdateOrderDto : AddOrderDto
     {
@@ -830,12 +840,17 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public List<string>? DuplicateIds { get; set; }
 
-        /// <summary>
-        /// 推送分类
-        /// </summary>
-        public string? PushTypeCode { get; set; }
 
-        public string? PushType { get; set; }
+		/// <summary>
+		/// 推送分类 -- 弃用 转为表存储
+		/// </summary>
+		public string? PushTypeCode { get; set; }
+
+
+		/// <summary>
+		/// 推送分类 -- 弃用 转为表存储
+		/// </summary>
+		public string? PushType { get; set; }
 
         /// <summary>
         /// 附件
@@ -988,9 +1003,14 @@ namespace Hotline.Share.Dtos.Order
         public bool IsUrgent { get; set; }
 
         /// <summary>
-        /// 是否政民互动公开
+        /// 是否三方通话
         /// </summary>
-        public bool IsProvinceZmhd { get; set; }
+        public bool IsThreePartyConference { get; set; }
+
+		/// <summary>
+		/// 是否政民互动公开
+		/// </summary>
+		public bool IsProvinceZmhd { get; set; }
 
         /// <summary>
         /// 初审人姓名
@@ -1006,7 +1026,12 @@ namespace Hotline.Share.Dtos.Order
         /// 政民互动公开ID
         /// </summary>
         public string? OrderProvinceZmhdId { get; set; }
-    }
+
+        /// <summary>
+        /// 工单推送分类
+        /// </summary>
+        public List<OrderPushTypeDto>? OrderPushTypes { get; set; }
+	}
 
     public record CanLinkCallRecordOrderDto : PagedKeywordRequest
     {

+ 1 - 0
src/Hotline.Share/Dtos/Order/OrderPreviousDto.cs

@@ -5,4 +5,5 @@ namespace Hotline.Share.Dtos.Order;
 public class OrderPreviousDto : PreviousWorkflowDto
 {
     public string OrderId { get; set; }
+
 }

+ 26 - 0
src/Hotline.Share/Dtos/Order/OrderPushTypeDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Order
+{
+	public class OrderPushTypeDto
+	{
+		/// <summary>
+		/// 工单Id
+		/// </summary>
+		public string? OrderId { get; set; }
+
+		/// <summary>
+		/// 推送分类Code
+		/// </summary>
+		public string? PushTypeCode { get; set; }
+
+		/// <summary>
+		/// 推送分类名称
+		/// </summary>
+		public string? PushType { get; set; }
+	}
+}

+ 2 - 0
src/Hotline.Share/Dtos/Order/OrderSpecialDto.cs

@@ -456,6 +456,8 @@ namespace Hotline.Share.Dtos.Order
 
 	public class OrderReTransactDto : OrderSpecialAddDto
 	{
+		public ESpecialType? SpecialType { get; set; }
+
 		/// <summary>
 		/// 错件类型
 		/// </summary>

+ 4 - 1
src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs

@@ -11,7 +11,10 @@ namespace Hotline.Share.Dtos.Order
 {
     public class OrderStartFlowDto : StartWorkflowDto<string>
     {
-        
+        /// <summary>
+        /// 是否转办
+        /// </summary>
+        public bool IsForwarded { get; set; }
     }
 
     public class ScreenStartFlowDto : StartWorkflowDto<OrderScreenDto>

+ 165 - 4
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -59,10 +59,40 @@ namespace Hotline.Share.Dtos.Order
         /// 是否有效智能回访
         /// </summary>
         public bool? IsEffectiveAiVisit { get; set; }
+
+        /// <summary>
+        /// 来电号码
+        /// </summary>
+        public string? FromPhone { get; set; }
+
+        /// <summary>
+        /// 联系电话
+        /// </summary>
+        public string? Contact { get; set; }
+
+        /// <summary>
+        /// 语音评价(话务评价)
+        /// </summary>
+        public List<EVoiceEvaluate> VoiceEvaluate { get; set; } = new();
+
+        /// <summary>
+        /// 话务员评价(话务评价)
+        /// </summary>
+        public List<ESeatEvaluate> SeatEvaluate { get; set; } = new();
+
+        /// <summary>
+        /// 部门办件结果
+        /// </summary>
+        public List<string> OrgProcessingResults { get; set; } = new();
+
+        /// <summary>
+        /// 部门办件态度
+        /// </summary>
+        public List<string> OrgHandledAttitude { get; set; } = new();
     }
 
     public record QueryOrderPublishStatisticsAllDto : PagedRequest
-    { 
+    {
         /// <summary>
         /// 开始时间
         /// </summary>
@@ -77,7 +107,7 @@ namespace Hotline.Share.Dtos.Order
     }
 
     public record QueryOrderPublishStatisticsDto : PagedRequest
-    { 
+    {
         /// <summary>
         /// 开始时间
         /// </summary>
@@ -98,8 +128,8 @@ namespace Hotline.Share.Dtos.Order
     }
 
 
-    public record QueryOrderVisitSourceChannelDto 
-    { 
+    public record QueryOrderVisitSourceChannelDto
+    {
         /// <summary>
         /// 开始时间
         /// </summary>
@@ -232,6 +262,105 @@ namespace Hotline.Share.Dtos.Order
         public string UserId { get; set; }
     }
 
+    public class VisitSmsInDto
+    {
+        [Required]
+        public List<string> Ids { get; set; }
+    }
+
+    /// <summary>
+    /// 批量保存回访入参
+    /// </summary>
+    public class VisitBatchInDto
+    {
+        /// <summary>
+        /// 批量保存回访入参
+        /// </summary>
+        public class VisitIdsBatchInDto
+        {
+            /// <summary>
+            /// 工单Id
+            /// </summary>
+            [Required(ErrorMessage = "工单Id不能为空")]
+            public string OrderId { get; set; }
+
+            /// <summary>
+            /// 回访Id
+            /// </summary>
+            [Required(ErrorMessage = "回访Id不能为空")]
+            public string VisitId { get; set; }
+
+            /// <summary>
+            /// 工单标题
+            /// </summary>
+            [Required(ErrorMessage = "工单标题不能为空")]
+            public string No { get; set; }
+        }
+
+        /// <summary>
+        /// 回访Id集合
+        /// </summary>
+        [Required]
+        public List<VisitIdsBatchInDto> Visit { get; set; }
+
+        /// <summary>
+        /// 话务员评价(话务评价)
+        /// </summary>
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+
+        /// <summary>
+        /// 部门办件结果
+        /// </summary>
+        [Required(ErrorMessage = "部门办结结果不能为空")]
+        public Kv OrgProcessingResults { get; set; }
+
+        /// <summary>
+        /// 部门办件态度
+        /// </summary>
+        [Required(ErrorMessage = "部门办件态度不能为空")]
+        public Kv OrgHandledAttitude { get; set; }
+
+        /// <summary>
+        /// 不满意原因
+        /// </summary>
+        public List<Kv>? OrgNoSatisfiedReason { get; set; }
+
+        /// <summary>
+        /// 话务员回访内容
+        /// </summary>
+        [Required(ErrorMessage = "话务员回访内容不能为空")]
+        public string SeatVisitContent { get; set; }
+
+        /// <summary>
+        /// 部门回访内容
+        /// </summary>
+        [Required(ErrorMessage = "部门回访内容不能为空")]
+        public string OrgVisitContent { get; set; }
+    }
+
+    public class VisitBatchOutDto
+    {
+        /// <summary>
+        /// 总个数
+        /// </summary>
+        public int TotalCount { get; set; }
+
+        /// <summary>
+        /// 成功个数
+        /// </summary>
+        public int CompleteCount { get; set; }
+
+        /// <summary>
+        /// 异常个数
+        /// </summary>
+        public int ErrorCount { get; set; }
+
+        /// <summary>
+        /// 异常信息
+        /// </summary>
+        public string ErrorMessage { get; set; }
+    }
+
     public record VisitDto
     {
         /// <summary>
@@ -477,6 +606,20 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         [Description("未回访")]
         NoVisit = 2,
+
+        /// <summary>
+        /// 短信回访中
+        /// 逻辑需求(Task_317) : 操作了短信回访的工单,在没有短信结果回复前,回访状态需从“待回访”更新为“短信回访中”
+        /// </summary>
+        [Description("短信回访中")]
+        SMSVisiting = 21,
+
+        /// <summary>
+        /// 短信不满意待回访
+        /// 逻辑需求(Task_317) : 若短信回访结果为不满意,回访状态需从“短信回访中”更新为“短信不满意待回访”
+        /// </summary>
+        [Description("短信不满意待回访")]
+        SMSUnsatisfied = 41,
     }
 
     public class OrderVisitSourceChannelDto
@@ -712,6 +855,24 @@ namespace Hotline.Share.Dtos.Order
 
     }
 
+    /// <summary>
+    /// 回访详情的历史记录
+    /// </summary>
+    public class OrderVisitDetailHistiryDto
+    {
+        public EVoiceEvaluate? VoiceEvaluate { get; set; }
+        public string? VoiceEvaluateTxt => this.VoiceEvaluate?.GetDescription();
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+        public string? SeatEvaluateTxt => this.SeatEvaluate?.GetDescription();
+        public string VisitOrgName { get; set; }
+        public Kv? OrgProcessingResults { get; set; }
+        public string? orgProcessingResultsValue => this.OrgProcessingResults?.Value;
+        public Kv? OrgHandledAttitude { get; set; }
+        public string? OrgHandledAttitudeValue => this.OrgHandledAttitude?.Value;
+        public string? VisitContent { get; set; }
+        public DateTime? VisitTime { get; set; }
+    }
+
     public class DistributionVisitRspDto
     {
         public int SuccessCount { get; set; }

+ 1 - 1
src/Hotline.Share/Dtos/Order/OrderWaitedDto.cs

@@ -86,7 +86,7 @@ namespace Hotline.Share.Dtos.Order
         /// <summary>
         /// 接办部门
         /// </summary>
-        public string? CurrentHandleOrgName { get; set; }
+        public string? ActualHandleOrgName { get; set; }
 
         /// <summary>
         /// 状态

+ 28 - 15
src/Hotline.Share/Dtos/Order/PublishedDto.cs

@@ -30,14 +30,14 @@ public class PublishedDto
 
     public bool? Resolve { get; set; }
 
-	/// <summary>
-	/// 最近更新时间
-	/// </summary>
-	public DateTime? LastModificationTime { get; set; }
+    /// <summary>
+    /// 最近更新时间
+    /// </summary>
+    public DateTime? LastModificationTime { get; set; }
 }
 
 public class PublishedOrderStatisticsDto
-{ 
+{
     /// <summary>
     /// 待发布量
     /// </summary>
@@ -53,10 +53,23 @@ public class PublishedOrderStatisticsDto
     /// </summary>
     public int PrivateCount { get; set; }
 
+    //private int totalCount;
     /// <summary>
     /// 总量
     /// </summary>
-    public int TotalCount { get; set; }
+    public int TotalCount => WaitCount + PublicCount + PrivateCount;
+    //{
+    //    get
+    //    {
+    //        if (totalCount == 0)
+    //            return WaitCount + PublicCount + PrivateCount;
+    //        return totalCount;
+    //    }
+    //    set
+    //    {
+    //        totalCount = value;
+    //    }
+    //}
 
     /// <summary>
     /// 名字
@@ -75,7 +88,7 @@ public class PublishedOrderStatisticsDto
 }
 
 public class QueryPublishedOrderDataDto
-{ 
+{
     /// <summary>
     /// 发布人名称
     /// </summary>
@@ -407,10 +420,10 @@ public class SuperviseOrderDto
 
     public string StateText => State == 0 ? "待办未读" : State == 1 ? "已回复" : State == 2 ? "签收已读" : "-";
 
-	/// <summary>
-	/// 督办签收时间
-	/// </summary>
-	public DateTime? SignTime { get; set; }
+    /// <summary>
+    /// 督办签收时间
+    /// </summary>
+    public DateTime? SignTime { get; set; }
 
     /// <summary>
     /// 督办回复时间
@@ -505,10 +518,10 @@ public class UrgeOrderDto
 
     public string StateText => State == 0 ? "待办未读" : State == 1 ? "已回复" : State == 2 ? "签收已读" : "-";
 
-	/// <summary>
-	/// 催办签收时间
-	/// </summary>
-	public DateTime? SignTime { get; set; }
+    /// <summary>
+    /// 催办签收时间
+    /// </summary>
+    public DateTime? SignTime { get; set; }
 
     /// <summary>
     /// 催办回复时间

+ 6 - 0
src/Hotline.Share/Dtos/Order/QueryOrderDto.cs

@@ -58,6 +58,12 @@ namespace Hotline.Share.Dtos.Order
         public string? OrgId { get; set; }
         //public List<string> OrgCodes { get; set; } = new();
 
+        public string? OrgLevelOneName { get; set; }
+        /// <summary>
+        /// 接办名称(综合查询使用)
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
+
         /// <summary>
         /// 受理坐席名字或工号(×)
         /// </summary>

+ 30 - 0
src/Hotline.Share/Dtos/Order/SendBackDto.cs

@@ -25,6 +25,12 @@ namespace Hotline.Share.Dtos.Order
 		/// </summary>
 		public string? AuditContent { get; set; }
 
+
+		/// <summary>
+		/// 是否允许再次退回
+		/// </summary>
+		public bool? IsReturnAgain { get; set; }
+
 	}
 
 	public class BatchAuditSendBackDto : AuditSendBackDto {
@@ -91,6 +97,30 @@ namespace Hotline.Share.Dtos.Order
 		public ESendBackAuditState State { get; set; }
 
 		public string StateText => State.GetDescription();
+		/// <summary>
+		/// 退回节点名称
+		/// </summary>
+		public string? SendBackStepName { get; set; }
+
+		/// <summary>
+		/// 退回节点创建时间
+		/// </summary>
+		public DateTime? WorkflowStepSendBackCrTime { get; set; }
+
+		/// <summary>
+		///  退回时差
+		/// </summary>
+		public double SendBackTimeDifference => GetSendBackTimeDifference();
+
+		public double GetSendBackTimeDifference() {
+			if (WorkflowStepSendBackCrTime.HasValue)
+			{
+				TimeSpan? timeDifference = CreationTime - WorkflowStepSendBackCrTime;
+				return Math.Round(timeDifference.Value.TotalMinutes / 60, 1);
+			}
+			return 0;
+		}
+
 
 	}
 	public class SendBackBaseDto

+ 15 - 0
src/Hotline.Share/Dtos/Push/FWMessage/MessageDataDto.cs

@@ -95,5 +95,20 @@ namespace Hotline.Share.Dtos.Push.FWMessage
         /// 从发次数
         /// </summary>
         public int ResendCount { get; set; }
+
+        /// <summary>
+        /// 短信回复是否回复
+        /// </summary>   
+        public bool IsSmsReply { get; set; }
+
+        /// <summary>
+        /// 短信回复内容
+        /// </summary>   
+        public string? SmsReplyContent { get; set; }
+
+        /// <summary>
+        /// 短信回复时间
+        /// </summary>
+        public DateTime? SmsReplyTime { get; set; }
     }
 }

+ 32 - 1
src/Hotline.Share/Dtos/Push/MessagePagedDto.cs

@@ -1,4 +1,5 @@
-using Hotline.Share.Enums.Push;
+using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Enums.Push;
 using Hotline.Share.Requests;
 using XF.Utility.EnumExtensions;
 
@@ -157,4 +158,34 @@ namespace Hotline.Share.Dtos.Push
     {
         public string TaskId { get; set; }
     }
+
+    public class PublishLeaderSMSDto
+    {
+        public PublishLeaderSMSDto()
+        {
+            
+        }
+
+        public PublishLeaderSMSDto(string orderId, string dicDataName, string dicDataValue)
+        {
+            OrderId = orderId;
+            TelNumber = dicDataValue;
+            Name = dicDataName;
+        }
+
+        /// <summary>
+        /// 工单Id
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 接收手机号码
+        /// </summary>
+        public string TelNumber { get; set; }
+
+        /// <summary>
+        /// 接收人
+        /// </summary>
+        public string Name { get; set; }
+    }
 }

+ 6 - 0
src/Hotline.Share/Dtos/Settings/IsFuzzyQueryAttribute.cs

@@ -0,0 +1,6 @@
+
+namespace Hotline.Share.Dtos.Settings;
+
+public class IsFuzzyQueryAttribute : Attribute
+{
+}

+ 6 - 0
src/Hotline.Share/Dtos/Settings/NoCodeAttribute.cs

@@ -0,0 +1,6 @@
+
+namespace Hotline.Share.Dtos.Settings;
+
+public class NoCodeAttribute : Attribute
+{
+}

+ 20 - 0
src/Hotline.Share/Dtos/Settings/SystemDicDataDto.cs

@@ -0,0 +1,20 @@
+namespace Hotline.Share.Dtos.Settings
+{
+    public class SystemDicDataOutDto
+    {
+        /// <summary>
+        /// Id
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 字典名称
+        /// </summary>
+        public string DicDataName { get; set; }
+
+        /// <summary>
+        /// 字典值
+        /// </summary>
+        public string DicDataValue { get; set; }
+    }
+}

+ 79 - 2
src/Hotline.Share/Dtos/Settings/TimeConfig.cs

@@ -3,16 +3,64 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
+using Hotline.Share.Tools;
 using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Settings
 {
+    /// <summary>
+    /// 计算期满时间所需要的 工单信息
+    /// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+    /// !!!!!该类中的字段顺序很重要!!!!!!
+    /// 字段的顺序等于期满条件的优先级
+    /// 计算期满时间时, 会根据该类中字段顺序计算期满
+    /// </summary>
+    public class OrderTimeClacInfo
+    {
+        public const string BusCodeName = "AcceptTypeCode";
+
+        /// <summary>
+        /// 受理类型代码
+        /// </summary>
+        public string? AcceptTypeCode { get; set; }
+
+        /// <summary>
+        /// 流程方向
+        /// </summary>
+        public EFlowDirection FlowDirection { get; set; }
+
+        /// <summary>
+        /// 24小时办结
+        /// </summary>
+        [NoCode] // 不需要查询 BusCode
+        public bool Is24HoursComplete { get; set; }
+
+        /// <summary>
+        /// 热点分类类目名称
+        /// </summary>
+        [IsFuzzyQuery] // 模糊查询
+        [NoCode] // 不需要查询 BusCode
+        public string? HotspotSpliceName { get; set; }
+
+        /// <summary>
+        /// 来电/信人身份
+        /// </summary>
+        public EIdentityType? IdentityType { get; set; }
+
+        /// <summary>
+        /// 来源渠道
+        /// </summary>
+        public string? SourceChannel { get; set; }
+    }
+
     public class TimeConfig
     {
         public TimeConfig()
         {
-            
+
         }
 
         public TimeConfig(int count, ETimeType timeType)
@@ -24,12 +72,41 @@ namespace Hotline.Share.Dtos.Settings
 
         public int Count { get; set; }
         public ETimeType TimeType { get; set; }
-        public string TimeText { get; set; }
+
+        private string timeText;
+        public string TimeText
+        {
+            get
+            {
+                if (timeText.IsNullOrEmpty()) return $"{Count}个{TimeType.GetDescription()}";
+                return timeText;
+            }
+            set
+            {
+                timeText = value;
+            }
+        }
+
+        /// <summary>
+        /// 超期时限百分比
+        /// </summary>
+        public int Percentage { get; set; }
+
+        /// <summary>
+        /// 超期时间百分比(第一级)
+        /// </summary>
+        public int PercentageOne { get; set; }
+
+        /// <summary>
+        /// 工作时间
+        /// </summary>
+        public IList<string>? WorkTime { get; set; }
     }
 
     public class ExpiredTimeWithConfig : TimeConfig
     {
         public DateTime ExpiredTime { get; set; }
+
         /// <summary>
         /// 即将超期时间
         /// </summary>

+ 7 - 0
src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs

@@ -195,6 +195,13 @@ namespace Hotline.Share.Dtos.TrCallCenter
         public bool isCallOut { get; set; }
     }
 
+    public class TelOutDto
+    {
+        public string TelNo { get; set; }
+        public string TelPwd { get; set; }
+        public string Queue { get; set; }
+    }
+
     public class TrOnDutyResponseDto
     {
         public string? TelNo { get; set; }

+ 36 - 0
src/Hotline.Share/Enums/FlowEngine/EDynamicPolicy.cs

@@ -30,4 +30,40 @@ public enum EDynamicPolicy
     /// </summary>
     [Description("直属下级(中心作为一级部门)")]
     OrgDown = 3,
+
+	/// <summary>
+	/// 直属上级部门(中心作为顶级部门)经办人
+/// </summary>
+	[Description("直属上级(中心作为顶级部门) 经办人")]
+    OrgUpHandleCenterTop = 4,
+
+    /// <summary>
+    /// 直属上级(中心作为一级部门)
+    /// </summary>
+    [Description("直属上级(中心作为一级部门)经办人")]
+	OrgUpHandle = 5,
+
+	/// <summary>
+	/// 直属上级部门(中心作为顶级部门) 经办人与领导
+	/// </summary>
+	[Description("直属上级(中心作为顶级部门)经办人与领导")]
+    OrgUpLeadCenterTop = 6,
+
+	/// <summary>
+	/// 直属上级(中心作为一级部门)经办人与领导
+	/// </summary>
+	[Description("直属上级(中心作为一级部门)经办人与领导")]
+	OrgUpLead = 7,
+
+	/// <summary>
+	/// 直达中心
+	/// </summary>
+	[Description("直达中心")]
+    ArriveCenter= 8,
+
+	/// <summary>
+	/// 直达一级部门
+	/// </summary>
+	[Description("直达一级部门")]
+	ArriveOneOrg = 9,
 }

+ 33 - 0
src/Hotline.Share/Enums/FlowEngine/EDynamicPolicyCountersign.cs

@@ -0,0 +1,33 @@
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.FlowEngine;
+
+/// <summary>
+/// 动态实例化策略
+/// </summary>
+public enum EDynamicPolicyCountersign
+{
+    /// <summary>
+    /// 直属上级部门(中心作为顶级部门)
+    /// </summary>
+    [Description("直属上级(中心作为顶级部门)")]
+    OrgUpCenterTop = 0,
+
+    /// <summary>
+    /// 直属上级(中心作为一级部门)
+    /// </summary>
+    [Description("直属上级(中心作为一级部门)")]
+    OrgUp = 1,
+
+    /// <summary>
+    /// 直属下级部门(中心作为顶级部门)
+    /// </summary>
+    [Description("直属下级(中心作为顶级部门)")]
+    OrgDownCenterTop = 2,
+
+    /// <summary>
+    /// 直属下级(中心作为一级部门)
+    /// </summary>
+    [Description("直属下级(中心作为一级部门)")]
+    OrgDown = 3,
+}

+ 6 - 0
src/Hotline.Share/Enums/FlowEngine/EHandlerType.cs

@@ -33,4 +33,10 @@ public enum EHandlerType
     /// </summary>
     [Description("指定部门")]
     AssignedOrg = 4,
+
+    /// <summary>
+    /// 指定部门与角色
+    /// </summary>
+    [Description("指定部门与角色")]
+	AssignedOrgOrRole = 5,
 }

+ 10 - 10
src/Hotline.Share/Enums/Order/ESeatEvaluate.cs

@@ -14,11 +14,11 @@ namespace Hotline.Share.Enums.Order
         /// </summary>
         [Description("默认满意")]
         DefaultSatisfied = 0,
-        ///// <summary>
-        ///// 非常不满意
-        ///// </summary>
-        //[Description("非常不满意")]
-        //VeryNoSatisfied = 1,
+        /// <summary>
+        /// 非常不满意
+        /// </summary>
+        [Description("非常不满意")]
+        VeryNoSatisfied = 1,
 
         /// <summary>
         /// 不满意
@@ -26,11 +26,11 @@ namespace Hotline.Share.Enums.Order
         [Description("不满意")]
         NoSatisfied = 2,
 
-        ///// <summary>
-        ///// 一般
-        ///// </summary>
-        //[Description("一般")]
-        //Normal = 3,
+        /// <summary>
+        /// 一般
+        /// </summary>
+        [Description("一般")]
+        Normal = 3,
 
         /// <summary>
         /// 满意

+ 5 - 0
src/Hotline.Share/Enums/Order/ESource.cs

@@ -74,6 +74,11 @@ public enum ESource
     /// </summary>
     WLLZ = 404,
 
+    /// <summary>
+    /// 宜办事
+    /// </summary>
+    YBS = 405,
+
     #region 导入类型(>=500  <530为导入来源)
     /// <summary>
     /// 麻辣社区导入

+ 7 - 0
src/Hotline.Share/Enums/Order/ESpecialType.cs

@@ -17,5 +17,12 @@ namespace Hotline.Share.Enums.Order
 		/// 重办
 		/// </summary>
 		ReTransact = 2,
+
+
+
+		/// <summary>
+		/// 退回
+		/// </summary>
+		SendBack = 3,
 	}
 }

Деякі файли не було показано, через те що забагато файлів було змінено