فهرست منبع

merge conflict test -> release

xf 2 هفته پیش
والد
کامیت
1de591b657
100فایلهای تغییر یافته به همراه2704 افزوده شده و 1188 حذف شده
  1. 1 0
      .gitignore
  2. 33 16
      src/Hotline.Api/Controllers/Bi/BiCallController.cs
  3. 2 0
      src/Hotline.Api/Controllers/Bi/BiKnowledgeController.cs
  4. 396 362
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  5. 3 0
      src/Hotline.Api/Controllers/Bi/BiQualityController.cs
  6. 2 0
      src/Hotline.Api/Controllers/Bigscreen/DataScreenController.cs
  7. 3 1
      src/Hotline.Api/Controllers/Bigscreen/EnforcementScreenController.cs
  8. 3 1
      src/Hotline.Api/Controllers/Bigscreen/JudicialManagementScreenController.cs
  9. 3 1
      src/Hotline.Api/Controllers/Bigscreen/SeatController.cs
  10. 41 6
      src/Hotline.Api/Controllers/CallController.cs
  11. 3 1
      src/Hotline.Api/Controllers/CaseController.cs
  12. 3 1
      src/Hotline.Api/Controllers/ContingencyManagementController.cs
  13. 3 1
      src/Hotline.Api/Controllers/EnterpriseLuzhouController.cs
  14. 5 2
      src/Hotline.Api/Controllers/ExportWordController.cs
  15. 3 1
      src/Hotline.Api/Controllers/FileController.cs
  16. 4 2
      src/Hotline.Api/Controllers/HotSpotController.cs
  17. 3 2
      src/Hotline.Api/Controllers/IPPbxController.cs
  18. 4 2
      src/Hotline.Api/Controllers/IndustrialManagementController.cs
  19. 18 9
      src/Hotline.Api/Controllers/JudicialManagementOrdersController.cs
  20. 4 2
      src/Hotline.Api/Controllers/KnowledgeController.cs
  21. 413 117
      src/Hotline.Api/Controllers/OrderController.cs
  22. 13 5
      src/Hotline.Api/Controllers/OrderRevocationController.cs
  23. 258 251
      src/Hotline.Api/Controllers/OrderTerminateController.cs
  24. 2 1
      src/Hotline.Api/Controllers/OrgController.cs
  25. 3 1
      src/Hotline.Api/Controllers/PlanController.cs
  26. 15 13
      src/Hotline.Api/Controllers/PushMessageController.cs
  27. 1 1
      src/Hotline.Api/Controllers/QualityController.cs
  28. 3 2
      src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs
  29. 7 3
      src/Hotline.Api/Controllers/StatisticalReportController.cs
  30. 20 7
      src/Hotline.Api/Controllers/SysController.cs
  31. 4 2
      src/Hotline.Api/Controllers/TelRestController.cs
  32. 6 6
      src/Hotline.Api/Controllers/TestController.cs
  33. 2 1
      src/Hotline.Api/Controllers/UserController.cs
  34. 6 0
      src/Hotline.Api/Controllers/WebPortalController.cs
  35. 2 1
      src/Hotline.Api/Controllers/WorkflowController.cs
  36. BIN
      src/Hotline.Api/Documents/luzhou/泸州12345平台工单查询接口(V1.0-20250312) .docx
  37. BIN
      src/Hotline.Api/Documents/zigong/丰窝12345平台工单接入接口(V1.1-20250225) .docx
  38. 53 0
      src/Hotline.Api/Filter/ClientIpFilterAttribute.cs
  39. 62 0
      src/Hotline.Api/Filter/UserNameSessionContextFilter.cs
  40. 23 14
      src/Hotline.Api/Properties/launchSettings.json
  41. 25 13
      src/Hotline.Api/StartupExtensions.cs
  42. 3 0
      src/Hotline.Api/StartupHelper.cs
  43. 21 0
      src/Hotline.Api/config/appsettings.Test.json
  44. 51 50
      src/Hotline.Api/config/appsettings.json
  45. 2 2
      src/Hotline.Api/config/appsettings.shared.Development.json
  46. 2 2
      src/Hotline.Application/CallCenter/DefaultCallApplication.cs
  47. 1 0
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  48. 14 2
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  49. 1 0
      src/Hotline.Application/Handlers/FlowEngine/CancelHandler.cs
  50. 16 15
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  51. 8 10
      src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs
  52. 1 0
      src/Hotline.Application/Handlers/FlowEngine/WorkflowPreviousHandler.cs
  53. 1 0
      src/Hotline.Application/Handlers/FlowEngine/WorkflowStartHandler.cs
  54. 0 3
      src/Hotline.Application/Mappers/SnapshotMapperConfigs.cs
  55. 3 0
      src/Hotline.Application/OrderApp/IOrderApplication.cs
  56. 258 31
      src/Hotline.Application/OrderApp/OrderApplication.cs
  57. 3 3
      src/Hotline.Application/Quality/QualityApplication.cs
  58. 5 1
      src/Hotline.Application/Snapshot/IndustryApplication.cs
  59. 15 10
      src/Hotline.Application/Snapshot/RedPackApplication.cs
  60. 6 3
      src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs
  61. 83 60
      src/Hotline.Application/StatisticalReport/OrderReportApplication.cs
  62. 12 1
      src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs
  63. 22 2
      src/Hotline.Share/Dtos/Article/BulletinDto.cs
  64. 1 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  65. 4 0
      src/Hotline.Share/Dtos/FlowEngine/Workflow/PreviousWorkflowDto.cs
  66. 44 8
      src/Hotline.Share/Dtos/Order/OrderBiDto.cs
  67. 17 7
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  68. 36 1
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  69. 5 0
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  70. 2 2
      src/Hotline.Share/Dtos/Push/MessagePagedDto.cs
  71. 65 18
      src/Hotline.Share/Dtos/Snapshot/OrderDto.cs
  72. 9 0
      src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs
  73. 47 0
      src/Hotline.Share/Dtos/StatisticalReport/OrderDelayStatisicalReturnDto.cs
  74. 6 0
      src/Hotline.Share/Enums/FlowEngine/EHandleMode.cs
  75. 22 0
      src/Hotline.Share/Enums/Order/EOrderUpdateSource.cs
  76. 34 0
      src/Hotline.Share/Requests/PagedKeywordRequest.cs
  77. 6 5
      src/Hotline.WeChat/Hotline.WeChat.csproj
  78. 15 17
      src/Hotline.WeChat/ServiceCollectionExtensions.cs
  79. 5 0
      src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs
  80. 5 0
      src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs
  81. 9 2
      src/Hotline/Caching/Services/SysDicDataCacheManager.cs
  82. 25 3
      src/Hotline/Caching/Services/SystemSettingCacheManager.cs
  83. 12 0
      src/Hotline/Configurations/SenparcWeixinSetting.cs
  84. 13 1
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  85. 91 44
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  86. 21 4
      src/Hotline/Orders/Order.cs
  87. 7 1
      src/Hotline/Orders/OrderCopy.cs
  88. 1 21
      src/Hotline/Orders/OrderDomainService.cs
  89. 105 0
      src/Hotline/Orders/OrderPublishTemp.cs
  90. 2 1
      src/Hotline/Orders/OrderRevocation.cs
  91. 17 0
      src/Hotline/SeedData/SystemDicDataSeedData.cs
  92. 5 0
      src/Hotline/Settings/SettingConstants.cs
  93. 0 1
      src/Hotline/Settings/SysDicTypeConsts.cs
  94. 3 1
      src/Hotline/Snapshot/Services/SnapshotPointsDomainService.cs
  95. 2 2
      src/Hotline/Snapshot/SupplementRecord.cs
  96. 18 0
      src/Hotline/Validators/Ippbx/TrOnDutyDtoValidator.cs
  97. 23 1
      src/Hotline/dataview.md
  98. 9 0
      test/Hotline.Tests/Application/IndustryApplicationTest.cs
  99. 34 4
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs
  100. 1 1
      test/Hotline.Tests/Application/RedPackApplicationTest.cs

+ 1 - 0
.gitignore

@@ -348,3 +348,4 @@ healthchecksdb
 /merge_245_test.ps1
 /merge_dev.ps1
 /merge_snapshot_test.ps1
+/src/Hotline.Api/Properties/launchSettings.json

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

@@ -23,6 +23,7 @@ using Hotline.Settings;
 using XF.Utility.EnumExtensions;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers.Bi;
 
@@ -84,7 +85,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("calls_export")]
-    [AllowAnonymous]
+	[LogFilterAlpha("导出日志")]
+	[AllowAnonymous]
     public async Task<FileStreamResult> ExportQueryCallsAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
         => ExcelStreamResult(
             _exportApplication.GetExcelStream(
@@ -134,7 +136,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query_calls_statistics_export")]
-    public async Task<FileStreamResult> QueryCallsStatisticsExportAsync([FromBody] ExportExcelDto<StartEndTimeDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryCallsStatisticsExportAsync([FromBody] ExportExcelDto<StartEndTimeDto> dto)
     {
         var items = (await _callReportApplication.QueryCallsDetailStatisticsAsync(dto.QueryDto, HttpContext.RequestAborted));
         return _exportApplication.GetExcelFile(dto, items, "话务日期统计", "Date");
@@ -156,7 +159,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query_calls_statistics_detail/export")]
-    public async Task<FileStreamResult> QueryCallsStatisticsDetailAsync([FromBody] ExportExcelDto<QueryCallsStatisticsDetailInDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryCallsStatisticsDetailAsync([FromBody] ExportExcelDto<QueryCallsStatisticsDetailInDto> dto)
     {
         var items = (await _callReportApplication.QueryCallsStatisticsDetailAsync(dto.QueryDto, HttpContext.RequestAborted)).Item2;
         return _exportApplication.GetExcelFile(dto, items, "话务日期统计详情", "OrderNo");
@@ -214,7 +218,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query_calls_detail_export")]
-    public async Task<FileStreamResult> QueryCallsDetailExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryCallsDetailExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
     {
         return ExcelStreamResult(
             _exportApplication.GetExcelStream(
@@ -262,7 +267,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query_incall_calls_list_export")]
-    public async Task<FileStreamResult> GetInCallCallListExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> GetInCallCallListExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
     {
         var (total, data) = await _callReportApplication.QueryCallsDetailInTotalAsync(dto.QueryDto, dto.IsExportAll);
 
@@ -322,7 +328,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query_calls_hour_detail_list_export")]
-    public async Task<FileStreamResult> QueryCallsHourDetailListExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryCallsHourDetailListExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
         => ExcelStreamResult(
             _exportApplication.GetExcelStream(
                 dto,
@@ -356,7 +363,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("seats/export")]
-    public async Task<FileStreamResult> ExportSeatss([FromBody] ExportExcelDto<ReportRequiredPagedRequest> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> ExportSeatss([FromBody] ExportExcelDto<ReportRequiredPagedRequest> dto)
     {
         return ExcelStreamResult(
             _exportApplication.GetExcelStream(
@@ -451,7 +459,8 @@ public class BiCallController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpPost("hourcall/export")]
-    [AllowAnonymous]
+	[LogFilterAlpha("导出日志")]
+	[AllowAnonymous]
     public async Task<FileStreamResult> ExportQueryHourCall([FromBody] ExportExcelDto<BiQueryHourCallDto> dto)
         => ExcelStreamResult(
             _exportApplication.GetExcelStream(
@@ -489,7 +498,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("hourcall_list/export")]
-    public async Task<FileStreamResult> ExportQueryCallList([FromBody] ExportExcelDto<QueryCallListDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> ExportQueryCallList([FromBody] ExportExcelDto<QueryCallListDto> dto)
     {
 		foreach (var item in dto.ColumnInfos)
 		{
@@ -538,7 +548,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("gateway-query/export")]
-    public async Task<FileStreamResult> ExportQueryGatetWay(ExportExcelDto<BiQueryGateWayDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> ExportQueryGatetWay(ExportExcelDto<BiQueryGateWayDto> dto)
         => ExcelStreamResult(
             _exportApplication.GetExcelStream(
                 dto,
@@ -585,7 +596,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-calldate-statistics/export")]
-    public async Task<FileStreamResult> QueryCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
          =>
             _exportApplication.GetExcelFile(
                 dto,
@@ -618,7 +630,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-person-calldate-statistics/export")]
-    public async Task<FileStreamResult> QueryPersonCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryPersonCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
      => _exportApplication.GetExcelFile(
                 dto,
                 await _callReportApplication.QueryPersonCallDateStatisticsDetail(dto.QueryDto)
@@ -651,7 +664,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-enterprise-calldate-statistics/export")]
-    public async Task<FileStreamResult> QueryEnterpriseCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryEnterpriseCallDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
     => _exportApplication.GetExcelFile(
                 dto,
                 await _callReportApplication.QueryEnterpriseCallDateStatisticsDetail(dto.QueryDto)
@@ -692,7 +706,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-callout-date-statistics/export")]
-    public async  Task<FileStreamResult> QueryCallOutDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async  Task<FileStreamResult> QueryCallOutDateStatisticsDetailExport([FromBody]ExportExcelDto<QueryCallDateStatisticsDetailDto> dto)
     {
         List<string> enterpriseTels = _systemSettingCacheManager.GetSetting(SettingConstants.EnterpriseTel)?.SettingValue;
 
@@ -748,7 +763,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-seat-monthcall/export")]
-    public async Task<FileStreamResult> QuerySeatMonthCallExport([FromBody] ExportExcelDto<QuerySeatMonthCallRequest> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QuerySeatMonthCallExport([FromBody] ExportExcelDto<QuerySeatMonthCallRequest> dto)
     =>  _exportApplication.GetExcelFile(
             dto,              
             await _callReportApplication.QuerySeatMonthCall(dto.QueryDto)
@@ -774,7 +790,8 @@ public class BiCallController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("query-seat-monthcall-detail/export")]
-    public async Task<FileStreamResult> QuerySeatMonthCallDetailExport([FromBody] ExportExcelDto<QuerySeatMonthCallDetailRequest> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QuerySeatMonthCallDetailExport([FromBody] ExportExcelDto<QuerySeatMonthCallDetailRequest> dto)
     {
         var query = _callReportApplication.QuerySeatMonthCallDetail(dto.QueryDto);
         List<QuerySeatMonthCallDetailResp> data;

+ 2 - 0
src/Hotline.Api/Controllers/Bi/BiKnowledgeController.cs

@@ -13,6 +13,7 @@ using Hotline.Share.Requests;
 using Hotline.Tools;
 using MapsterMapper;
 using Org.BouncyCastle.Utilities;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers.Bi
 {
@@ -79,6 +80,7 @@ namespace Hotline.Api.Controllers.Bi
 		/// </summary>
 		/// <returns></returns>
 		[HttpPost("data_list/_export")]
+		[LogFilterAlpha("导出日志")]
 		public async Task<FileStreamResult> DataList([FromBody] ExportExcelDto<KnowledgeBiDataListDto> dto)
 		{
 			if (!dto.QueryDto.CreationTimeStart.HasValue || !dto.QueryDto.CreationTimeEnd.HasValue) 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 396 - 362
src/Hotline.Api/Controllers/Bi/BiOrderController.cs


+ 3 - 0
src/Hotline.Api/Controllers/Bi/BiQualityController.cs

@@ -17,6 +17,7 @@ using XF.Utility.EnumExtensions;
 using Hotline.Caching.Interfaces;
 using Hotline.Users;
 using XF.Domain.Repository;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers.Bi
 {
@@ -63,6 +64,7 @@ namespace Hotline.Api.Controllers.Bi
 		/// <param name="dto"></param>
 		/// <returns></returns>
 		[HttpPost("seats_quality_analyse/export")]
+		[LogFilterAlpha("导出日志")]
 		public async Task<FileStreamResult> SeatsQualityAnalyseExport([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
 		{
 			var query = _qualityApplication.SeatsQualityAnalyse(dto.QueryDto, HttpContext.RequestAborted);
@@ -114,6 +116,7 @@ namespace Hotline.Api.Controllers.Bi
 		/// <param name="dto"></param>
 		/// <returns></returns>
 		[HttpPost("quality_order_overview/export")]
+		[LogFilterAlpha("导出日志")]
 		public async Task<FileStreamResult> QualityOrderOverviewExport([FromBody] ExportExcelDto<QualityWorkAnalysisRequest> dto)
 		{
 			var allOrderNum = await _qualityRepository.Queryable().Where(x => x.Source == EQualitySource.Accepted && x.QualityTime >= dto.QueryDto.StartTime && x.QualityTime <= dto.QueryDto.EndTime && x.State == EQualityState.End).CountAsync();

+ 2 - 0
src/Hotline.Api/Controllers/Bigscreen/DataScreenController.cs

@@ -1,4 +1,5 @@
 using DocumentFormat.OpenXml.Drawing;
+using Hotline.Api.Filter;
 using Hotline.Caching.Interfaces;
 using Hotline.Configurations;
 using Hotline.KnowledgeBase;
@@ -22,6 +23,7 @@ using XF.Domain.Repository;
 
 namespace Hotline.Api.Controllers.Bigscreen
 {
+    [ServiceFilter(typeof(ClientIpFilterAttribute))]
     public class DataScreenController : BaseController
     {
         private readonly IOrderRepository _orderRepository;

+ 3 - 1
src/Hotline.Api/Controllers/Bigscreen/EnforcementScreenController.cs

@@ -1,4 +1,5 @@
-using Hotline.JudicialManagement;
+using Hotline.Api.Filter;
+using Hotline.JudicialManagement;
 using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Dtos.JudicialManagement;
@@ -14,6 +15,7 @@ namespace Hotline.Api.Controllers.Bigscreen
     /// <summary>
     /// 司法行政监督管理大屏  
     /// </summary>
+    [ServiceFilter(typeof(ClientIpFilterAttribute))]
     public class EnforcementScreenController : BaseController
     {
         private readonly IMapper _mapper;

+ 3 - 1
src/Hotline.Api/Controllers/Bigscreen/JudicialManagementScreenController.cs

@@ -1,4 +1,5 @@
-using Hotline.JudicialManagement;
+using Hotline.Api.Filter;
+using Hotline.JudicialManagement;
 using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Dtos.JudicialManagement;
@@ -14,6 +15,7 @@ namespace Hotline.Api.Controllers.Bigscreen
     /// <summary>
     /// 司法行政监督管理大屏
     /// </summary>
+    [ServiceFilter(typeof(ClientIpFilterAttribute))]
     public class JudicialManagementScreenController : BaseController
     {
         private readonly IMapper _mapper;

+ 3 - 1
src/Hotline.Api/Controllers/Bigscreen/SeatController.cs

@@ -1,4 +1,5 @@
-using Hotline.Application.Bigscreen;
+using Hotline.Api.Filter;
+using Hotline.Application.Bigscreen;
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Tels;
 using Hotline.CallCenter.Tels.CallTelDomain;
@@ -11,6 +12,7 @@ using Microsoft.AspNetCore.Mvc;
 
 namespace Hotline.Api.Controllers.Bigscreen
 {
+    [ServiceFilter(typeof(ClientIpFilterAttribute))]
     public class SeatController : BaseController
     {
         private readonly ISeatStateDataService _seatStateDataService;

+ 41 - 6
src/Hotline.Api/Controllers/CallController.cs

@@ -24,6 +24,9 @@ using MapsterMapper;
 using SqlSugar;
 using Hotline.Api.Filter;
 using Microsoft.AspNetCore.Authorization;
+using Hotline.Share.Dtos.Order;
+using Hotline.Tools;
+using XF.Domain.Authentications;
 
 namespace Hotline.Api.Controllers
 {
@@ -138,12 +141,44 @@ namespace Hotline.Api.Controllers
         public async Task<int> QueryCallsFixedCount([FromQuery] QueryCallsFixedDto dto)
             => await _callApplication.QueryCallsFixedAsync(dto, HttpContext.RequestAborted).CountAsync(HttpContext.RequestAborted);
 
-        /// <summary>
-        /// 查询通话记录
-        /// </summary>
-        /// <param name="callId"></param>
-        /// <returns></returns>
-        [HttpGet("{callId}")]
+		/// <summary>
+		/// 导出通话记录
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpPost("calls-fixed/export")]
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryCallsFixedDto> dto)
+		{
+			var query = _callApplication.QueryCallsFixedAsync(dto.QueryDto, HttpContext.RequestAborted);
+			List<CallNativeDto> callls;
+			if (dto.IsExportAll)
+			{
+				callls = await query.ToListAsync(HttpContext.RequestAborted);
+			}
+			else
+			{
+				var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+				callls = items;
+			}
+			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<CallNativeDto>(dto.ColumnInfos);
+
+			var dtos = callls
+				.Select(stu => _mapper.Map(stu, typeof(CallNativeDto), dynamicClass))
+				.Cast<object>()
+				.ToList();
+
+			var stream = ExcelHelper.CreateStream(dtos);
+
+			return ExcelStreamResult(stream, "通话记录");
+		}
+
+		/// <summary>
+		/// 查询通话记录
+		/// </summary>
+		/// <param name="callId"></param>
+		/// <returns></returns>
+		[HttpGet("{callId}")]
         public Task<List<CallNative>> GetCall(string callId)
         {
             //为兼容天润通话记录返回集合

+ 3 - 1
src/Hotline.Api/Controllers/CaseController.cs

@@ -16,6 +16,7 @@ using Hotline.Share.Enums.Article;
 using XF.Utility.EnumExtensions;
 using Hotline.Share.Dtos.Order;
 using Hotline.Application.ExportExcel;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers
 {
@@ -462,7 +463,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("list/info/export")]
-        public async Task<IActionResult> CaseInfoExport([FromBody] CaseInfoExportDto dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<IActionResult> CaseInfoExport([FromBody] CaseInfoExportDto dto)
         {
             if (dto.Ids.Length > 1)
             {

+ 3 - 1
src/Hotline.Api/Controllers/ContingencyManagementController.cs

@@ -1,4 +1,5 @@
 using DotNetCore.CAP;
+using Hotline.Api.Filter;
 using Hotline.ContingencyManagement;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Share.Dtos;
@@ -69,7 +70,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getlist_export")]
-        public async Task<FileStreamResult> GetListExport([FromBody] ExportExcelDto<ContingencyManagementPagedKeywordRequest> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetListExport([FromBody] ExportExcelDto<ContingencyManagementPagedKeywordRequest> dto)
         {
             var query = _contingencyManagementOrdersRepository.Queryable()
                 .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Title), p => p.ArrangeTitle.Contains(dto.QueryDto.Title))

+ 3 - 1
src/Hotline.Api/Controllers/EnterpriseLuzhouController.cs

@@ -13,6 +13,7 @@ using Hotline.Repository.SqlSugar.Extensions;
 using MapsterMapper;
 using Microsoft.Extensions.Options;
 using XF.Domain.Repository;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers
 {
@@ -120,7 +121,8 @@ namespace Hotline.Api.Controllers
         /// 导出企业专员工单
         /// </summary>
         [HttpPost("specialist/orders/export")]
-        public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
         {
             var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto.QueryDto, HttpContext.RequestAborted);
             List<Order> orders;

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

@@ -1,4 +1,5 @@
-using Hotline.Application.ExportWord;
+using Hotline.Api.Filter;
+using Hotline.Application.ExportWord;
 using Hotline.Caching.Interfaces;
 using Hotline.Configurations;
 using Hotline.Orders;
@@ -56,7 +57,8 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpPost("order_submission_form")]
-        public async Task<IActionResult> OrderSubmissionForm([FromBody] List<string> Ids)
+		[LogFilterAlpha("导出日志")]
+		public async Task<IActionResult> OrderSubmissionForm([FromBody] List<string> Ids)
         {
             var streams = new Dictionary<string, Stream>();
             var path = $"{Directory.GetCurrentDirectory()}/Template/AssignmentForm.doc";
@@ -136,6 +138,7 @@ namespace Hotline.Api.Controllers
         /// <param name="Ids"></param>
         /// <returns></returns>
 		[HttpPost("quality_certificate")]
+		[LogFilterAlpha("导出日志")]
 		public async Task<IActionResult> QualityCertificate([FromBody] List<string> Ids) {
 
 			var streams = new Dictionary<string, Stream>();

+ 3 - 1
src/Hotline.Api/Controllers/FileController.cs

@@ -16,6 +16,7 @@ using Hotline.Share.Requests;
 using SqlSugar;
 using Hotline.Tools;
 using Hotline.Share.Dtos.Order;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers
 {
@@ -247,7 +248,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getaudiofileslist/export")]
-        public async Task<FileStreamResult> ExportGetAudioFilesList([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> ExportGetAudioFilesList([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
         {
             var query = _uploadAudioFilesRepository.Queryable()
                 .Where(p => p.CreationTime >= dto.QueryDto.StartTime && p.CreationTime <= dto.QueryDto.EndTime)

+ 4 - 2
src/Hotline.Api/Controllers/HotSpotController.cs

@@ -1,4 +1,5 @@
-using Hotline.Application.ExportExcel;
+using Hotline.Api.Filter;
+using Hotline.Application.ExportExcel;
 using Hotline.Caching.Interfaces;
 using Hotline.FlowEngine;
 using Hotline.Repository.SqlSugar.Extensions;
@@ -139,7 +140,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("event/tree/export")]
-        public async Task<FileStreamResult> GetEventAllTreeExport([FromBody]ExportExcelDto<string> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetEventAllTreeExport([FromBody]ExportExcelDto<string> dto)
         {
             var items = await _eventCategoryRepository.Queryable()
                 .OrderBy(d => d.OrderBy)

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

@@ -601,7 +601,7 @@ namespace Hotline.Api.Controllers
                             }
                             catch (Exception e)
                             {
-                                _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                                _logger.LogError($"写入智能质检异常2!, \r\n{e.Message}");
                             }
 
                         }
@@ -708,7 +708,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("calls/call-list/export")]
-        public async Task<FileStreamResult> GetCallListExport([FromBody] ExportExcelDto<GetCallListDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetCallListExport([FromBody] ExportExcelDto<GetCallListDto> dto)
         {
             var query = _callRecordRepository.GetCallList(dto.QueryDto);
             List<TrCallRecord> data;

+ 4 - 2
src/Hotline.Api/Controllers/IndustrialManagementController.cs

@@ -205,7 +205,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getindustrialmanagementlist_export")]
-        public async Task<FileStreamResult> GetIndustrialManagementListExport([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetIndustrialManagementListExport([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
         {
             var query = _industryClassificationApplication.GetIndustrialManagementList(dto.QueryDto);
 
@@ -248,7 +249,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("industrial-orders-export")]
-        public async Task<FileStreamResult> GetIndustrialManagementOrderListExport([FromBody] ExportExcelDto<IndustrialManagementRequestDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetIndustrialManagementOrderListExport([FromBody] ExportExcelDto<IndustrialManagementRequestDto> dto)
         {
             var query = _industryClassificationApplication.GetIndustrialManagementOrderList(dto.QueryDto);
 

+ 18 - 9
src/Hotline.Api/Controllers/JudicialManagementOrdersController.cs

@@ -305,7 +305,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getownorderlist_export")]
-        public async Task<FileStreamResult> GetOwnOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetOwnOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
         {
             var query = _enforcementApplication.GetOwnOrderList(dto.QueryDto);
             List<JudicialManagementOrders> data;
@@ -360,7 +361,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getorderlist_export")]
-        public async Task<FileStreamResult> GetOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetOrderListExport([FromBody] ExportExcelDto<QueryEnforcementOrderNewDto> dto)
         {
             var query = _enforcementApplication.GetOrderList(dto.QueryDto);
             List<JudicialManagementOrders> data;
@@ -611,7 +613,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("event_classification_statistics_order_list_export")]
-        public async Task<FileStreamResult> GetEventClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryEventClassificationStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetEventClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryEventClassificationStatisticsDto> dto)
         {
             var query = _enforcementApplication.GetEventClassificationStatisticsOrderListAsync(dto.QueryDto);
             List<JudicialManagementOrders> data;
@@ -657,7 +660,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("enforcement_departmental_processing_statistics_export")]
-        public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
         {
             var list = await _enforcementApplication.GetDepartmentalProcessingStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime).ToListAsync();
 
@@ -701,7 +705,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("enforcement_departmental_processing_statistics_order_list_export")]
-        public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetDepartmentalProcessingStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryDepartmentalProcessingStatisticsDto> dto)
         {
             var query = _enforcementApplication.GetDepartmentalProcessingStatisticsOrderListAsync(dto.QueryDto);
             List<EnforcementOrderListDto> data;
@@ -742,7 +747,8 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpPost("regional_classification_statistics_export")]
-        public async Task<FileStreamResult> GetRegionalClassificationStatisticsExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetRegionalClassificationStatisticsExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
         {
             var list = await _enforcementApplication.GetRegionalClassificationStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime).ToListAsync();
 
@@ -784,7 +790,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("regional_classification_statistics_order_list_export")]
-        public async Task<FileStreamResult> GetRegionalClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetRegionalClassificationStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryRegionalClassificationStatisticsDto> dto)
         {
             var query = _enforcementApplication.GetRegionalClassificationStatisticsOrderListAsync(dto.QueryDto);
             List<JudicialManagementOrders> data;
@@ -844,7 +851,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("enforcement_visit_org_satisfaction_statistics_export")]
-        public async Task<object> GetVisitAndOrgSatisfactionStatisticsExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<object> GetVisitAndOrgSatisfactionStatisticsExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
         {
             var list = await _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsAsync(dto.QueryDto.StartTime, dto.QueryDto.EndTime, dto.QueryDto.TypeId).ToListAsync();
 
@@ -890,7 +898,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("enforcement_visit_org_satisfaction_statistics_order_list_export")]
-        public async Task<FileStreamResult> GetVisitAndOrgSatisfactionStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetVisitAndOrgSatisfactionStatisticsOrderListExportAsync([FromBody] ExportExcelDto<QueryOrgSatisfactionStatisticsDto> dto)
         {
             var query = _enforcementApplication.GetVisitAndOrgSatisfactionStatisticsOrderListAsync(dto.QueryDto);
             List<EnforcementOrgSatisfactionOrderListDto> data;

+ 4 - 2
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -752,7 +752,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("info/export")]
-        public async Task<IActionResult> KnowledgeInfoExport([FromBody] KnowledgeInfoExportInDto dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<IActionResult> KnowledgeInfoExport([FromBody] KnowledgeInfoExportInDto dto)
         {
             if (dto.Ids.Length > 1)
             {
@@ -1837,7 +1838,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("pageview/export")]
-        public async Task<FileStreamResult> GetPageViewListAsync([FromBody] ExportExcelDto<PageViewInDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetPageViewListAsync([FromBody] ExportExcelDto<PageViewInDto> dto)
         {
             var items = (await _knowApplication.GetPageViewListAsync(dto.QueryDto, HttpContext.RequestAborted))
                 .Item2;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 413 - 117
src/Hotline.Api/Controllers/OrderController.cs


+ 13 - 5
src/Hotline.Api/Controllers/OrderRevocationController.cs

@@ -1,5 +1,6 @@
 using Hotline.Application.FlowEngine;
 using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Orders;
@@ -16,6 +17,7 @@ using Hotline.Users;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
 using MongoDB.Driver;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
@@ -35,9 +37,10 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<User> _userRepository;
         private readonly IMediator _mediator;
         private readonly IWorkflowDomainService _workflowDomainService;
+		private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
 
-        public OrderRevocationController(IMapper mapper,
+		public OrderRevocationController(IMapper mapper,
             IRepository<OrderRevocation> orderRevocationRepository,
             IRepository<Order> orderRepository,
             ISessionContext sessionContext,
@@ -46,7 +49,8 @@ namespace Hotline.Api.Controllers
             IRepository<SystemOrganize> systemOrganizeRepository,
             IRepository<User> userRepository,
             IMediator mediator,
-            IWorkflowDomainService workflowDomainService)
+            IWorkflowDomainService workflowDomainService,
+			IOptionsSnapshot<AppConfiguration> appOptions)
         {
             _mapper = mapper;
             _orderRevocationRepository = orderRevocationRepository;
@@ -58,7 +62,8 @@ namespace Hotline.Api.Controllers
             _userRepository = userRepository;
             _mediator = mediator;
             _workflowDomainService = workflowDomainService;
-        }
+			_appOptions = appOptions;
+		}
 
         /// <summary>
         /// 撤销件处理
@@ -158,8 +163,11 @@ namespace Hotline.Api.Controllers
                             }
                             else
                             {
-                                await _workflowDomainService.JumpToEndAsync(_sessionContext, order.WorkflowId, dto.RevocationReason,
-                                    null, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);
+                                if (_appOptions.Value.IsLuZhou)
+                                {
+									await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, dto.RevocationReason, order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Revocation, cancellationToken: HttpContext.RequestAborted);
+								}
+								await _workflowDomainService.JumpToEndAsync(_sessionContext, order.WorkflowId, dto.RevocationReason,null, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted);
                             }
 
                             #endregion

+ 258 - 251
src/Hotline.Api/Controllers/OrderTerminateController.cs

@@ -28,285 +28,292 @@ using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Requests;
 using Hotline.Tools;
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
 
 namespace Hotline.Api.Controllers
 {
-	/// <summary>
-	/// 终止管理
-	/// </summary>
-	public class OrderTerminateController : BaseController
-	{
-		private readonly ISessionContext _sessionContext;
-		private readonly IMapper _mapper;
-		private readonly IFileRepository _fileRepository;
-		private readonly IWorkflowApplication _workflowApplication;
-		private readonly IRepository<Workflow> _workflowRepository;
-		private readonly IWorkflowDomainService _workflowDomainService;
-		private readonly IOrderRepository _orderRepository;
-		private readonly IOrderDomainService _orderDomainService;
-		private readonly IOrderTerminateRepository _orderTerminateRepository;
-		private readonly IOrderApplication _orderApplication;
+    /// <summary>
+    /// 终止管理
+    /// </summary>
+    public class OrderTerminateController : BaseController
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+        private readonly IFileRepository _fileRepository;
+        private readonly IWorkflowApplication _workflowApplication;
+        private readonly IRepository<Workflow> _workflowRepository;
+        private readonly IWorkflowDomainService _workflowDomainService;
+        private readonly IOrderRepository _orderRepository;
+        private readonly IOrderDomainService _orderDomainService;
+        private readonly IOrderTerminateRepository _orderTerminateRepository;
+        private readonly IOrderApplication _orderApplication;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
-		public OrderTerminateController(
-			ISessionContext sessionContext,
-			IMapper mapper,
-			IFileRepository fileRepository,
-			IWorkflowApplication workflowApplication,
-			IRepository<Workflow> workflowRepository,
-			IWorkflowDomainService workflowDomainService,
-			IOrderRepository orderRepository,
-			IOrderDomainService orderDomainService,
-			IOrderTerminateRepository orderTerminateRepository,
-			IOrderApplication orderApplication
-			) 
-		{ 
-			_sessionContext = sessionContext;
-			_mapper = mapper;
-			_fileRepository = fileRepository;
-			_workflowApplication = workflowApplication;
-			_workflowRepository = workflowRepository;
-			_workflowDomainService = workflowDomainService;
-			_orderRepository = orderRepository;
-			_orderDomainService = orderDomainService;
-			_orderTerminateRepository = orderTerminateRepository;
-			_orderApplication= orderApplication;
-		}
+        public OrderTerminateController(
+            ISessionContext sessionContext,
+            IMapper mapper,
+            IFileRepository fileRepository,
+            IWorkflowApplication workflowApplication,
+            IRepository<Workflow> workflowRepository,
+            IWorkflowDomainService workflowDomainService,
+            IOrderRepository orderRepository,
+            IOrderDomainService orderDomainService,
+            IOrderTerminateRepository orderTerminateRepository,
+            IOrderApplication orderApplication,
+             IOptionsSnapshot<AppConfiguration> appOptions
+            )
+        {
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+            _fileRepository = fileRepository;
+            _workflowApplication = workflowApplication;
+            _workflowRepository = workflowRepository;
+            _workflowDomainService = workflowDomainService;
+            _orderRepository = orderRepository;
+            _orderDomainService = orderDomainService;
+            _orderTerminateRepository = orderTerminateRepository;
+            _orderApplication = orderApplication;
+            _appOptions = appOptions;
 
-		/// <summary>
-		/// 工单终止待申请列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("may-terminate")]
-		public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
-		{
-			var isAdmin = _orderDomainService.IsCheckAdmin();
-			var (total, items) =await _orderRepository.Queryable(isAdmin:isAdmin)
-				.Includes(d=>d.OrderTerminates)
-				.Where(d=> SqlFunc.Subqueryable<OrderTerminate>().Where(t=> t.OrderId  == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
-				.Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
-				.WhereIF(!string.IsNullOrEmpty(dto.No),d=>d.No!.Contains(dto.No!))
-				.WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
-				.WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
-					d => d.OrderTerminates.Any(t=>t.CreationTime >= dto.ApplyStartTime && t.CreationTime<= dto.ApplyEndTime))
-				.WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue,d=>d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
-				.OrderByDescending(d => d.StartTime)
-				.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>
+        [HttpGet("may-terminate")]
+        public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
+        {
+            var isAdmin = _orderDomainService.IsCheckAdmin();
+            var (total, items) = await _orderRepository.Queryable(isAdmin: isAdmin)
+                .Includes(d => d.OrderTerminates)
+                .WhereIF(_appOptions.Value.IsZiGong, d => d.Source != ESource.ProvinceStraight)//自贡任务  495 终止申请页面只显示市工单
+                .Where(d => SqlFunc.Subqueryable<OrderTerminate>().Where(t => t.OrderId == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
+                .Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
+                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
+                .WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
+                    d => d.OrderTerminates.Any(t => t.CreationTime >= dto.ApplyStartTime && t.CreationTime <= dto.ApplyEndTime))
+                .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
+                .OrderByDescending(d => d.StartTime)
+                .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>
-		[HttpGet]
-		public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
-		{
-			var (total, items) = await _orderApplication.OrderTerminateList(dto)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
-		}
 
-		/// <summary>
-		/// 工单终止列表导出
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
+        /// <summary>
+        /// 工单终止列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet]
+        public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
+        {
+            var (total, items) = await _orderApplication.OrderTerminateList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
+        }
 
-		[HttpPost("export")]
-		public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
-		{
-			var query = _orderApplication.OrderTerminateList(dto.QueryDto);
-			List<OrderTerminate> data;
-			if (dto.IsExportAll)
-			{
-				data = await query.ToListAsync(HttpContext.RequestAborted);
-			}
-			else
-			{
-				var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
-				data = items;
-			}
+        /// <summary>
+        /// 工单终止列表导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
 
-			var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);
+        [HttpPost("export")]
+        public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
+        {
+            var query = _orderApplication.OrderTerminateList(dto.QueryDto);
+            List<OrderTerminate> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
 
-			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);
+            var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);
 
-			var dtos = dataDtos
-				.Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
-				.Cast<object>()
-				.ToList();
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);
 
-			var stream = ExcelHelper.CreateStream(dtos);
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
 
-			return ExcelStreamResult(stream, "工单终止列表");
-		}
+            var stream = ExcelHelper.CreateStream(dtos);
 
+            return ExcelStreamResult(stream, "工单终止列表");
+        }
 
-		/// <summary>
-		/// 开始工单终止流程
-		/// </summary>
-		[HttpPost("startflow")]
-		[LogFilter("开始工单终止流程")]
-		public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
-		{
-			var screenAny = await _orderTerminateRepository.AnyAsync(x =>
-				x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
-			if (screenAny)
-				throw UserFriendlyException.SameMessage("该工单已提起终止申请,正在审批过程中,不能申请");
 
-			var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status ==  ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
-			if (isNoPass)
-				throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请,不能再次申请");
+        /// <summary>
+        /// 开始工单终止流程
+        /// </summary>
+        [HttpPost("startflow")]
+        [LogFilter("开始工单终止流程")]
+        public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
+        {
+            var screenAny = await _orderTerminateRepository.AnyAsync(x =>
+                x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
+            if (screenAny)
+                throw UserFriendlyException.SameMessage("该工单已提起终止申请,正在审批过程中,不能申请");
 
-			var model = _mapper.Map<OrderTerminate>(dto.Data);
-			model.Status = ETerminateStatus.Approval ;
-			model.InitId();
-			if (dto.Data.Files.Any())
-				model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
-			else
-				model.FileJson = new List<Share.Dtos.File.FileJson>();
-			await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
-			try
-			{
-				var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
-				startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
-				startDto.Opinion = dto.Data.Content;
-				startDto.Title = "申请终止流程";
-				// await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-				// await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-				await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-			}
-			catch (Exception e)
-			{
-				await _orderTerminateRepository.RemoveAsync(model.Id);
-				model.Id = string.Empty;
-				throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
-			}
-		}
+            var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status == ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
+            if (isNoPass)
+                throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请,不能再次申请");
 
+            var model = _mapper.Map<OrderTerminate>(dto.Data);
+            model.Status = ETerminateStatus.Approval;
+            model.InitId();
+            if (dto.Data.Files.Any())
+                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
+            else
+                model.FileJson = new List<Share.Dtos.File.FileJson>();
+            await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
+            try
+            {
+                var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
+                startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
+                startDto.Opinion = dto.Data.Content;
+                startDto.Title = "申请终止流程";
+                // await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+                // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+                await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+            }
+            catch (Exception e)
+            {
+                await _orderTerminateRepository.RemoveAsync(model.Id);
+                model.Id = string.Empty;
+                throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
+            }
+        }
 
-		/// <summary>
-		/// 工单终止修改后下一步流程
-		/// </summary>
-		[HttpPost("initial_nextFlow")]
-		[LogFilter("办理工单终止流程")]
-		public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
-		{
-			var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);
 
-			if (dto.Data.Files.Any())
-				model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
-			else
-				model.FileJson = new List<Share.Dtos.File.FileJson>();
+        /// <summary>
+        /// 工单终止修改后下一步流程
+        /// </summary>
+        [HttpPost("initial_nextFlow")]
+        [LogFilter("办理工单终止流程")]
+        public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
+        {
+            var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);
 
-			model.Status = ETerminateStatus.Approval;
-			model.Content = dto.Data.Content;
-			model.IsRecommit = true;
-			await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
-			try
-			{
-				dto.NextWorkflow.WorkflowId = model.WorkflowId;
-				await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
-			}
-			catch (Exception e)
-			{
-				throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
-			}
-		}
+            if (dto.Data.Files.Any())
+                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
+            else
+                model.FileJson = new List<Share.Dtos.File.FileJson>();
 
-		/// <summary>
-		/// 查询工单终止流程开启参数
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("screen/startflow")]
-		public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
-		{
-			return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
-				HttpContext.RequestAborted);
-		}
+            model.Status = ETerminateStatus.Approval;
+            model.Content = dto.Data.Content;
+            model.IsRecommit = true;
+            await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
+            try
+            {
+                dto.NextWorkflow.WorkflowId = model.WorkflowId;
+                await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
+            }
+            catch (Exception e)
+            {
+                throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
+            }
+        }
 
-		/// <summary>
-		/// 查询工单终止流程参数
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("workflow/{id}")]
-		public async Task<string> GetTerminateWorkFlowAsync(string id)
-		{
-			var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
-			return workflow.Id;
-		}
+        /// <summary>
+        /// 查询工单终止流程开启参数
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("screen/startflow")]
+        public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
+        {
+            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
+                HttpContext.RequestAborted);
+        }
 
-		/// <summary>
-		///  甄别查询流程办理下一步可选节点
-		/// </summary>
-		/// <param name="workflowId"></param>
-		/// <returns></returns>
-		[HttpGet("{workflowId}/nextsteps")]
-		public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
-		{
-			return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
-		}
+        /// <summary>
+        /// 查询工单终止流程参数
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("workflow/{id}")]
+        public async Task<string> GetTerminateWorkFlowAsync(string id)
+        {
+            var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
+            return workflow.Id;
+        }
 
-		/// <summary>
-		/// 终止详情
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("{id}")]
-		public async Task<OrderTerminateEntityDto> Entity(string id)
-		{
-			var model = await _orderTerminateRepository.Queryable()
-				.Includes(x => x.Order) 
-				.Includes(x => x.Workflow, d => d.Steps)
-				.FirstAsync(x => x.Id == id);
-			var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
-			rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
-				_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
-			if (model.Status ==  ETerminateStatus.SendBackStart)
-				rspModel.IsCanHandle = false;
-			rspModel.Handle = false;
-			if (!string.IsNullOrEmpty(rspModel.WorkflowId))
-			{
-				rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
-					_sessionContext.RequiredOrgId, HttpContext.RequestAborted);
-			}
+        /// <summary>
+        ///  甄别查询流程办理下一步可选节点
+        /// </summary>
+        /// <param name="workflowId"></param>
+        /// <returns></returns>
+        [HttpGet("{workflowId}/nextsteps")]
+        public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
+        {
+            return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
+        }
 
-			if (rspModel.FileJson != null && rspModel.FileJson.Any())
-			{
-				var ids = rspModel.FileJson.Select(x => x.Id).ToList();
-				rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
-			}
-			return rspModel;
-		}
+        /// <summary>
+        /// 终止详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("{id}")]
+        public async Task<OrderTerminateEntityDto> Entity(string id)
+        {
+            var model = await _orderTerminateRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.Workflow, d => d.Steps)
+                .FirstAsync(x => x.Id == id);
+            var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
+            rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
+                _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
+            if (model.Status == ETerminateStatus.SendBackStart)
+                rspModel.IsCanHandle = false;
+            rspModel.Handle = false;
+            if (!string.IsNullOrEmpty(rspModel.WorkflowId))
+            {
+                rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
+                    _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
+            }
 
-		/// <summary>
-		/// 列表页面基础数据
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("base")]
-		public async Task<object> BaseData()
-		{
-			var rsp = new
-			{
-				Status = EnumExts.GetDescriptions<ETerminateStatus>(),
-			};
-			return rsp;
-		}
+            if (rspModel.FileJson != null && rspModel.FileJson.Any())
+            {
+                var ids = rspModel.FileJson.Select(x => x.Id).ToList();
+                rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+            }
+            return rspModel;
+        }
 
-		/// <summary>
-		/// 终止修改理由
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut("update_content")]
-		[LogFilter("终止修改理由")]
-		public async Task Update([FromBody] OrderTerminateContentDto dto)
-		{
-			await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
-		}
+        /// <summary>
+        /// 列表页面基础数据
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("base")]
+        public async Task<object> BaseData()
+        {
+            var rsp = new
+            {
+                Status = EnumExts.GetDescriptions<ETerminateStatus>(),
+            };
+            return rsp;
+        }
 
-	}
+        /// <summary>
+        /// 终止修改理由
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("update_content")]
+        [LogFilter("终止修改理由")]
+        public async Task Update([FromBody] OrderTerminateContentDto dto)
+        {
+            await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
+        }
+
+    }
 }

+ 2 - 1
src/Hotline.Api/Controllers/OrgController.cs

@@ -72,7 +72,8 @@ namespace Hotline.Api.Controllers
         }
 
         [HttpPost("getorgjsonforuser/export")]
-        [AllowAnonymous]
+		[LogFilterAlpha("导出日志")]
+		[AllowAnonymous]
         public async Task<FileStreamResult> GetOrgJsonItemsExport([FromBody] ExportExcelDto<string> dto)
         {
             var items = await _orgApplication.GetOrgJsonItems();

+ 3 - 1
src/Hotline.Api/Controllers/PlanController.cs

@@ -16,6 +16,7 @@ using Hotline.Share.Enums.Article;
 using XF.Utility.EnumExtensions;
 using Hotline.Share.Dtos.Order;
 using Hotline.Application.ExportExcel;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers
 {
@@ -433,7 +434,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("list/info/export")]
-        public async Task<IActionResult> PlanInfoExport([FromBody] PlanInfoExportDto dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<IActionResult> PlanInfoExport([FromBody] PlanInfoExportDto dto)
         {
             if (dto.Ids.Length > 1)
             {

+ 15 - 13
src/Hotline.Api/Controllers/PushMessageController.cs

@@ -186,7 +186,7 @@ namespace Hotline.Api.Controllers
         public async Task<dynamic> SendMessageBaseDataAsync()
         {
             var users = await _userRepository.Queryable()
-                .Select(m => new {m.Id,  m.PhoneNo, m.Name }).ToListAsync();
+                .Select(m => new { m.Id, m.PhoneNo, m.Name }).ToListAsync();
             return new Dictionary<string, dynamic>() { { "contacts", users } };
         }
 
@@ -211,11 +211,13 @@ namespace Hotline.Api.Controllers
                     d => d.Name.Contains(pagedDto.Keyword!) || d.Content.Contains(pagedDto.Keyword!) ||
                          d.TelNumber.Contains(pagedDto.Keyword!) || d.CreatorName.Contains(pagedDto.Keyword!) ||
                          d.CreatorOrgName.Contains(pagedDto.Keyword!))
-                .WhereIF(pagedDto.StartTime.HasValue, d => d.SendTime >= pagedDto.StartTime)
-                .WhereIF(pagedDto.EndTime.HasValue, d => d.SendTime <= pagedDto.EndTime)
+                .WhereIF(pagedDto.StartTime.HasValue, d => d.SendTime >= pagedDto.StartTime)//发送时间开始
+                .WhereIF(pagedDto.EndTime.HasValue, d => d.SendTime <= pagedDto.EndTime)//发送时间结束
+                 .WhereIF(pagedDto.CreationStartTime.HasValue, d => d.CreationTime >= pagedDto.CreationStartTime)//添加时间开始
+                .WhereIF(pagedDto.CreationEndTime.HasValue, d => d.CreationTime <= pagedDto.CreationEndTime)//添加时间结束
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.UserName), d => d.Name.Contains(pagedDto.UserName))
                  .WhereIF(!string.IsNullOrEmpty(pagedDto.TelNumber), d => d.TelNumber.Contains(pagedDto.TelNumber))
-                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendName),d=>d.CreatorName.Contains(pagedDto.SendName))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendName), d => d.CreatorName.Contains(pagedDto.SendName))
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.SendOrg), d => d.CreatorOrgName.Contains(pagedDto.SendOrg))
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.SendContent), d => d.Content.Contains(pagedDto.SendContent))
                 .OrderByDescending(it => it.CreationTime)
@@ -250,7 +252,7 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("add-batchsmstask")]
-        public async Task AddBatchSmsTask([FromBody]AddBatchSmsTaskDto dto)
+        public async Task AddBatchSmsTask([FromBody] AddBatchSmsTaskDto dto)
         {
             //验证是否有重复电话
             if (dto.BatchSmsTaskDetail.DistinctBy(x => x.PhoneNum).Count() != dto.BatchSmsTaskDetail.Count)
@@ -267,7 +269,7 @@ namespace Hotline.Api.Controllers
             {
                 x.TaskId = task.Id;
             });
-            await _batchSmsTaskDetailRepository.AddRangeAsync(detail,HttpContext.RequestAborted);
+            await _batchSmsTaskDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted);
             //推送任务延迟消息
             //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
             _capPublisher.PublishDelay(task.PlanSendTime - DateTime.Now, EventNames.HotlineBatchSmsTask, new PublishBatchSmsTaskDto() { TaskId = task.Id });
@@ -279,7 +281,7 @@ namespace Hotline.Api.Controllers
         /// <param name="id"></param>
         /// <returns></returns>
         [HttpGet("stop-batchsmstask")]
-        public async Task StopBatchSmsTask([FromQuery]string id)
+        public async Task StopBatchSmsTask([FromQuery] string id)
         {
             var task = await _batchSmsTaskRepository.GetAsync(id, HttpContext.RequestAborted);
             if (task == null)
@@ -287,7 +289,7 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("无效任务");
             }
 
-            if (task.SmsTaskState!= ESmsTaskState.WaitDo)
+            if (task.SmsTaskState != ESmsTaskState.WaitDo)
             {
                 throw UserFriendlyException.SameMessage("当前任务状态不能终止");
             }
@@ -302,9 +304,9 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpGet("batchsmstask-query")]
-        public async Task<PagedDto<BatchSmsTaskRep>> BatchSmsTaskList([FromQuery]BatchSmsTaskReq dto)
+        public async Task<PagedDto<BatchSmsTaskRep>> BatchSmsTaskList([FromQuery] BatchSmsTaskReq dto)
         {
-            var (total,items) = await _batchSmsTaskRepository.Queryable()
+            var (total, items) = await _batchSmsTaskRepository.Queryable()
                 .WhereIF(string.IsNullOrEmpty(dto.TaskName) == false, x => x.TaskName.Contains(dto.TaskName))
                 .WhereIF(dto.State.HasValue, x => x.SmsTaskState == dto.State)
                 .WhereIF(dto.StateTime.HasValue, x => x.CreationTime >= dto.StateTime)
@@ -333,10 +335,10 @@ namespace Hotline.Api.Controllers
         /// <param name="id"></param>
         /// <returns></returns>
         [HttpGet("batchsmstask-entity")]
-        public async Task<BatchSmsTaskRep> BatchSmsTaskEntity([FromQuery]string id)
+        public async Task<BatchSmsTaskRep> BatchSmsTaskEntity([FromQuery] string id)
         {
             var model = await _batchSmsTaskRepository.GetAsync(id, HttpContext.RequestAborted);
-            if(model == null)
+            if (model == null)
             {
                 throw UserFriendlyException.SameMessage("无效任务");
             }
@@ -351,7 +353,7 @@ namespace Hotline.Api.Controllers
         [HttpGet("batchsmsmtaskdetail-query")]
         public async Task<PagedDto<AddBatchSmsTaskDetailDto>> BatchSmsTaskDetailList([FromQuery] BatchSmsTaskDetailListReq dto)
         {
-            var (total,items) = await _batchSmsTaskDetailRepository.Queryable()
+            var (total, items) = await _batchSmsTaskDetailRepository.Queryable()
                 .Where(x => x.TaskId == dto.Id)
                 .WhereIF(string.IsNullOrEmpty(dto.Name) == false, x => x.Name.Contains(dto.Name))
                 .WhereIF(string.IsNullOrEmpty(dto.PhoneNum) == false, x => x.PhoneNum.Contains(dto.PhoneNum))

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

@@ -757,7 +757,7 @@ namespace Hotline.Api.Controllers
                     }
                     catch (Exception e)
                     {
-                        _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                        _logger.LogError($"写入智能质检异常3!, \r\n{e.Message}");
                     }
                 }
                 await _qualitey.UpdateAsync(quality, HttpContext.RequestAborted);

+ 3 - 2
src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs

@@ -281,8 +281,9 @@ public class SnapshotController : BaseController
     /// <returns></returns>
     [HttpGet("wait_accept_count")]
     public async Task<int> GetSnapshotWaitForAcceptCountAsync()
-        => await _orderRepository
-            .CountAsync(m => m.SourceChannelCode == "ZGSSP" && m.Status == Share.Enums.Order.EOrderStatus.WaitForAccept);
+    { return 0; }
+    //=> await _orderRepository
+    //        .CountAsync(m => m.SourceChannelCode == "ZGSSP" && m.Status == Share.Enums.Order.EOrderStatus.WaitForAccept);
 
     /// <summary>
     /// 获取区域

+ 7 - 3
src/Hotline.Api/Controllers/StatisticalReportController.cs

@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
 using XF.Domain.Authentications;
 using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers
 {
@@ -49,7 +50,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getseatreturnorderlist_export")]
-        public async Task<FileStreamResult> GetSeatReturnOrderListExport([FromBody] ExportExcelDto<SeatReturnOrderListRequestDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetSeatReturnOrderListExport([FromBody] ExportExcelDto<SeatReturnOrderListRequestDto> dto)
         {
             var query = _orderReportApplication.GetSeatReturnOrderList(dto.QueryDto);
 
@@ -97,7 +99,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("getcenterreturnorderlist_export")]
-        public async Task<FileStreamResult> GetCenterReturnOrderListExport([FromBody] ExportExcelDto<SeatReturnOrderListRequestDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetCenterReturnOrderListExport([FromBody] ExportExcelDto<SeatReturnOrderListRequestDto> dto)
         {
             var query = _orderReportApplication.GetCenterReturnOrderList(dto.QueryDto);
 
@@ -141,7 +144,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("order_delay_statisical_list_export")]
-        public async Task<FileStreamResult> OrderDelayStatisicalListExport([FromBody] ExportExcelDto<OrderDelayStatisicalRequestDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> OrderDelayStatisicalListExport([FromBody] ExportExcelDto<OrderDelayStatisicalRequestDto> dto)
         {
             var query = _orderReportApplication.OrderDelayStatisicalList(dto.QueryDto);
 

+ 20 - 7
src/Hotline.Api/Controllers/SysController.cs

@@ -45,6 +45,7 @@ namespace Hotline.Api.Controllers
     public class SysController : BaseController
     {
         private readonly IMapper _mapper;
+        private readonly IHybridCachingProvider _hybridCaching;
         private readonly IRepository<SystemSetting> _systemSettingsRepository;
         private readonly ISystemMenuRepository _systemMenuRepository;
         private readonly IRepository<SystemDicType> _sysDicTypeRepository;
@@ -310,7 +311,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("dictdata-type/export")]
-        public async Task<FileStreamResult> GetSysDicDataExport([FromBody]ExportExcelDto<GetSysDicDataDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetSysDicDataExport([FromBody]ExportExcelDto<GetSysDicDataDto> dto)
         {
             var items = await _sysDicDataRepository.Queryable().Where(x => x.DicTypeId == dto.QueryDto.typeid).OrderBy(x => x.Sort).ToTreeAsync(x => x.Children, x => x.ParentId, "");
             return _exportApplication.GetExcelFile(dto, items, "字典列表");
@@ -416,12 +418,23 @@ namespace Hotline.Api.Controllers
             return await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0);
         }
 
-        /// <summary>
-        /// 获取省市区树形
-        /// </summary>
-        /// <returns></returns>
-        [HttpPost("area/tree/export")]
-        public async Task<FileStreamResult> GetAreaTreeExport([FromBody]ExportExcelDto<string> dto)
+		/// <summary>
+		/// 获取省市区树形 来电弹单界面获取
+		/// </summary>
+		/// <returns></returns>
+		[HttpGet("area/tree_accepted")]
+		public async Task<List<SystemArea>> GetAreaTree_Accepted()
+		{
+			return await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0, _appOptions.Value.IsLuZhou ? "510500" : "510000");
+		}
+
+		/// <summary>
+		/// 获取省市区树形
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("area/tree/export")]
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetAreaTreeExport([FromBody]ExportExcelDto<string> dto)
         {
             var items = await _systemAreaDomainService.GetAreaTree(_appOptions.Value.IsZiGong ? 6 : 0);
             return _exportApplication.GetExcelFile(dto, items, "行政区域");

+ 4 - 2
src/Hotline.Api/Controllers/TelRestController.cs

@@ -1,4 +1,5 @@
-using Hotline.Application.CallCenter;
+using Hotline.Api.Filter;
+using Hotline.Application.CallCenter;
 using Hotline.Article;
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Tels;
@@ -263,7 +264,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("get_restapply_list_export")]
-        public async Task<FileStreamResult> GetRestApplyListExport([FromBody] ExportExcelDto<TelRestApplyRequestDto> dto)
+		[LogFilterAlpha("导出日志")]
+		public async Task<FileStreamResult> GetRestApplyListExport([FromBody] ExportExcelDto<TelRestApplyRequestDto> dto)
         {
             var query = _pbxApplication.GetRestApplyList(dto.QueryDto);
 

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

@@ -255,7 +255,7 @@ public class TestController : BaseController
         {
             AppId = _systemSettingCacheManager.WxOpenAppId,
             Secret = _systemSettingCacheManager.WxOpenAppSecret,
-            WebApiHost = _systemSettingCacheManager.WxApiHost,
+            WebApiHost = "http://10.56.131.9:50200/wxapi/"
         };
         return await _thirdIdentiyService.GetPhoneNumberAsync(inDto, CancellationToken.None);
     }
@@ -1507,7 +1507,7 @@ public class TestController : BaseController
     public async Task OrderPushTypeCode([FromBody] OrderPushTypeCodeDto dto)
     {
         var orders = await _orderRepository.Queryable()
-            .Where(d => d.PushTypeCode.Contains(dto.PushTypeCode))
+            .Where(d => d.PushTypeCode.Contains(dto.PushTypeCode) && d.Source == ESource.Hotline)
             .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime) //受理时间开始
             .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime) //受理时间结束
             .ToListAsync(HttpContext.RequestAborted);
@@ -1539,9 +1539,9 @@ public class TestController : BaseController
         return ipv4;
     }
 
-    public string DecryptSign(string sign)
-    {
-        return sign;
-    }
+    //public string DecryptSign(string sign)
+    //{
+    //    return sign;
+    //}
 }
 

+ 2 - 1
src/Hotline.Api/Controllers/UserController.cs

@@ -193,7 +193,8 @@ public class UserController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("paged/_export")]
-    public async Task<FileStreamResult> QueryPagedExport([FromBody] ExportExcelDto<UserPagedDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> QueryPagedExport([FromBody] ExportExcelDto<UserPagedDto> dto)
     {
         var query =  _userApplication.QueryPaged(dto.QueryDto);
         List<User> data;

+ 6 - 0
src/Hotline.Api/Controllers/WebPortalController.cs

@@ -824,6 +824,12 @@ namespace Hotline.Api.Controllers
                    RSFlagName = p.Status >= EOrderStatus.Filed ? "办理完成" : "办理中"
                });
 
+            //if (_appOptions.Value.IsLuZhou)
+            //{
+            //    // 添加只查询临时待发布的公开件
+            //    queryNew = queryNew.Where(it => SqlFunc.Subqueryable<OrderPublishTemp>().Where(s => s.Id == it.FlowID).Any());
+            //}
+
             var queryold = _oldPublicDataRepository.Queryable()
                       .WhereIF(!string.IsNullOrEmpty(dto.FlowCode), p => p.OrderNo == dto.FlowCode)
                       .WhereIF(!string.IsNullOrEmpty(dto.FlowName), p => p.Title.Contains(dto.FlowName))

+ 2 - 1
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -588,7 +588,8 @@ public class WorkflowController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpPost("order-countersign/_export")]
-    public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<QueryOrderCountersignDto> dto)
+	[LogFilterAlpha("导出日志")]
+	public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<QueryOrderCountersignDto> dto)
     {
         var query = _workflowApplication.QueryOrderCountersigns(dto.QueryDto, _sessionContext)
              .Select((c, w, o) => new WorkflowCountersign()

BIN
src/Hotline.Api/Documents/luzhou/泸州12345平台工单查询接口(V1.0-20250312) .docx


BIN
src/Hotline.Api/Documents/zigong/丰窝12345平台工单接入接口(V1.1-20250225) .docx


+ 53 - 0
src/Hotline.Api/Filter/ClientIpFilterAttribute.cs

@@ -0,0 +1,53 @@
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.Filters;
+
+namespace Hotline.Api.Filter
+{
+    public class ClientIpFilterAttribute : ActionFilterAttribute
+    {
+        private readonly List<string> _whiteIps;
+        private readonly ILogger _logger;
+
+        public ClientIpFilterAttribute(List<string> whiteIps, ILogger logger)
+        {
+            _whiteIps = whiteIps;
+            _logger = logger;
+        }
+
+        public override void OnActionExecuting(ActionExecutingContext context)
+        {
+            if (!_whiteIps.Any()) return;
+
+            var ip = context.HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+            if (string.IsNullOrEmpty(ip))
+                ip = context.HttpContext.Request.Headers["X-Real-IP"].FirstOrDefault();
+
+            if (string.IsNullOrEmpty(ip))
+            {
+                var remoteIp = context.HttpContext.Connection.RemoteIpAddress;
+                if (remoteIp?.IsIPv4MappedToIPv6 ?? false)
+                    remoteIp = remoteIp.MapToIPv4();
+                ip = remoteIp?.ToString();
+            }
+
+            _logger.LogWarning("Request from IP: {RemoteIp}", ip);
+
+            if (ip.StartsWith(':') || ip.StartsWith("::"))
+                ip = ip.Replace(':', ' ').Trim();
+
+            if (string.IsNullOrEmpty(ip))
+            {
+                _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", ip);
+                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
+            }
+
+            if (!_whiteIps.Contains(ip))
+            {
+                _logger.LogWarning("Forbidden Request from IP: {RemoteIp}", ip);
+                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
+            }
+
+            base.OnActionExecuting(context);
+        }
+    }
+}

+ 62 - 0
src/Hotline.Api/Filter/UserNameSessionContextFilter.cs

@@ -0,0 +1,62 @@
+using Hotline.Identity.Accounts;
+using Hotline.Settings;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Tools;
+using Hotline.Users;
+using IdentityModel;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System.Security.Claims;
+using XF.Domain.Authentications;
+using XF.Domain.Repository;
+using static Hotline.AppDefaults;
+
+namespace Hotline.Api.Filter;
+
+public class UserNameSessionContextFilter : ActionFilterAttribute
+{
+    private IAccountRepository _accountRepository;
+    private IRepository<User> _userRepository;
+    private readonly string Name;  
+
+    public UserNameSessionContextFilter(string name)
+    {
+        Name = name;
+    }
+
+    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
+    {
+        await ReloadUser(context);
+        await next();
+    }
+
+    private async Task ReloadUser(ActionExecutingContext context)
+    {
+        try
+        {
+            _accountRepository = context.HttpContext.RequestServices.GetRequiredService<IAccountRepository>();
+            _userRepository = context.HttpContext.RequestServices.GetRequiredService<IRepository<User>>();
+            var user = _userRepository.Queryable().Where(m => m.Name == Name).First();
+            if (user == null) return;
+            var account = await _accountRepository.GetExtAsync(m => m.Id == user.Id, m => m.Includes(x => x.Roles));
+
+            List<Claim> userClaims = [
+                new(JwtClaimTypes.Subject, account.Id),
+                new(JwtClaimTypes.PhoneNumber, account.PhoneNo ?? string.Empty),
+                new(ClaimTypes.NameIdentifier, user.Id),
+                new(AppClaimTypes.UserDisplayName, account.Name),
+                new(AppClaimTypes.DepartmentId, user.OrgId ?? string.Empty),
+                new(AppClaimTypes.DepartmentIsCenter, user.Organization?.IsCenter.ToString() ?? string.Empty),
+                new(AppClaimTypes.DepartmentName, user.Organization?.Name ?? string.Empty),
+                new(AppClaimTypes.DepartmentAreaCode, user.Organization?.AreaCode ?? string.Empty),
+                new(AppClaimTypes.DepartmentAreaName, user.Organization?.AreaName ?? string.Empty),
+                new(AppClaimTypes.DepartmentLevel, user.Organization?.Level.ToString() ?? string.Empty),
+                new(AppClaimTypes.AreaId, user.OrgId?.GetHigherOrgId() ?? string.Empty),
+            ];
+            userClaims.AddRange(account.Roles.Select(d => new Claim(JwtClaimTypes.Role, d.Name)));
+            context.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity(userClaims));
+        }
+        catch
+        {
+        }
+    }
+}

+ 23 - 14
src/Hotline.Api/Properties/launchSettings.json

@@ -1,15 +1,24 @@
-{
-  "$schema": "https://json.schemastore.org/launchsettings.json",
-  "profiles": {
-    "Hotline.Api": {
-      "commandName": "Project",
-      "dotnetRunMessages": true,
-      "launchBrowser": true,
-      "launchUrl": "swagger",
-      "applicationUrl": "http://localhost:50100",
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      }
+{
+    "profiles": {
+        "Hotline.Api": {
+            "commandName": "Project",
+            "dotnetRunMessages": true,
+            "launchBrowser": true,
+            "launchUrl": "swagger",
+            "applicationUrl": "http://localhost:50100",
+            "environmentVariables": {
+                "ASPNETCORE_ENVIRONMENT": "Development"
+            }
+        },
+        "Hotline.Api.Test": {
+            "commandName": "Project",
+            "dotnetRunMessages": true,
+            "launchBrowser": true,
+            "launchUrl": "swagger",
+            "applicationUrl": "http://localhost:50100",
+            "environmentVariables": {
+                "ASPNETCORE_ENVIRONMENT": "Test"
+            }
+        }
     }
-  }
-}
+}

+ 25 - 13
src/Hotline.Api/StartupExtensions.cs

@@ -3,7 +3,6 @@ using FluentValidation;
 using FluentValidation.AspNetCore;
 using Hotline.Api.Realtimes;
 using Hotline.Application;
-using Hotline.Application.Contracts;
 using Hotline.NewRock;
 using Hotline.Permissions;
 using Hotline.Repository.SqlSugar.Extensions;
@@ -37,8 +36,11 @@ using Hotline.Orders.DatabaseEventHandler;
 using Hotline.Ai.XingTang;
 using Hotline.Pdf;
 using Hotline.XingTang;
-using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Snapshot.IRepository;
+using Hotline.Validators;
+using Hotline.Api.Filter;
+using Hotline.Caching.Interfaces;
+using Hotline.Settings;
 
 
 namespace Hotline.Api;
@@ -56,7 +58,7 @@ internal static class StartupExtensions
 #if DEBUG
         builder.WebHost.UseUrls("http://*:50100");
 #endif
-        
+
         services.Configure<IdentityConfiguration>(d => configuration.GetSection(nameof(IdentityConfiguration)).Bind(d));
 
         var appConfigurationSection = configuration.GetRequiredSection(nameof(AppConfiguration));
@@ -69,10 +71,10 @@ internal static class StartupExtensions
         services.Configure<CallCenterConfiguration>(d => callCenterConfigurationSection.Bind(d));
 
         services.Configure<CityBaseConfiguration>(d => configuration.GetSection(nameof(CityBaseConfiguration)).Bind(d));
-		//services.Configure<SendSmsConfiguration>(d => configuration.GetSection("SendSms").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;
@@ -85,11 +87,11 @@ internal static class StartupExtensions
             .AddScoped(typeof(IPasswordHasher<>), typeof(PasswordHasher<>))
             .AddHttpClient()
             ;
-        
+
         services.AddKeyedScoped<ISessionContext, ProvinceSessionContext>(ProvinceSessionContext.Key)
             .AddKeyedScoped<ISessionContext, Police110SessionContext>(Police110SessionContext.Key)
             ;
-        
+
         //cache
         services.AddCache(d =>
         {
@@ -144,7 +146,7 @@ internal static class StartupExtensions
                     .AddKeyedScoped<ISessionContext, ZzptSessionContext>(ZzptSessionContext.Key);
                 break;
             case AppDefaults.AppScope.ZiGong:
-				services.AddAiXingTang(appConfiguration.ZiGong.AiQuality.Url);
+                services.AddAiXingTang(appConfiguration.ZiGong.AiQuality.Url);
                 break;
             case AppDefaults.AppScope.LuZhou:
                 break;
@@ -195,7 +197,7 @@ internal static class StartupExtensions
         {
             config.DisableDataAnnotationsValidation = true;
         })
-            .AddValidatorsFromAssembly(typeof(AppContractsStartupExtensions).Assembly);
+            .AddValidatorsFromAssembly(typeof(ValidatorExtensions).Assembly);
 
         //mq
         services.AddMq(configuration);
@@ -218,12 +220,22 @@ internal static class StartupExtensions
         services.AddScoped<IExpireTimeSupplier, WorkDaySupplier>();
         services.AddScoped<IExpireTimeSupplier, HourSupplier>();
 
-        services.AddWeChatService();
+        services.AddWeChatService(configuration);
 
         services.AddScoped<IGuiderSystemService, TiqnQueService>();
 
-        //services.AddScoped<LogFilterAttribute>();
-        //ServiceLocator.Instance = services.BuildServiceProvider();
+        services.AddScoped<ClientIpFilterAttribute>(sp =>
+        {
+            var loggerFactory = sp.GetService<ILoggerFactory>();
+            var logger = loggerFactory.CreateLogger<ClientIpFilterAttribute>();
+            var cacheManager = sp.GetService<ISystemSettingCacheManager>();
+            var whiteIps = cacheManager.GetSetting(SettingConstants.WhiteIp).SettingValue
+                .Where(d => !string.IsNullOrEmpty(d))
+                .ToList();
+
+            return new ClientIpFilterAttribute(whiteIps, logger);
+        });
+
         return builder.Build();
     }
 

+ 3 - 0
src/Hotline.Api/StartupHelper.cs

@@ -2,8 +2,10 @@
 using System.IO.Compression;
 using System.Reflection;
 using System.Text;
+using Hotline.Api.Filter;
 using Hotline.Application;
 using Hotline.Application.Jobs;
+using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Configs;
 using Hotline.Configurations;
 using Hotline.DI;
@@ -11,6 +13,7 @@ using Hotline.EventBus;
 using Hotline.Identity;
 using Hotline.Repository.SqlSugar;
 using Hotline.Repository.SqlSugar.Ts;
+using Hotline.Settings;
 using Mapster;
 using MapsterMapper;
 using MediatR.Pipeline;

+ 21 - 0
src/Hotline.Api/config/appsettings.Test.json

@@ -0,0 +1,21 @@
+{
+    "ConnectionStrings": {
+        "Hotline": "PORT=5432;DATABASE=hotline_test;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+        //"Hotline1": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+    },
+    "Cache": {
+        "Host": "110.188.24.182",
+        "Port": 50179,
+        "Password": "fengwo123!$!$",
+        "Database": 2 //hotline:3, dev:5, test:2, demo:4
+    },
+    "SenparcWeixinSetting": {
+        "IsDebug": true,
+
+        //小程序
+        "WxOpenAppId": "wx22e6092dd504b567",
+        "WxOpenAppSecret": "bb29f684a9ea6b9d136062d68e867831"
+        //"WxOpenToken": "#{WxOpenToken}#",
+        //"WxOpenEncodingAESKey": "#{WxOpenEncodingAESKey}#"
+    }
+}

+ 51 - 50
src/Hotline.Api/config/appsettings.json

@@ -1,7 +1,48 @@
 {
   "AllowedHosts": "*",
+  "AppConfiguration": {
+    "AppScope": "ZiGong",
+    "YiBin": {
+      "AreaCode": "511500",
+      "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
+      //智能回访
+      "AiVisit": {
+        "Url": "http://118.122.73.80:19061",
+        "Appkey": "MTAwMDAx",
+        "ServiceVersion": "V1.0.0" //接口版本号
+      },
+      //智能质检
+      "AiQuality": {
+        "Url": "http://118.122.73.80:19072/" // 正式
+        //"Url": "http://118.122.73.80:19072/", // 测试
+      },
+      //企业服务
+      "Enterprise": {
+        "AddressUrl": "http://10.12.185.227:8834/",
+        "ClientId": "1462598736",
+        "ClientSecret": "6nZtVK4rKfnsncGymUHB",
+        "TenantId": "000000"
+      }
+    },
+    "ZiGong": {
+      //智能质检
+      "AiQuality": {
+        "Url": "http://175.10.86.234:10095" //  测试
+        //"Url": "http://10.56.131.13:10095/", // 正式
+      },
+      "AreaCode": "510300",
+      "CallCenterType": "XingTang"
+    },
+    "LuZhou": {
+      "AreaCode": "510500",
+      "CallCenterType": "XingTang"
+    },
+    "FileUpload": {
+      "Url": "http://110.188.24.28:50120/"
+    }
+  },
   "CallCenterConfiguration": {
-    "CallCenterType": "XingTang", //XunShi、WeiErXin、TianRun、XingTang
+    //"CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang
     "NewRock": {
       "Address": "http://192.168.100.100/xml",
       "Authorize": true,
@@ -25,24 +66,24 @@
     },
     "XingTang": {
       //"DbConnectionString": "server=123.56.10.71;Database=callcenter_db;Uid=root;Pwd=Lhw1981!(*!"
-      "DbConnectionString": "server=110.188.24.182;Database=callcenter_db;Uid=dev;Pwd=fengwo123!@#"
+      "DbConnectionString": "server=110.188.24.182;Database=callcenter_xingtang;Uid=dev;Pwd=fengwo11!!"
+      //"DbConnectionString": "PORT=50143;server=110.188.24.182;Database=callcenter_db;Uid=dev;Pwd=fengwo123!@#;"
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
-    //"Redis": "110.188.24.182:50179,password=fengwo22@@",
-    //"MongoDB": "mongodb://192.168.100.121:27017",
-    //"Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
+    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    //"Hotline1": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
   },
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 5 
+    "Database": 3 //hotline:3, dev:5, test:2, demo:4
   },
   "Swagger": true,
+  "AccLog": false,
   "Cors": {
-    "Origins": [ "http://10.210.252.122:8888", "http://localhost:8888", "http://localhost:8113", "http://hotline.12345lm.cn", "http://110.188.24.28:50101", "http://110.188.24.28:50102", "http://110.188.24.28:50301", "http://bs.hotline.12345lm.cn" ]
+    "Origins": [ "http://localhost:8888", "http://admin.hotline.fw.com", "http://localhost:80", "http://localhost:8113" ]
   },
   "IdentityConfiguration": {
     "Password": {
@@ -59,7 +100,7 @@
     },
     "Lockout": {
       "MaxFailedAccessAttempts": 5,
-      "DefaultLockoutTimeSpan": "00:01:00"
+      "DefaultLockoutTimeSpan": "00:10:00"
     },
     "Account": {
       "DefaultPassword": "Fwkj@789"
@@ -86,49 +127,9 @@
       "VirtualHost": "fwt-master"
     }
   },
-  "SmsAccountInfo": {
-    "MessageServerUrl": "http://webservice.fway.com.cn:1432/FWebService.asmx/FWay_Service", //短信发送地址
-    "AccountUser": "CS12345", //短信系统账号
-    "AccountPwd": "9EE3899305A8FC97D6146CAC6B802E6F", //短信系统密码
-    "ReturnAccountUser": "fwkj", //短信回传账号
-    "ReturnAccountPwd": "fwkj12" //短信回传密码
-  },
   "FwClient": {
     "ClientId": "hotline",
     "ClientSecret": "08db29cc-0da0-4adf-850c-1b2689bd535d"
-  },
-  "ConfigCenter": {
-    "ServerAddresses": [ "http://110.188.24.28:8848" ],
-    "Namespace": "f5017bc5-af0a-4f85-8e38-6718accc8f36", //dev
-    "ServiceName": "hotline"
-  },
-  "Tr": {
-    //"Address": "http://internal.ttf-cti.com:8080",
-    //"Username": "yscs",
-    //"Password": "123456"
-    "Address": "http://222.213.23.229:29003/",
-    "Username": "root",
-    "Password": "12345678aa",
-    "Ip": "222.213.23.229"
-  },
-  //智能质检
-  "AiQuality": {
-    "Url": "http://118.121.201.140:19072/"
-  },
-  //智能回访
-  "AiVisit": {
-    "Url": "http://118.122.73.80:19061",
-    "Appkey": "MTAwMDAx",
-    "ServiceVersion": "V1.0.0" //接口版本号
-  },
-  //企业服务
-  "Enterprise": {
-    "AddressUrl": "http://172.15.28.11:8835",
-    "ClientId": "1476116956",
-    "ClientSecret": "6NVnvmsFSC8d3qwgBZmN",
-    "TenantId": "000000"
-  },
-  "SendSms": {
-    "Url": "http://110.188.24.28:50108/api/v1/PushMessage/addwaitmsg"
   }
+
 }

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

@@ -61,11 +61,11 @@
       //{
       //  "Name": "MongoDBBson",
       //  "Args": {
-      //    "databaseUrl": "mongodb://192.168.100.121:27017/hotline_logs",
+      //    "databaseUrl": "mongodb://dev:fw123kj@110.188.24.182:57017/hotline_log?authSource=admin",
       //    "collectionName": "logs",
       //    "cappedMaxSizeMb": "1024",
       //    "cappedMaxDocuments": "50000",
-      //    "rollingInterval": "Day",
+      //    "rollingInterval": "Month",
       //    "outputTemplate": "[{Timestamp:HH:mm:ss} {Level}] {SourceContext} [{TraceId}]{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}"
       //  }
       //}

+ 2 - 2
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -404,8 +404,8 @@ public abstract class DefaultCallApplication : ICallApplication
     {
         return _telOperationRepository.Queryable()
             .Where(m => m.OperateStateText != "未知")
-            .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName == dto.UserName)
-            .WhereIF(!string.IsNullOrEmpty(dto.StaffNo), d => d.StaffNo == dto.StaffNo)
+            .WhereIF(!string.IsNullOrEmpty(dto.UserName), d => d.UserName.Contains(dto.UserName))
+            .WhereIF(!string.IsNullOrEmpty(dto.StaffNo), d => d.StaffNo.Contains(dto.StaffNo))
             .WhereIF(!string.IsNullOrEmpty(dto.GroupId), d => d.GroupId == dto.GroupId)
             .WhereIF(dto.TelNo != null, d => d.TelNo.Contains(dto.TelNo))
             .WhereIF(dto.OperateState != null, d => d.OperateState == dto.OperateState)

+ 1 - 0
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -90,6 +90,7 @@ namespace Hotline.Application.FlowEngine
         /// 查询指定节点的下一步待选节点
         /// </summary>
         Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, string stepId, CancellationToken cancellationToken);
+        Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(Workflow workflow, CancellationToken cancellationToken);
 
         /// <summary>
         /// 跨级指派查询下一步可选节点及办理对象参数

+ 14 - 2
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -203,7 +203,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         CancellationToken cancellationToken = default)
     {
         var validator = new StartWorkflowDtoValidator();
-        var validResult = await validator.ValidateAsync(dto, cancellationToken);
+        var validResult = validator.Validate(dto);
         if (!validResult.IsValid)
             throw new UserFriendlyException(
                 $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}");
@@ -550,6 +550,17 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
         return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
     }
+    
+    public async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(Workflow workflow, CancellationToken cancellationToken)
+    {
+        var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
+            _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
+            _sessionContext.Roles);
+        if (currentStep.StepType is EStepType.End)
+            throw new UserFriendlyException("结束节点无需办理");
+
+        return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
+    }
 
     /// <summary>
     /// 跨级指派查询下一步可选节点及办理对象参数
@@ -633,13 +644,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             CurrentHandlerType = currentStep.HandlerType,
             CurrentTag = currentStep.Tag ?? string.Empty,
             CurrentIsCountersignEndStep = currentStep.IsCountersignEndStep,
+            CurrentIsTopCountersignEndStep = currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId),
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
             StepId = currentStep.Id,
             CurrentOrgLevel = string.IsNullOrEmpty(currentStep.HandlerOrgId) ? null : currentStep.HandlerOrgId.CalcOrgLevel(),
             Opinion = currentStep.Opinion,
         };
-
+        
         var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
 
         if (currentStep.InstanceMode is EInstanceMode.Dynamic &&

+ 1 - 0
src/Hotline.Application/Handlers/FlowEngine/CancelHandler.cs

@@ -32,6 +32,7 @@ public class CancelHandler : INotificationHandler<CancelWorkflowNotify>
         switch (workflow.ModuleCode)
         {
             case WorkflowModuleConsts.OrderHandle:
+            case WorkflowModuleConsts.OrderHandleSnapshot:
                 var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, cancellationToken: cancellationToken);
                 order.CheckIfFiled();
                 order.Cancel();

+ 16 - 15
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -122,6 +122,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     await _telDomainService.TelRestApplyPassAsync(workflow.ExternalId, cancellationToken);
                     break;
                 case WorkflowModuleConsts.OrderHandle:
+                case WorkflowModuleConsts.OrderHandleSnapshot:
                     var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId,
                         withExtension: true, cancellationToken: cancellationToken);
                     //order.CheckIfFiled();
@@ -315,21 +316,21 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     // await _enforcementApplication.AddPassTheBuckOrderAsync(order, _sessionContext.OrgId, _sessionContext.OrgName, cancellationToken);
                     break;
                 case WorkflowModuleConsts.OrderDelay:
-                    var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                    if (delay != null)
-                    {
-                        //delay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
-                        delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
-                        await _orderDelayRepository.Updateable(delay)
-                            .UpdateColumns(d => d.DelayState)
-                            .ExecuteCommandAsync(cancellationToken);
-                        if (isReviewPass)
-                        {
-                            //处理工单延期
-                            await _orderApplication.DelayOrderExpiredTimeAsync(delay.OrderId, delay.DelayNum,
-                                delay.DelayUnit, delay.IsProDelay, cancellationToken);
-                        }
-                    }
+                    // var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
+                    // if (delay != null)
+                    // {
+                    //     //delay.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
+                    //     delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
+                    //     await _orderDelayRepository.Updateable(delay)
+                    //         .UpdateColumns(d => d.DelayState)
+                    //         .ExecuteCommandAsync(cancellationToken);
+                    //     if (isReviewPass)
+                    //     {
+                    //         //处理工单延期
+                    //         await _orderApplication.DelayOrderExpiredTimeAsync(delay.OrderId, delay.DelayNum,
+                    //             delay.DelayUnit, delay.IsProDelay, cancellationToken);
+                    //     }
+                    // }
                     break;
                 case WorkflowModuleConsts.OrderTerminate:
                     var orderTerminate = await _orderTerminateRepository.Queryable()

+ 8 - 10
src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs

@@ -105,7 +105,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
             //_logger.LogInformation(
             //    $"收到{nameof(NextStepNotify)}, notification: {JsonConvert.SerializeObject(notification)}");
             var workflow = notification.Workflow;
-            var data = notification.Dto;
+            var dto = notification.Dto;
 
             var currentTag = notification.Trace.Tag.TryDeserialize<DefinitionTag>();
             var nextTag = notification.NextStepDefine.Tag.TryDeserialize<DefinitionTag>();
@@ -113,13 +113,14 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
             switch (workflow.ModuleCode)
             {
                 case WorkflowModuleConsts.OrderHandle:
+                case WorkflowModuleConsts.OrderHandleSnapshot:
                     var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, withHotspot: true,
                         withAcceptor: true, withExtension: true, cancellationToken: cancellationToken);
                     order.CheckIfFiled();
                     order.UpdateHandlingStatus(workflow.IsInCountersign);
                     _mapper.Map(workflow, order);
 
-                    var isCenterToOrg = data.FlowDirection is EFlowDirection.CenterToOrg;
+                    var isCenterToOrg = dto.FlowDirection is EFlowDirection.CenterToOrg;
                     //if (isCenterToOrg)
                     //{
                     //    var expiredTimeConfig =
@@ -131,9 +132,9 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                     //}
 
                     if (order.CounterSignType is ECounterSignType.Center &&
-                        notification.Trace.BusinessType is EBusinessType.Seat or EBusinessType.Send &&
+                        //notification.Trace.BusinessType is EBusinessType.Seat or EBusinessType.Send or EBusinessType.CenterLeader or EBusinessType.CenterMonitor &&
                         notification.Workflow.IsTopCountersignEndStep(notification.Trace) &&
-                        data.FlowDirection is EFlowDirection.CenterToOrg)
+                        isCenterToOrg)
                     {
                         bool.TryParse(
                             _systemSettingCacheManager.GetSetting(SettingConstants.IsResetCenterCountersignType)?.SettingValue[0],
@@ -142,7 +143,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                             order.CounterSignType = null;
                     }
 
-                    if (data.FlowDirection is EFlowDirection.CenterToOrg)
+                    if (isCenterToOrg)
                         order.SendBackAuditEndTime = await _expireTime.GetWorkDay(DateTime.Now);
                     await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
 
@@ -236,14 +237,11 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                         }, cancellationToken: cancellationToken);
                     }
 
-                    if (data.FlowDirection is EFlowDirection.CenterToOrg)
+                    if (isCenterToOrg)
                         await _qualityApplication.AddQualityAsync(EQualitySource.Send, order.Id, cancellationToken);
 
                     //随手拍推送网格员
-                    bool.TryParse(
-                        _systemSettingCacheManager.GetSetting(SettingConstants.Snapshot)?.SettingValue[0],
-                        out bool isSnapshotEnable);
-                    if (isSnapshotEnable)
+                    if (_systemSettingCacheManager.Snapshot)
                     {
                         if (string.Compare(TagDefaults.Wanggeyuan, notification.NextStepDefine.Tag,
                                 StringComparison.OrdinalIgnoreCase) == 0)

+ 1 - 0
src/Hotline.Application/Handlers/FlowEngine/WorkflowPreviousHandler.cs

@@ -96,6 +96,7 @@ namespace Hotline.Application.Handlers.FlowEngine
                 switch (workflow.ModuleCode)
                 {
                     case WorkflowModuleConsts.OrderHandle:
+                    case WorkflowModuleConsts.OrderHandleSnapshot:
                         var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, withHotspot: true, withAcceptor: true,
                             withExtension: true, cancellationToken: cancellationToken);
                         order.CheckIfFiled();

+ 1 - 0
src/Hotline.Application/Handlers/FlowEngine/WorkflowStartHandler.cs

@@ -96,6 +96,7 @@ namespace Hotline.Application.Handlers.FlowEngine
                 switch (workflow.ModuleCode)
                 {
                     case WorkflowModuleConsts.OrderHandle:
+                    case WorkflowModuleConsts.OrderHandleSnapshot:
                         var order = await _orderDomainService.GetOrderAsync(workflow.ExternalId, withHotspot: true, withAcceptor: true,
                             withExtension: true, cancellationToken);
                         order.CheckIfFiled();

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

@@ -56,9 +56,6 @@ public class SnapshotMapperConfigs : IRegister
         config.ForType<Hotline.File.File, IndustryFileDto>()
             .Map(m => m.AdditionId, n => n.Additions);
 
-        config.ForType<IndustryFileDto, Hotline.File.File>()
-            .Map(m => m.Additions, n => n.AdditionId);
-
         config.ForType<SnapshotFileInDto, File.File>()
             .Map(m => m.Additions, n => n.AdditionId);
 

+ 3 - 0
src/Hotline.Application/OrderApp/IOrderApplication.cs

@@ -116,6 +116,7 @@ namespace Hotline.Application.OrderApp
 
         ISugarQueryable<Order> QueryOrders(QueryOrderDto dto);
         ISugarQueryable<Order> QueryTravel(QueryOrderDto dto);
+        ISugarQueryable<Order> QueryEnterprise(QueryOrderDto dto);
 
         /// <summary>
         /// 保存工单办理时页面填写的数据
@@ -352,6 +353,8 @@ namespace Hotline.Application.OrderApp
         ISugarQueryable<OrderPublish> GetPublishedOrder(PublishedPagedRequest dto);
         ISugarQueryable<Order> GetPublishOrderList(QueryOrderPublishDto dto);
 
+        ISugarQueryable<Order> GetPublishTempOrderList(QueryOrderPublishDto dto);
+
         /// <summary>
         /// 回访列表
         /// </summary>

+ 258 - 31
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -1,6 +1,4 @@
-using System.Data;
-using System.Dynamic;
-using DotNetCore.CAP;
+using DotNetCore.CAP;
 using FluentValidation;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.Quality;
@@ -48,11 +46,11 @@ using Hotline.Validators.FlowEngine;
 using Mapster;
 using MapsterMapper;
 using MediatR;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
 using Microsoft.Extensions.Options;
 using PanGu;
-using Quartz.Simpl;
 using SqlSugar;
+using System.Data;
+using System.Dynamic;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
@@ -848,6 +846,86 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .OrderByIF(dto is { SortRule: 1, SortField: "expiredTimeProvince" }, d => d.ExpiredTimeProvince, OrderByType.Desc);
     }
 
+    /// <summary>
+    /// 获取临时待发布列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<Order> GetPublishTempOrderList(QueryOrderPublishDto dto)
+    {
+        var query = _orderRepository.Queryable().Includes(d => d.OrderTags);
+        if (_appOptions.Value.IsLuZhou)
+            query = query.Includes(d => d.FwCallRecord);
+        query = query.RightJoin<OrderPublishTemp>((d, p) => d.No == p.No);
+
+        return query.Where(d => d.Status == EOrderStatus.Filed)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!))
+            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No))
+            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title))
+            //.WhereIF(dto.PubState == EPubState.Pub, d => d.Status >= EOrderStatus.Published)
+            //.WhereIF(dto.PubState == EPubState.NoPub, d => d.Status == EOrderStatus.Filed)
+            .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel)
+            //.WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTagCode == dto.OrderTag!) //工单标签
+            .WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTag)) //工单标签
+            .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName.Contains(dto.CenterToOrgHandlerName)) //派单人
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo),
+                d => d.AcceptorName.Contains(dto.NameOrNo) || d.AcceptorStaffNo.Contains(dto.NameOrNo)) //受理人/坐席
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
+            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
+            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
+            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
+            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
+            .WhereIF(!string.IsNullOrEmpty(dto.Contact), d => d.Contact == dto.Contact) //联系电话
+                                                                                        //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
+                                                                                        //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
+                                                                                        //.WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState)
+                                                                                        //.WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState)
+            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.IsProvince == true)
+            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.IsProvince == false)
+            //.WhereIF(dto.FiledType != null && dto.FiledType == FiledType.CenterFiled, d => d.ProcessType == EProcessType.Zhiban)
+            //.WhereIF(dto.FiledType != null && dto.FiledType == FiledType.OrgFiled, d => d.ProcessType == EProcessType.Jiaoban)
+            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.CenterFiled, d => d.FileOrgIsCenter == true)
+            .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.OrgFiled, d => d.FileOrgIsCenter == false)
+            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == true, d => d.CounterSignType != null)
+            .WhereIF(dto.IsCountersign != null && dto.IsCountersign == false, d => d.CounterSignType == null)
+            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType))
+            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId))
+            //.WhereIF(dto.Resolve.HasValue, d => d.OrderPublish.Resolve == dto.Resolve)
+            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart)
+            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd)
+            .WhereIF(dto.FiledTimeStart.HasValue, d => d.FiledTime >= dto.FiledTimeStart)
+            .WhereIF(dto.FiledTimeEnd.HasValue, d => d.FiledTime <= dto.FiledTimeEnd)
+            .WhereIF(dto.ExpiredTimeProvinceStart.HasValue, d => d.ExpiredTimeProvince >= dto.ExpiredTimeProvinceStart) //省期满时间开始
+            .WhereIF(dto.ExpiredTimeProvinceEnd.HasValue, d => d.ExpiredTimeProvince <= dto.ExpiredTimeProvinceEnd) //省期满时间结束
+            .WhereIF(dto.Iszgzfw.HasValue && dto.Iszgzfw == true, d => d.ReceiveProvinceNo.StartsWith("ZGZFW"))
+            .WhereIF(dto.Isgjzwfwpt.HasValue && dto.Isgjzwfwpt == true, d => d.ReceiveProvinceNo.StartsWith("GJZWFWPT"))
+            .WhereIF(dto.QuerySelf.HasValue && dto.QuerySelf.Value, d => d.WaitForPublisherId == _sessionContext.RequiredUserId)
+            .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
+            .WhereIF(dto.IsOverTime == true,
+                d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
+                     (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
+            .WhereIF(dto.IsOverTime == false,
+                d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) ||
+                     (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
+            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "1", d => d.Source == ESource.ProvinceStraight &&
+                d.SourceChannelCode == "SZMHD" && d.IsProvince == false) //政民互动直派
+            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "2", d => d.Source == ESource.ProvinceStraight &&
+                d.SourceChannelCode == "SZMHD" && d.IsProvince == true) //政民互动
+            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "3", d => d.Source == ESource.ProvinceStraight &&
+                d.SourceChannelCode == "S12345" && d.IsProvince == true) //省12345
+            .OrderBy(d => new { IsUrgent = d.IsUrgent }, OrderByType.Desc)
+            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.IsUrgent, OrderByType.Desc)
+            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.FiledTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "filedTime" }, d => d.FiledTime, OrderByType.Asc)
+            .OrderByIF(dto is { SortRule: 1, SortField: "filedTime" }, d => d.FiledTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "actualHandleTime" }, d => d.ActualHandleTime, OrderByType.Asc)
+            .OrderByIF(dto is { SortRule: 1, SortField: "actualHandleTime" }, d => d.ActualHandleTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "creationTime" }, d => d.CreationTime, OrderByType.Asc)
+            .OrderByIF(dto is { SortRule: 1, SortField: "creationTime" }, d => d.CreationTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "expiredTimeProvince" }, d => d.ExpiredTimeProvince, OrderByType.Asc)
+            .OrderByIF(dto is { SortRule: 1, SortField: "expiredTimeProvince" }, d => d.ExpiredTimeProvince, OrderByType.Desc);
+    }
+
     public ISugarQueryable<OrderPublish> GetPublishedOrder(PublishedPagedRequest dto)
     {
         return _orderPublishRepository.Queryable()
@@ -882,7 +960,15 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 d.Order.SourceChannelCode == "SZMHD" && d.Order.IsProvince == true) //政民互动
             .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "3", d => d.Order.Source == ESource.ProvinceStraight &&
                 d.Order.SourceChannelCode == "S12345" && d.Order.IsProvince == true) //省12345
-            .OrderByDescending(d => d.CreationTime);
+            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "creationTime" }, d => d.Order.CreationTime, OrderByType.Asc)   //受理时间
+            .OrderByIF(dto is { SortRule: 1, SortField: "creationTime" }, d => d.Order.CreationTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "filedTime" }, d => d.Order.FiledTime, OrderByType.Asc)  //办结时间
+            .OrderByIF(dto is { SortRule: 1, SortField: "filedTime" }, d => d.Order.FiledTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "publishTime" }, d => d.CreationTime, OrderByType.Asc) //发布时间
+            .OrderByIF(dto is { SortRule: 1, SortField: "publishTime" }, d => d.CreationTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "lastModificationTime" }, d => d.LastModificationTime, OrderByType.Asc) //更新时间
+            .OrderByIF(dto is { SortRule: 1, SortField: "lastModificationTime" }, d => d.LastModificationTime, OrderByType.Desc);
     }
 
     /// <summary>
@@ -1433,6 +1519,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 visit.OrderVisitDetails[i].ScreenByEndTime = await _orderDomainService.GetScreenByEndTime();
             }
         }
+        if (dto.IsTransact.HasValue && dto.IsTransact.Value)
+        {
+            visit.Order.VisitReTransactNum = visit.Order.VisitReTransactNum is null ? 1 : visit.Order.VisitReTransactNum + 1;
+        }
 
         await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
         await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
@@ -1456,20 +1546,23 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 {
                     if (visit.Order.Source != ESource.ProvinceStraight)
                     {
-                        //发送查询短信
-                        var messageDto = new Share.Dtos.Push.MessageDto
+                        if (visit.Order.FileOrgIsCenter.Value == false || (visit.Order.FileOrgIsCenter.Value == true && visit.Order.CounterSignType != null))
                         {
-                            PushBusiness = EPushBusiness.SearchSms,
-                            ExternalId = visit.Id,
-                            OrderId = visit.Order.Id,
-                            PushPlatform = EPushPlatform.Sms,
-                            Remark = visit.Order.Title,
-                            Name = visit.Order.FromName,
-                            TemplateCode = "1021",
-                            Params = new List<string>() { visit.Order.No, visit.Order.Password },
-                            TelNumber = visit.Order.Contact,
-                        };
-                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                            //发送查询短信
+                            var messageDto = new Share.Dtos.Push.MessageDto
+                            {
+                                PushBusiness = EPushBusiness.SearchSms,
+                                ExternalId = visit.Id,
+                                OrderId = visit.Order.Id,
+                                PushPlatform = EPushPlatform.Sms,
+                                Remark = visit.Order.Title,
+                                Name = visit.Order.FromName,
+                                TemplateCode = "1021",
+                                Params = new List<string>() { visit.Order.No, visit.Order.Password },
+                                TelNumber = visit.Order.Contact,
+                            };
+                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                        }
                     }
                 }
             }
@@ -1527,10 +1620,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                         var visitData = dto.VisitDetails.Where(x => x.VisitTarget == EVisitTarget.Seat).FirstOrDefault();
                         if (visitData != null)
                         {
-                            if ((visitData.VoiceEvaluate == EVoiceEvaluate.VerySatisfied ||
-                                 visitData.VoiceEvaluate == EVoiceEvaluate.Satisfied) &&
-                                (visitData.SeatEvaluate == ESeatEvaluate.VerySatisfied ||
-                                 visitData.SeatEvaluate == ESeatEvaluate.Satisfied))
+                            if (visitData.VoiceEvaluate != EVoiceEvaluate.NoSatisfied &&
+                                visitData.VoiceEvaluate != EVoiceEvaluate.VeryNoSatisfied &&
+                                visitData.SeatEvaluate != ESeatEvaluate.NoSatisfied &&
+                                visitData.SeatEvaluate != ESeatEvaluate.VeryNoSatisfied)
                             {
                                 await _orderScreenRepository.RemoveAsync(x => x.VisitId == visitData.VisitId);
                             }
@@ -1547,8 +1640,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                         {
                             if (visitData.OrgProcessingResults != null)
                             {
-                                if (visitData.OrgProcessingResults.Value == "非常满意" ||
-                                    visitData.OrgProcessingResults.Value == "满意")
+                                if (visitData.OrgProcessingResults.Value != "非常不满意" &&
+                                    visitData.OrgProcessingResults.Value != "不满意")
                                 {
                                     await _orderScreenRepository.RemoveAsync(x => x.VisitId == visitData.VisitId);
                                 }
@@ -1721,6 +1814,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         //}
 
         query = query
+                .WhereIF(!string.IsNullOrEmpty(dto.PoliticalIdentityValue), d => d.PoliticalIdentityValue == dto.PoliticalIdentityValue)//政治身份查询
                 .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
                 .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
                 .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), d => d.ReceiveProvinceNo.Contains(dto.ReceiveProvinceNo)) //省编号
@@ -1976,6 +2070,139 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         return query;
     }
 
+    public ISugarQueryable<Order> QueryEnterprise(QueryOrderDto dto)
+    {
+        var query = _orderRepository.Queryable(canView: false);
+        query = query.Includes(d => d.OrderScreens).Includes(d => d.OrderTags);
+
+        query = query
+                .Where(d => d.IdentityType == EIdentityType.Enterprise) //来电主体
+                .WhereIF(!string.IsNullOrEmpty(dto.PoliticalIdentityValue), d => d.PoliticalIdentityValue == dto.PoliticalIdentityValue)//政治身份查询
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
+                .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), d => d.ReceiveProvinceNo.Contains(dto.ReceiveProvinceNo)) //省编号
+                .WhereIF(dto.IsSecret.HasValue, d => d.IsSecret == dto.IsSecret.Value)
+                .WhereIF(dto.IsReTransact.HasValue && dto.IsReTransact.Value, d => d.ReTransactNum > 0)
+                .WhereIF(dto.IsReTransact.HasValue && dto.IsReTransact.Value == false, d => d.ReTransactNum == null || d.ReTransactNum == 0)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
+                                                                                                         //.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(!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.StartTimeStart.HasValue, d => d.StartTime >= dto.StartTimeStart) //流程开启时间开始
+                .WhereIF(dto.StartTimeEnd.HasValue, d => d.StartTime <= dto.StartTimeEnd) //流程开启时间结束
+                                                                                          //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
+                .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone.Contains(dto.FromPhone)) //来电号码
+                .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact.Contains(dto.PhoneNo)) //联系电话
+                                                                                                   //.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.Status.HasValue, d => d.Status == dto.Status) //工单状态
+                                                                           //.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)) //无甄别
+                .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.CurrentStepCode == dto.CurrentStepCode) //当前办理节点
+                .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.FiledTime >= dto.ActualHandleTimeStart) //办结时间开始
+                .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.FiledTime <= dto.ActualHandleTimeEnd) //办结时间结束
+                .WhereIF(dto.IsOverTime == true,
+                    d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) ||
+                         (d.ExpiredTime < d.FiledTime && d.Status >= EOrderStatus.Filed)) //是 超期
+                .WhereIF(dto.IsOverTime == false,
+                    d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) ||
+                         (d.ExpiredTime > d.FiledTime && 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(!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 && dto.ProvinceSearch != true, d => d.IsProvince == true)
+                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false && dto.ProvinceSearch != true, d => d.IsProvince == false)
+                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true && dto.ProvinceSearch == true, d => d.Source == ESource.ProvinceStraight)
+                .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), d => SqlFunc.JsonArrayAny(d.Sensitive, dto.SensitiveWord))
+                .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true,
+                    d => d.Sensitive != null && SqlFunc.JsonArrayLength(d.Sensitive) > 0)
+                .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "1", d => d.Source == ESource.ProvinceStraight &&
+                    d.SourceChannelCode == "SZMHD" && d.IsProvince == false) //政民互动直派
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "2", d => d.Source == ESource.ProvinceStraight &&
+                    d.SourceChannelCode == "SZMHD" && d.IsProvince == true) //政民互动
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceChannel) && dto.ProvinceChannel == "3", d => d.Source == ESource.ProvinceStraight &&
+                    d.SourceChannelCode == "S12345" && d.IsProvince == true) //省12345
+                                                                             //.WhereIF(!string.IsNullOrEmpty(dto.ContentRetrieval),d => d.Title.Contains(dto.ContentRetrieval) || d.Content.Contains(dto.ContentRetrieval) || d.FileOpinion.Contains(dto.ContentRetrieval) || d.ActualOpinion.Contains(dto.ContentRetrieval))
+                .WhereIF(!string.IsNullOrEmpty(dto.ContentRetrieval), d => d.Content.Contains(dto.ContentRetrieval!))
+                .WhereIF(!string.IsNullOrEmpty(dto.FileOption), d => d.FileOpinion.Contains(dto.FileOption!))
+                .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == true, d => d.CurrentStepAcceptTime != null)
+                .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == false, d => d.CurrentStepAcceptTime == null)
+                .WhereIF(dto.FiledType is FiledType.CenterFiled, d => d.FileOrgIsCenter == true) //d => d.ProcessType == EProcessType.Zhiban
+                .WhereIF(dto.FiledType is FiledType.OrgFiled, d => d.FileOrgIsCenter == false) //d => d.ProcessType == EProcessType.Jiaoban
+                                                                                               //.WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTagCode == dto.OrderTagCode)// 工单标签
+                .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode)) //工单标签
+                .WhereIF(!string.IsNullOrEmpty(dto.FocusOnEvents),
+                    d => d.FocusOnEvents.Contains(dto.FocusOnEvents)) //!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
+                .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) //默认排序时间为创建时间
+                .OrderByIF(dto is { SortField: "no", SortRule: 0 }, d => d.No, OrderByType.Asc) //工单编号升序
+                .OrderByIF(dto is { SortField: "no", SortRule: 1 }, d => d.No, OrderByType.Desc) //工单编号降序
+                .OrderByIF(dto is { SortField: "isProvinceText", SortRule: 0 }, d => d.IsProvince, OrderByType.Asc) //是否省工单升序
+                .OrderByIF(dto is { SortField: "isProvinceText", SortRule: 1 }, d => d.IsProvince, OrderByType.Desc) //是否省工单降序
+                .OrderByIF(dto is { SortField: "reTransactNum", SortRule: 0 }, d => d.ReTransactNum, OrderByType.Asc) //重办次数升序
+                .OrderByIF(dto is { SortField: "reTransactNum", SortRule: 1 }, d => d.ReTransactNum, OrderByType.Desc) //重办次数降序
+                .OrderByIF(dto is { SortField: "isUrgentText", SortRule: 0 }, d => d.IsUrgent, OrderByType.Asc) //是否紧急升序
+                .OrderByIF(dto is { SortField: "isUrgentText", SortRule: 1 }, d => d.IsUrgent, OrderByType.Desc) //是否紧急降序
+                .OrderByIF(dto is { SortField: "isSecret", SortRule: 0 }, d => d.IsSecret, OrderByType.Asc) //是否紧急升序
+                .OrderByIF(dto is { SortField: "isSecret", SortRule: 1 }, d => d.IsSecret, OrderByType.Desc) //是否紧急降序
+                .OrderByIF(dto is { SortField: "currentStepName", SortRule: 0 }, d => d.CurrentStepName, OrderByType.Asc) //当前节点升序
+                .OrderByIF(dto is { SortField: "currentStepName", SortRule: 1 }, d => d.CurrentStepName, OrderByType.Desc) //当前节点降序
+                .OrderByIF(dto is { SortField: "actualStepAcceptText", SortRule: 0 }, d => d.ActualHandleStepAcceptTime.HasValue,
+                    OrderByType.Asc) //受理情况升序
+                .OrderByIF(dto is { SortField: "actualStepAcceptText", SortRule: 1 }, d => d.ActualHandleStepAcceptTime.HasValue,
+                    OrderByType.Desc) //受理情况降序
+                .OrderByIF(dto is { SortField: "statusText", SortRule: 0 }, d => d.Status, OrderByType.Asc) //工单状态升序
+                .OrderByIF(dto is { SortField: "statusText", SortRule: 1 }, d => d.Status, OrderByType.Desc) //工单状态降序
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序
+                .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //超期时间升序
+                .OrderByIF(dto is { SortField: "expiredTime", SortRule: 1 }, d => d.ExpiredTime, OrderByType.Desc) //超期时间降序
+                .OrderByIF(dto is { SortField: "filedTime", SortRule: 0 }, d => d.FiledTime, OrderByType.Asc) //办结时间升序
+                .OrderByIF(dto is { SortField: "filedTime", SortRule: 1 }, d => d.FiledTime, OrderByType.Desc) //办结时间降序
+                .OrderByIF(dto is { SortField: "orgLevelOneName", SortRule: 0 }, d => d.OrgLevelOneName, OrderByType.Asc) //一级部门升序
+                .OrderByIF(dto is { SortField: "orgLevelOneName", SortRule: 1 }, d => d.OrgLevelOneName, OrderByType.Desc) //一级部门降序
+                .OrderByIF(dto is { SortField: "orgLevelTwoName", SortRule: 0 }, d => d.OrgLevelTwoName, OrderByType.Asc) //二级部门升序
+                .OrderByIF(dto is { SortField: "orgLevelTwoName", SortRule: 1 }, d => d.OrgLevelTwoName, OrderByType.Desc) //二级部门降序
+                .OrderByIF(dto is { SortField: "actualHandleOrgName", SortRule: 0 }, d => d.ActualHandleOrgName, OrderByType.Asc) //接办部门升序
+                .OrderByIF(dto is { SortField: "actualHandleOrgName", SortRule: 1 }, d => d.ActualHandleOrgName, OrderByType.Desc) //接办部门降序
+                .OrderByIF(dto is { SortField: "acceptType", SortRule: 0 }, d => d.AcceptTypeCode, OrderByType.Asc) //受理类型升序
+                .OrderByIF(dto is { SortField: "acceptType", SortRule: 1 }, d => d.AcceptTypeCode, OrderByType.Desc) //受理类型降序
+                .OrderByIF(dto is { SortField: "counterSignTypeText", SortRule: 0 }, d => d.CounterSignType, OrderByType.Asc) //是否会签升序
+                .OrderByIF(dto is { SortField: "counterSignTypeText", SortRule: 1 }, d => d.CounterSignType, OrderByType.Desc) //是否会签降序
+                .OrderByIF(dto is { SortField: "hotspotSpliceName", SortRule: 0 }, d => d.HotspotSpliceName, OrderByType.Asc) //热点分类全称升序
+                .OrderByIF(dto is { SortField: "hotspotSpliceName", SortRule: 1 }, d => d.HotspotSpliceName, OrderByType.Desc) //热点分类全称降序
+                .OrderByIF(dto is { SortField: "hotspotName", SortRule: 0 }, d => d.HotspotName, OrderByType.Asc) //热点分类升序
+                .OrderByIF(dto is { SortField: "hotspotName", SortRule: 1 }, d => d.HotspotName, OrderByType.Desc) //热点分类降序
+                .OrderByIF(dto is { SortField: "acceptorName", SortRule: 0 }, d => d.AcceptorName, OrderByType.Asc) //受理人升序
+                .OrderByIF(dto is { SortField: "acceptorName", SortRule: 1 }, d => d.AcceptorName, OrderByType.Desc) //受理人降序
+                .OrderByIF(dto is { SortField: "currentStepAcceptTime", SortRule: 0 }, d => d.CurrentStepAcceptTime, OrderByType.Asc) //接办时间升序
+                .OrderByIF(dto is { SortField: "currentStepAcceptTime", SortRule: 1 }, d => d.CurrentStepAcceptTime, OrderByType.Desc) //接办时间降序
+            ;
+
+        return query;
+    }
+
     /// <summary>
     /// 未签收统计
     /// </summary>
@@ -3903,6 +4130,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                     .Where((s, p) => p.DicDataValue == dto.OrderTagCode && d.OrderId == s.OrderId).Any()) //工单标签
             .WhereIF(dto.IsUpdate.HasValue && dto.IsUpdate == true, d => d.IsUpdate == true)
             .WhereIF(dto.IsUpdate.HasValue && dto.IsUpdate == false, d => d.IsUpdate == false || d.IsUpdate == null)
+            .WhereIF(dto.IsEmployeeNameNull.HasValue && dto.IsEmployeeNameNull == true, d => d.EmployeeId != null && d.EmployeeId != "")
+            .WhereIF(dto.IsEmployeeNameNull.HasValue && dto.IsEmployeeNameNull == false, d => d.EmployeeId == null || d.EmployeeId == "")
 
             .OrderByIF(_appOptions.Value.IsYiBin && dto.VisitStateQuery != EVisitStateQuery.Visited, d => d.Order.IsUrgent, OrderByType.Desc)
             .OrderByIF(_appOptions.Value.IsZiGong == false, d => d.PublishTime, OrderByType.Desc)
@@ -4079,7 +4308,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             OrgId = startStep.HandlerOrgId,
             OrgName = startStep.HandlerOrgName,
         };
-        //_sessionContext.ChangeSession(startStep.HandlerId);
         await _sessionContextManager.ChangeSessionContextByUserIdAsync(startStep.HandlerId, cancellationToken);
         var isAutoFillSummaryOpinion = _systemSettingCacheManager.IsAutoFillSummaryOpinion;
 
@@ -5098,10 +5326,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         //);
 
         //随手拍
-        bool.TryParse(
-            _systemSettingCacheManager.GetSetting(SettingConstants.Snapshot)?.SettingValue[0],
-            out bool isSnapshotEnable);
-        if (isSnapshotEnable && !string.IsNullOrEmpty(dto.IndustryId))
+
+        if (_systemSettingCacheManager.Snapshot && !string.IsNullOrEmpty(dto.IndustryId))
         {
             query.Where(d => d.OrderSnapshot.IndustryId == dto.IndustryId);
         }
@@ -5571,7 +5797,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 //如果查询全部
                 //1.1、热线中心用户看系统中所有已申请延期的工单(需排除取消延期的工单)和自动延期的工单
                 //1.2、部门用户看部门及其下级部门已申请延期的工单(需排除取消延期的工单)和部门办理中时自动延期的工单
-                .WhereIF(dto.DataScope is 0, d => (d.AutomaticDelayNum == 0 || d.AutomaticDelayNum == null) && d.DelayState != EDelayState.Withdraw)
+                // .WhereIF(dto.DataScope is 0, d => (d.AutomaticDelayNum == 0 || d.AutomaticDelayNum == null) && d.DelayState != EDelayState.Withdraw)
+                .WhereIF(dto.DataScope is 0, d => d.DelayState != EDelayState.Withdraw)
                 .WhereIF(dto.DataScope is 0 && !_sessionContext.OrgIsCenter, d => d.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId))
                 .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
                     d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))

+ 3 - 3
src/Hotline.Application/Quality/QualityApplication.cs

@@ -193,14 +193,14 @@ namespace Hotline.Application.Quality
                     var audioFile = string.Empty;
                     var fromNo = string.Empty;
                     DateTime? callStartTime = null;
-                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
+                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun && !string.IsNullOrEmpty(order.CallId))
                     {
                         var call = await _callApplication.GetTianrunCallAsync(order.CallId, cancellationToken);
                         audioFile = call.RecordingAbsolutePath;
                         fromNo = call.CPN;
                         callStartTime = call.CreatedTime;
                     }
-                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
+                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang && !string.IsNullOrEmpty(order.CallId))
                     {
                         var call = await _callApplication.GetCallAsync(order.CallId, cancellationToken);
                         audioFile = call.AudioFile;
@@ -222,7 +222,7 @@ namespace Hotline.Application.Quality
                 }
                 catch (Exception e)
                 {
-                    _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                    _logger.LogError($"写入智能质检异常1!, \r\n{e.Message}");
                 }
             }
 

+ 5 - 1
src/Hotline.Application/Snapshot/IndustryApplication.cs

@@ -125,6 +125,10 @@ public class IndustryApplication : IIndustryApplication, IScopeDependency
             await _fileRepository.Removeable().Where(m => m.Key == entity.Id).ExecuteCommandAsync(requestAborted);
             await _fileRepository.AddRangeAsync(fileEntities, requestAborted);
         }
+        else
+        {
+            await _fileRepository.Removeable().Where(m => m.Key == entity.Id).ExecuteCommandAsync(requestAborted);
+        }
         dto.Adapt(entity);
         await _industryRepository.UpdateAsync(entity, requestAborted);
     }
@@ -400,7 +404,7 @@ public class IndustryApplication : IIndustryApplication, IScopeDependency
                 PhoneNumber = volunteer.DeclarePhoneNumber,
                 FullAddress = volunteer.Address + volunteer.FullAddress,
             }, true)
-            .Mapper((item, cache)=> 
+            .Mapper((item, cache) =>
             {
                 item.Files = _fileRepository.Queryable()
                 .Where(file => file.Key == item.Id)

+ 15 - 10
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -19,6 +19,7 @@ using Mapster;
 using Microsoft.AspNetCore.Http;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Logging;
+using Microsoft.Identity.Client;
 using SqlSugar;
 using SqlSugar.Extensions;
 using System.ComponentModel;
@@ -357,16 +358,17 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
 
     public async Task RevocationRedPackSpecialAuditAsync(IList<string> ids)
     {
-        var has = await _specialRedPackAuditRepository.Queryable()
-            .Where(m => m.IsSend == true && ids.Contains(m.Id))
+        var specialRedPackAuditIds = await _specialRedPackAuditRepository.Queryable()
+            .LeftJoin<Order>((special, order) => special.OrderId == order.Id)
+            .LeftJoin<RedPackAudit>((special, order, audit) => order.Id == audit.OrderId)
+            .Where((special, order, audit) => ids.Contains(audit.Id))
+            .Select((special, order, audit) => special.Id).ToListAsync();
+        var has = await _supplementRecordRepository.Queryable()
+            .Where(m => specialRedPackAuditIds.Contains(m.RedPackAuditId))
             .AnyAsync();
-        if (has) throw new UserFriendlyException("该工单已发放红包,不能撤销审批");
-        await _specialRedPackAuditRepository.Updateable()
-            .SetColumns(m => m.Status, ERedPackAuditStatus.Pending)
-            .SetColumns(m => m.AuditType, null)
-            .SetColumns(m => m.AuditTypeCode, null)
-            .SetColumns(m => m.AuditRemark, null)
-            .Where(m => ids.Contains(m.Id) && m.IsSend == false)
+        if (has) throw UserFriendlyException.SameMessage("该工单已发放红包,不能撤销审批");
+        await _specialRedPackAuditRepository.Removeable()
+            .Where(m => specialRedPackAuditIds.Contains(m.Id))
             .ExecuteCommandAsync();
     }
 
@@ -760,7 +762,10 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             .WhereIF(dto.Title.NotNullOrEmpty(), (supp, order) => order.Title.Contains(dto.Title))
             .WhereIF(dto.IndustryId.NotNullOrEmpty(), (supp, order) => supp.IndustryId == dto.IndustryId)
             .WhereIF(dto.BeginCreationTime.HasValue && dto.EndCreationTime.HasValue, (supp, order) => supp.CreationTime >= dto.BeginCreationTime && supp.CreationTime <= dto.EndCreationTime)
-            .Select<SnapshotRedPackRecordSupplementItemsOutDto>();
+            .Select((supp, order) => new SnapshotRedPackRecordSupplementItemsOutDto
+            { 
+                Remark = supp.ReplenishRemark
+            }, true);
         return query;
     }
 

+ 6 - 3
src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs

@@ -368,7 +368,10 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
             snapshot.VerifyType = dto.Data.VerifyType;
             snapshot.IsCheckList = dto.Data.IsCheckList;
             snapshot.CompliantType = dto.Data.CompliantType;
-            dto.Workflow.Opinion += $" 核实方式: {dto.Data.VerifyType}  是否按清单检查: {(dto.Data.IsCheckList.Value ? "是" : "否")}";
+            if (dto.Data.VerifyType != null)
+                dto.Workflow.Opinion += $" 核实方式: {dto.Data.VerifyType}";
+            if (dto.Data.IsCheckList.HasValue)
+                dto.Workflow.Opinion += $" 是否按清单检查: {(dto.Data.IsCheckList.Value ? "是" : "否")}";
             await _orderSnapshotRepository.UpdateAsync(snapshot);
             return;
         }
@@ -432,8 +435,8 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
                     .Then(async industry =>
                     {
                         await _fileRepository.Queryable()
-                        .Where(m => m.Classify == EIndustryType.Declare.ToString())
-                        .Select(m => new FileJson { Id = m.Id, FileName = m.Name, Path = m.Path, FileType = m.Type })
+                        .Where(m => m.Key == industry.Id)
+                        .Select(m => new FileJson { Id = m.Additions, FileName = m.Name, Path = m.Path, FileType = m.Type })
                         .ToListAsync()
                         .Then(async file =>
                         {

+ 83 - 60
src/Hotline.Application/StatisticalReport/OrderReportApplication.cs

@@ -1,9 +1,11 @@
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
+using Hotline.Configurations;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Identity.Accounts;
 using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.SeedData;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
@@ -23,6 +25,7 @@ using Hotline.Tools;
 using Hotline.Users;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
 using Quartz.Simpl;
 using SqlSugar;
 using System.Data;
@@ -52,28 +55,29 @@ namespace Hotline.Application.StatisticalReport
         private readonly IRepository<SystemOrganize> _systemOrganizerepository;
         private readonly IRepository<OrderSpecial> _orderSpecialRepository;
         private readonly IRepository<OrderSendBackAudit> _orderSendBackAuditRepository;
-		private readonly IRepository<Hotspot> _hotspotTypeRepository;
-
-		/// <summary>
-		/// 
-		/// </summary>
-		/// <param name="orderRepository"></param>
-		/// <param name="orderVisitDetailRepository"></param>
-		/// <param name="orderDelayRepository"></param>
-		/// <param name="mapper"></param>
-		/// <param name="orderPublishRepository"></param>
-		/// <param name="sessionContext"></param>
-		/// <param name="workflowTraceRepository"></param>
-		/// <param name="orderScreenRepository"></param>
-		/// <param name="sysDicDataCacheManager"></param>
-		/// <param name="trCallRecordRepository"></param>
-		/// <param name="systemSettingCacheManager"></param>
-		/// <param name="userRepository"></param>
-		/// <param name="accountRepository"></param>
-		/// <param name="statisticsDepartRepository"></param>
-		/// <param name="systemOrganizerepository"></param>
-		/// <param name="orderSpecialRepository"></param>
-		public OrderReportApplication(
+        private readonly IRepository<Hotspot> _hotspotTypeRepository;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="orderRepository"></param>
+        /// <param name="orderVisitDetailRepository"></param>
+        /// <param name="orderDelayRepository"></param>
+        /// <param name="mapper"></param>
+        /// <param name="orderPublishRepository"></param>
+        /// <param name="sessionContext"></param>
+        /// <param name="workflowTraceRepository"></param>
+        /// <param name="orderScreenRepository"></param>
+        /// <param name="sysDicDataCacheManager"></param>
+        /// <param name="trCallRecordRepository"></param>
+        /// <param name="systemSettingCacheManager"></param>
+        /// <param name="userRepository"></param>
+        /// <param name="accountRepository"></param>
+        /// <param name="statisticsDepartRepository"></param>
+        /// <param name="systemOrganizerepository"></param>
+        /// <param name="orderSpecialRepository"></param>
+        public OrderReportApplication(
             IOrderRepository orderRepository,
             IRepository<OrderVisitDetail> orderVisitDetailRepository,
             IRepository<OrderDelay> orderDelayRepository,
@@ -91,8 +95,9 @@ namespace Hotline.Application.StatisticalReport
             IRepository<SystemOrganize> systemOrganizerepository,
              IRepository<OrderSpecial> orderSpecialRepository,
              IRepository<OrderSendBackAudit> orderSendBackAuditRepository,
-			IRepository<Hotspot> hotspotTypeRepository
-			)
+            IRepository<Hotspot> hotspotTypeRepository,
+             IOptionsSnapshot<AppConfiguration> appOptions
+            )
         {
             _orderRepository = orderRepository;
             _orderVisitDetailRepository = orderVisitDetailRepository;
@@ -112,8 +117,10 @@ namespace Hotline.Application.StatisticalReport
             _orderSpecialRepository = orderSpecialRepository;
             _orderSendBackAuditRepository = orderSendBackAuditRepository;
             _hotspotTypeRepository = hotspotTypeRepository;
+            _appOptions = appOptions;
 
-		}
+
+        }
 
         #region 宜宾、自贡
         /// <summary>
@@ -2693,6 +2700,7 @@ namespace Hotline.Application.StatisticalReport
                .LeftJoin<WorkflowStep>((o, w) => o.Id == w.ExternalId)
                .Where((o, w) => o.CreationTime >= dto.StartTime && o.CreationTime <= dto.EndTime && w.ModuleCode == WorkflowModuleConsts.OrderHandle
                        && w.Status == EWorkflowStepStatus.WaitForAccept && w.CountersignPosition == ECountersignPosition.None)
+               .WhereIF(_appOptions.Value.IsZiGong, (o, w) => o.Status < EOrderStatus.Filed)//自贡需要排除已办理完成的
                .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (o, w) => o.Source == ESource.ProvinceStraight)
                .WhereIF(dto.TypeId != null && dto.TypeId == 1, (o, w) => o.IdentityType == EIdentityType.Citizen)
                .WhereIF(dto.TypeId != null && dto.TypeId == 2, (o, w) => o.IdentityType == EIdentityType.Enterprise)
@@ -2721,6 +2729,7 @@ namespace Hotline.Application.StatisticalReport
                 .LeftJoin<WorkflowStep>((o, w) => o.Id == w.ExternalId)
                 .Where((o, w) => w.CreationTime >= dto.StartTime && w.CreationTime <= dto.EndTime && w.ModuleCode == WorkflowModuleConsts.OrderHandle
                         && w.Status == EWorkflowStepStatus.WaitForAccept && w.CountersignPosition > ECountersignPosition.None)
+                   .WhereIF(_appOptions.Value.IsZiGong, (o, w) => o.Status < EOrderStatus.Filed)//自贡需要排除已办理完成的
                 .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (o, w) => o.Source == ESource.ProvinceStraight)
                 .WhereIF(dto.TypeId != null && dto.TypeId == 1, (o, w) => o.IdentityType == EIdentityType.Citizen)
                 .WhereIF(dto.TypeId != null && dto.TypeId == 2, (o, w) => o.IdentityType == EIdentityType.Enterprise)
@@ -2773,6 +2782,7 @@ namespace Hotline.Application.StatisticalReport
                     .LeftJoin<WorkflowStep>((o, w) => o.Id == w.ExternalId)
                     .Where((o, w) => w.CreationTime >= dto.StartTime && w.CreationTime <= dto.EndTime && w.ModuleCode == WorkflowModuleConsts.OrderHandle
                             && w.Status == EWorkflowStepStatus.WaitForAccept && w.CountersignPosition > ECountersignPosition.None)
+                       .WhereIF(_appOptions.Value.IsZiGong, (o, w) => o.Status < EOrderStatus.Filed)//自贡需要排除已办理完成的
                     .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (o, w) => o.Source == ESource.ProvinceStraight)
                     .WhereIF(dto.TypeId != null && dto.TypeId == 1, (o, w) => o.IdentityType == EIdentityType.Citizen)
                     .WhereIF(dto.TypeId != null && dto.TypeId == 2, (o, w) => o.IdentityType == EIdentityType.Enterprise)
@@ -2787,6 +2797,7 @@ namespace Hotline.Application.StatisticalReport
                     .LeftJoin<WorkflowStep>((o, w) => o.Id == w.ExternalId)
                     .Where((o, w) => o.CreationTime >= dto.StartTime && o.CreationTime <= dto.EndTime && w.ModuleCode == WorkflowModuleConsts.OrderHandle
                             && w.Status == EWorkflowStepStatus.WaitForAccept && w.CountersignPosition == ECountersignPosition.None)
+                       .WhereIF(_appOptions.Value.IsZiGong, (o, w) => o.Status < EOrderStatus.Filed)//自贡需要排除已办理完成的
                     .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (o, w) => o.Source == ESource.ProvinceStraight)
                     .WhereIF(dto.TypeId != null && dto.TypeId == 1, (o, w) => o.IdentityType == EIdentityType.Citizen)
                     .WhereIF(dto.TypeId != null && dto.TypeId == 2, (o, w) => o.IdentityType == EIdentityType.Enterprise)
@@ -3003,43 +3014,55 @@ namespace Hotline.Application.StatisticalReport
             return query;
         }
 
-		public async Task<DataTable> HotspotStatisticsExprot_LZ(ExportExcelDto<HotspotStatisticsRep> dto)
-		{
-			var IsCenter = _sessionContext.OrgIsCenter;
-			DataTable data = new DataTable();
-
-			data = await _hotspotTypeRepository.Queryable()
-			.LeftJoin<Order>((it, o) => o.HotspotId.StartsWith(it.Id))
-			.Where((it, o) => o.CreationTime >= dto.QueryDto.StartTime && o.CreationTime <= dto.QueryDto.EndTime && o.Id != null)
-			.WhereIF(dto.QueryDto.TypeId == 1, (it, o) => o.IdentityType == EIdentityType.Citizen)
-			.WhereIF(dto.QueryDto.TypeId == 2, (it, o) => o.IdentityType == EIdentityType.Enterprise)
-			.WhereIF(IsCenter == false, (it, o) => o.ActualHandleOrgCode.StartsWith(_sessionContext.RequiredOrgId))
+        public async Task<DataTable> HotspotStatisticsExprot_LZ(ExportExcelDto<HotspotStatisticsRep> dto)
+        {
+            var IsCenter = _sessionContext.OrgIsCenter;
+            DataTable data = new DataTable();
+
+            var  list = await _hotspotTypeRepository.Queryable()
+            .LeftJoin<Order>((it, o) => o.HotspotId.StartsWith(it.Id))
+            .Where((it, o) => o.CreationTime >= dto.QueryDto.StartTime && o.CreationTime <= dto.QueryDto.EndTime && o.Id != null)
+            .WhereIF(dto.QueryDto.TypeId == 1, (it, o) => o.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.QueryDto.TypeId == 2, (it, o) => o.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(IsCenter == false, (it, o) => o.ActualHandleOrgCode.StartsWith(_sessionContext.RequiredOrgId))
             .GroupBy((it, o) => it.Id)
-			.OrderBy((it, o) => new { it.Id }, OrderByType.Asc)
-			.Select((it, o) => new
+            .OrderBy((it, o) => new { it.Id }, OrderByType.Asc)
+            .Select((it, o) => new HotspotStatisticsDto
 			{
-				HotspotName = it.HotSpotName,
-				HotSpotFullName = it.HotSpotFullName,
-				SumCount = SqlFunc.AggregateSum(SqlFunc.IIF(o.HotspotId.StartsWith(it.Id), 1, 0))
-			})
-			.ToDataTableAsync();
-
-			data.Columns["HotspotName"].SetOrdinal(0);
-			data.Columns["HotSpotFullName"].SetOrdinal(1);
+                HotspotName = it.HotSpotName,
+                HotSpotFullName = it.HotSpotFullName,
+                SumCount = SqlFunc.AggregateSum(SqlFunc.IIF(o.HotspotId.StartsWith(it.Id), 1, 0))
+            })
+            .ToListAsync();
+            data = list.ToDataTable("HotspotStatistics");
+
+			data.Columns["Name"].SetOrdinal(0);
+            data.Columns["OneHotspotName"].SetOrdinal(1);
+			data.Columns["TwoHotspotName"].SetOrdinal(2);
+			data.Columns["ThreeHotspotName"].SetOrdinal(3);
+			data.Columns["FourHotspotName"].SetOrdinal(4);
+			data.Columns["FiveHotspotName"].SetOrdinal(5);
 			data.Columns["SumCount"].ColumnName = "分类统计";
-			data.Columns["HotspotName"].ColumnName = "热点名称";
-			data.Columns["HotSpotFullName"].ColumnName = "热点分级";
+            data.Columns["Name"].ColumnName = "热点名称";
+			data.Columns["OneHotspotName"].ColumnName = "一级热点";
+			data.Columns["TwoHotspotName"].ColumnName = "二级热点";
+			data.Columns["ThreeHotspotName"].ColumnName = "三级热点";
+			data.Columns["FourHotspotName"].ColumnName = "四级热点";
+			data.Columns["FiveHotspotName"].ColumnName = "五级热点";
+			data.Columns.Remove("HotSpotFullName");
+			data.Columns.Remove("HotspotName");
+			//data.Columns["HotSpotFullName"].ColumnName = "热点分级";
 			//合计
-			DataRow sumRow = data.NewRow();
-			sumRow["热点名称"] = "合计";
-			decimal totalAmount = 0;
-			foreach (DataRow row in data.Rows)
-			{
-				totalAmount += Convert.ToDecimal(row["分类统计"]);
-			}
-			sumRow["分类统计"] = totalAmount;
-			data.Rows.Add(sumRow);
-            return data;
-		}
-	}
+			//DataRow sumRow = data.NewRow();
+			//         sumRow["热点名称"] = "合计";
+			//         decimal totalAmount = 0;
+			//         foreach (DataRow row in data.Rows)
+			//         {
+			//             totalAmount += Convert.ToDecimal(row["分类统计"]);
+			//         }
+			//         sumRow["分类统计"] = totalAmount;
+			//         data.Rows.Add(sumRow);
+			return data;
+        }
+    }
 }

+ 12 - 1
src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs

@@ -39,6 +39,7 @@ using Hotline.Identity.Accounts;
 using Hotline.Share.Dtos.Enterprise;
 using XF.Domain.Exceptions;
 using Microsoft.AspNetCore.Http;
+using static Hotline.AppDefaults;
 
 namespace Hotline.Repository.SqlSugar.Orders
 {
@@ -1867,9 +1868,18 @@ namespace Hotline.Repository.SqlSugar.Orders
                 .WhereIF(dto.IsScreen.HasValue && dto.IsScreen.Value == false, x => SqlFunc.Subqueryable<OrderScreen>().Where(q => q.OrderId == x.OrderVisit.OrderId && q.VisitDetailId == x.Id).NotAny())
                 .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode),
                             d => SqlFunc.Subqueryable<OrderRelationTag>().InnerJoin<SystemDicData>((s, p) => s.TagId == p.Id).Where((s, p) => p.DicDataValue == dto.OrderTagCode && d.OrderVisit.OrderId == s.OrderId).Any())//工单标签
+               .WhereIF(!string.IsNullOrEmpty(dto.SourceChannelCode), x => x.OrderVisit.Order.SourceChannelCode == dto.SourceChannelCode)
+               .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), x => x.OrderVisit.Order.AcceptTypeCode == dto.AcceptTypeCode)
+               .WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason), x => SqlFunc.JsonListObjectAny(x.OrgNoSatisfiedReason, "Key", dto.OrgNoSatisfiedReason))
+               .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), x => x.OrderVisit.Order.AreaCode == dto.AreaCode)
                 .Select(x => new OrgVisitDetailListResp()
                 {
                     Id = x.Id,
+                    SourceChannel = x.OrderVisit.Order.SourceChannel,
+                    AcceptType = x.OrderVisit.Order.AcceptType,
+                    OrgNoSatisfiedReasonText = SqlFunc.MappingColumn<string>("(SELECT string_agg(elem->> 'Value', ',') FROM jsonb_array_elements(\"OrgNoSatisfiedReason\"::jsonb) elem )"),
+                    City = x.OrderVisit.Order.City,
+                    County = x.OrderVisit.Order.County,
                     OrderId = x.OrderVisit.Order.Id,
                     VisitId = x.OrderVisit.Id,
                     No = x.OrderVisit.No,
@@ -1894,7 +1904,8 @@ namespace Hotline.Repository.SqlSugar.Orders
                     IsProvinceOrder = x.OrderVisit.Order.IsProvince,
                     OrderTag = SqlFunc.Subqueryable<OrderRelationTag>().InnerJoin<SystemDicData>((s, p) => s.TagId == p.Id).Where((s, p) => x.OrderVisit.OrderId == s.OrderId)
 .SelectStringJoin((s, p) => p.DicDataName, ",")
-                }).MergeTable().OrderByIF(string.IsNullOrEmpty(dto.SortField), x => x.VisitTime, OrderByType.Desc)
+                })
+                .MergeTable().OrderByIF(string.IsNullOrEmpty(dto.SortField), x => x.VisitTime, OrderByType.Desc)
                 .OrderByIF(dto is { SortField: "orderScreenStatusText", SortRule: 0 }, x => x.OrderScreenStatus, OrderByType.Asc)
                 .OrderByIF(dto is { SortField: "orderScreenStatusText", SortRule: 1 }, x => x.OrderScreenStatus, OrderByType.Desc)
                 .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, x => x.CreationTime, OrderByType.Asc) //受理时间升序

+ 22 - 2
src/Hotline.Share/Dtos/Article/BulletinDto.cs

@@ -545,6 +545,27 @@ namespace Hotline.Share.Dtos.Article
         public string IndustryId { get; set; }
     }
 
+    public class BulletinListOutDto
+    { 
+        /// <summary>
+        /// 公告ID
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string Title { get; set; }
+
+        private string content;
+        /// <summary>
+        /// 内容
+        /// </summary>
+        public string Content { get { return content.RemoveHtmlTags(); } set { content = value; } }
+
+        public DateTime CreationTime { get; set; }
+    }
+
     /// <summary>
     /// 微信小程序获取宣传学习列表出参
     /// </summary>
@@ -560,11 +581,10 @@ namespace Hotline.Share.Dtos.Article
         /// </summary>
         public string Title { get; set; }
 
-        private string content;
         /// <summary>
         /// 内容
         /// </summary>
-        public string Content { get { return content.RemoveHtmlTags(); } set { content = value; } }
+        public string Content { get; set; }
 
         public DateTime CreationTime { get; set; }
     }

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

@@ -58,6 +58,7 @@ public class NextStepsDto
     /// 当前节点是否是会签结束节点
     /// </summary>
     public bool CurrentIsCountersignEndStep { get; set; }
+    public bool CurrentIsTopCountersignEndStep { get; set; }
 
     /// <summary>
     /// 时间类型

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

@@ -18,6 +18,10 @@ public class PreviousWorkflowDto : EndWorkflowIdDto
     //public FlowStepHandler? Handler { get; set; }
     public StepAssignInfo? Handler { get; set; }
 
+    /// <summary>
+    /// 是否退回至申请人
+    /// </summary>
+    public bool IsRecallToStartStep { get; set; }
     // /// <summary>
     // /// 逆向流程,节点指派方式
     // /// 退回、特提

+ 44 - 8
src/Hotline.Share/Dtos/Order/OrderBiDto.cs

@@ -544,6 +544,41 @@ namespace Hotline.Share.Dtos.Order
         /// 工单标签(自贡)
         /// </summary>
         public string? OrderTag { get; set; }
+
+        /// <summary>
+        /// 来源渠道
+        /// </summary>
+        public string? SourceChannel { get; set; }
+
+        /// <summary>
+        /// 受理类型
+        /// </summary>
+        public string? AcceptType { get; set; }
+
+        /// <summary>
+        /// 不满意原因
+        /// </summary>
+        public string OrgNoSatisfiedReasonText { get; set; }
+
+        /// <summary>
+        /// 不满意原因字符串
+        /// </summary>
+        //public string OrgNoSatisfiedReasonText => OrgNoSatisfiedReason != null ? string.Join(',', OrgNoSatisfiedReason.Select(d => d.Value)) : "";
+
+        /// <summary>
+        /// 市
+        /// </summary>
+        public string? City { get; set; }
+
+        /// <summary>
+        /// 区/县
+        /// </summary>
+        public string? County { get; set; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        public string? Area => string.IsNullOrEmpty(County) == false ? County : City;
     }
 
 
@@ -1559,7 +1594,8 @@ namespace Hotline.Share.Dtos.Order
         public int DutyDeskNum { get; set; }
     }
 
-    public class ExtendedSendBackVo {
+    public class ExtendedSendBackVo
+    {
 
         /// <summary>
         /// 部门Id
@@ -1595,7 +1631,7 @@ namespace Hotline.Share.Dtos.Order
 
     public class OnlineMassLineReportRes
     {
-       
+
         /// <summary>
         /// 受理渠道
         /// </summary>
@@ -1617,12 +1653,12 @@ namespace Hotline.Share.Dtos.Order
         public double Chain => PreviousCount == 0 ? 0 : Math.Round((SumCount / (double)PreviousCount) * 100, 2);
     }
 
-	public class OrgSendBackAuditListVo
-	{
-		public string OrgId { get; set; }
+    public class OrgSendBackAuditListVo
+    {
+        public string OrgId { get; set; }
 
-		public string OrgName { get; set; }
+        public string OrgName { get; set; }
 
-		public int Num { get; set; }
-	}
+        public int Num { get; set; }
+    }
 }

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

@@ -7,8 +7,6 @@ using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Requests;
-using Hotline.Share.Tools;
-using Novacode;
 using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Order
@@ -41,12 +39,9 @@ namespace Hotline.Share.Dtos.Order
 
         public string StatusText => Status.GetDescription();
 
-        /// <summary>
-		/// 终止状态
-		/// </summary>
-        public ETerminateStatus? TerminateStatus { get; set; }
+        public string? TerminateStatusText => IsTerminate == true ? "终止同意" : "";
 
-        public string? TerminateStatusText => TerminateStatus?.GetDescription();
+        public bool IsTerminate { get; set; }
     }
 
     public class OrderDto : UpdateOrderDto
@@ -814,6 +809,11 @@ namespace Hotline.Share.Dtos.Order
 
         public int ReTransactNum { get; set; }
 
+        /// <summary>
+        /// 回访重办次数
+        /// </summary>
+        public int? VisitReTransactNum { get; set; }
+
         /// <summary>
         /// 省重办次数
         /// </summary>
@@ -1198,6 +1198,7 @@ namespace Hotline.Share.Dtos.Order
         /// 能否编辑,true:任何节点可以编辑;false:未发起流程可以编辑
         /// </summary>
         public bool IsEdit { get; set; }
+
     }
 
     public class OrderUploadFiles
@@ -1217,6 +1218,15 @@ namespace Hotline.Share.Dtos.Order
     public class AddOrderDto : Position
     {
         #region 来电信息
+        /// <summary>
+        /// 政治身份
+        /// </summary>
+        public string? PoliticalIdentityValue { get; set; }
+
+        /// <summary>
+        /// 政治身份
+        /// </summary>
+        public string? PoliticalIdentityName { get; set; }
 
         /// <summary>
         /// 来源渠道

+ 36 - 1
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -153,6 +153,11 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool? IsUpdate { get; set; }
 
+        /// <summary>
+        /// 回访人是否为空
+        /// </summary>
+        public bool? IsEmployeeNameNull { get; set;}
+
     }
 
     public record QueryOrderPublishStatisticsAllDto : PagedRequest
@@ -476,7 +481,18 @@ namespace Hotline.Share.Dtos.Order
         public bool? IsUpdate { get; set; }
 
         public List<VisitDetailDto> VisitDetails { get; set; }
-    }
+
+        /// <summary>
+        /// 是否重办
+        /// </summary>
+        public bool? IsTransact { get; set; }
+
+        /// <summary>
+        /// 重办对象
+        /// </summary>
+        public OrderReTransactDto? OrderReTransact { get; set; }
+
+	}
 
     public record VisitDetailDto
     {
@@ -812,6 +828,25 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public List<OrderVisitDetailDto> OrderVisitDetails { get; set; }
 
+        /// <summary>
+        /// 坐席满意度
+        /// </summary>
+        public ESeatEvaluate? SeatEvaluate => OrderVisitDetails?.Where(x => x.VisitTarget == EVisitTarget.Seat).FirstOrDefault()?.SeatEvaluate;
+
+        /// <summary>
+        /// 坐席满意度
+        /// </summary>
+        public string? SeatEvaluateText => SeatEvaluate?.GetDescription() ?? string.Empty;
+
+        /// <summary>
+        /// 部门满意度
+        /// </summary>
+        public Kv? OrgProcessingResults => OrderVisitDetails?.Where(x => x.VisitTarget == EVisitTarget.Org).FirstOrDefault()?.OrgProcessingResults;
+
+        /// <summary>
+        /// 回复内容
+        /// </summary>
+        public string? VisitContent => OrderVisitDetails?.Where(x => x.VisitTarget == EVisitTarget.Org).FirstOrDefault()?.VisitContent ?? string.Empty;
 
         /// <summary>
         /// 可直接访问的通话录音地址

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

@@ -10,6 +10,11 @@ namespace Hotline.Share.Dtos.Order
 {
     public record QueryOrderDto : PagedKeywordRequest
     {
+        /// <summary>
+        /// 政治身份
+        /// </summary>
+        public string? PoliticalIdentityValue {  get; set; }
+
         /// <summary>
         /// 省本地编号(√)
         /// </summary>

+ 2 - 2
src/Hotline.Share/Dtos/Push/MessagePagedDto.cs

@@ -23,12 +23,12 @@ namespace Hotline.Share.Dtos.Push
         /// <summary>
         /// 开始时间
         /// </summary>
-        public DateTime? StartTime { get; set; }
+        public DateTime? CreationStartTime { get; set; }
 
         /// <summary>
         /// 结束时间
         /// </summary>
-        public DateTime? EndTime { get; set; }
+        public DateTime? CreationEndTime { get; set; }
 
         /// <summary>
         /// 电话号码

+ 65 - 18
src/Hotline.Share/Dtos/Snapshot/OrderDto.cs

@@ -229,24 +229,71 @@ public class AddSnapshotOrderInDto : Position
 /// <param name="ApprovedAmount">审批金额</param>
 /// <param name="IsDanger">是否安全生成</param>
 /// <param name="Status">审核状态: -1: 全部; 0: 待审批; 1: 同意; 2: 拒绝;</param>
-public record SnapshotOrderAuditItemsInDto(string? No, string? Title,
-    string? FromPhone,
-    DateTime? BeginCreationTime,
-    DateTime? EndCreationTime,
-    bool? IsDeal,
-    bool? IsTruth,
-    bool? IsTruthDepartment,
-    DateTime? BeginAuditTime,
-    DateTime? EndAuditTime,
-    DateTime? BeginFiledTime,
-    DateTime? EndFiledTime,
-    bool? IsIssued,
-    string? IndustryId,
-    double? ConfigAmount,
-    double? AcutalAmount,
-    double? ApprovedAmount,
-    bool? IsDanger,
-    int? Status) : PagedRequest;
+public record SnapshotOrderAuditItemsInDto : PagedRequest
+{
+    public SnapshotOrderAuditItemsInDto() { }
+
+    public SnapshotOrderAuditItemsInDto(string? no, string? title,
+        string? fromPhone,
+        DateTime? beginCreationTime,
+        DateTime? endCreationTime,
+        bool? isDeal,
+        bool? isTruth,
+        bool? isTruthDepartment,
+        DateTime? beginAuditTime,
+        DateTime? endAuditTime,
+        DateTime? beginFiledTime,
+        DateTime? endFiledTime,
+        bool? isIssued,
+        string? industryId,
+        double? configAmount,
+        double? acutalAmount,
+        double? approvedAmount,
+        bool? isDanger,
+        int? status)
+    {
+        No = no;
+        Title = title;
+        FromPhone = fromPhone;
+        BeginCreationTime = beginCreationTime;
+        EndCreationTime = endCreationTime;
+        IsDeal = isDeal;
+        IsTruth = isTruth;
+        IsTruthDepartment = isTruthDepartment;
+        BeginAuditTime = beginAuditTime;
+        EndAuditTime = endAuditTime;
+        BeginFiledTime = beginFiledTime;
+        EndFiledTime = endFiledTime;
+        IsIssued = isIssued;
+        IndustryId = industryId;
+        ConfigAmount = configAmount;
+        AcutalAmount = acutalAmount;
+        ApprovedAmount = approvedAmount;
+        IsDanger = isDanger;
+        Status = status;
+    }
+
+    public string? No { get; set; }
+    public string? Title { get; set; }
+    public string? FromPhone { get; set; }
+    public DateTime? BeginCreationTime { get; set; }
+    public DateTime? EndCreationTime { get; set; }
+    public bool? IsDeal { get; set; }
+    public bool? IsTruth { get; set; }
+    public bool? IsTruthDepartment { get; set; }
+    public DateTime? BeginAuditTime { get; set; }
+    public DateTime? EndAuditTime { get; set; }
+    public DateTime? BeginFiledTime { get; set; }
+    public DateTime? EndFiledTime { get; set; }
+    public bool? IsIssued { get; set; }
+    public string? IndustryId { get; set; }
+    public double? ConfigAmount { get; set; }
+    public double? AcutalAmount { get; set; }
+    public double? ApprovedAmount { get; set; }
+    public bool? IsDanger { get; set; }
+    public int? Status { get; set; }
+}
+
 
 public class SnapshotOrderAuditItemsOutDto
 {

+ 9 - 0
src/Hotline.Share/Dtos/Snapshot/RedPackDto.cs

@@ -256,6 +256,15 @@ public class SnapshotRedPackRecordSupplementItemsOutDto
     /// </summary>
     public string? ReplenishTypeId { get; set; }
 
+    /// <summary>
+    /// 补充奖励类型
+    /// </summary>
+    public string AuditType { get; set; }
+
+    /// <summary>
+    /// 补充奖励类型Code
+    /// </summary>
+    public string AuditTypeCode { get; set; }
 }
 
 public record SnapshotRedPackRecordSupplementItemsInDto : PagedRequest

+ 47 - 0
src/Hotline.Share/Dtos/StatisticalReport/OrderDelayStatisicalReturnDto.cs

@@ -44,4 +44,51 @@ namespace Hotline.Share.Dtos.StatisticalReport
         /// </summary>
         public string NodeCode { get; set; }
     }
+
+    public class HotspotStatisticsDto { 
+    
+        /// <summary>
+        /// 分类名称
+        /// </summary>
+        public string HotspotName { get; set; }
+
+        /// <summary>
+        /// 分类全称
+        /// </summary>
+        public string HotSpotFullName { get; set; }
+
+		/// <summary>
+		/// 热点名称
+		/// </summary>
+		public string Name => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length >= 1 && HotSpotFullName.Split("-")[0] == HotspotName ? HotSpotFullName.Split("-")[0] : string.Empty;
+
+		/// <summary>
+		/// 一级热点
+		/// </summary>
+		public string OneHotspotName => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length == 1  ? HotSpotFullName.Split("-")[0] : string.Empty;
+
+        /// <summary>
+        /// 二级热点
+        /// </summary>
+        public string TwoHotspotName => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length == 2  ? HotSpotFullName.Split("-")[1] : string.Empty;
+
+        /// <summary>
+        /// 三级热点
+        /// </summary>
+        public string ThreeHotspotName => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length == 3 ? HotSpotFullName.Split("-")[2] : string.Empty;
+
+        /// <summary>
+        /// 四级热点
+        /// </summary>
+        public string FourHotspotName => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length == 4  ? HotSpotFullName.Split("-")[3] : string.Empty;
+
+        /// <summary>
+        /// 五级热点
+        /// </summary>
+        public string FiveHotspotName => !string.IsNullOrEmpty(HotSpotFullName) && HotSpotFullName.Split("-").Length == 5 ? HotSpotFullName.Split("-")[4] : string.Empty;
+
+
+        public int SumCount { get; set; }
+
+	}
 }

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

@@ -72,4 +72,10 @@ public enum EHandleMode
     /// </summary>
     [Description("发布退回")]
     PublishPrevious = 203,
+
+	/// <summary>
+	/// 撤销
+	/// </summary>
+	[Description("撤销")]
+	Revocation = 204,
 }

+ 22 - 0
src/Hotline.Share/Enums/Order/EOrderUpdateSource.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+	public enum EOrderUpdateSource
+	{
+		/// <summary>
+		/// 受理列表
+		/// </summary>
+		Accepted = 0,
+
+		/// <summary>
+		/// 工单修改
+		/// </summary>
+		Alter =1
+
+	}
+}

+ 34 - 0
src/Hotline.Share/Requests/PagedKeywordRequest.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using System.ComponentModel.DataAnnotations;
 using XF.Utility.EnumExtensions;
@@ -371,6 +372,19 @@ public record VisitMeasureStatisticsRequest
     public string? VisitName { get; set; }
 }
 
+public record AiVisitNoSatisfiedPageListRequest : PagedRequest
+{
+    public DateTime StartTime { get; set; }
+    public DateTime EndTime { get; set; }
+
+    public string? VisitName { get; set; }
+}
+
+public class AiVisitNoSatisfiedPageListRep
+{
+    public OrderVisitDto OrderVisit { get; set; }
+}
+
 public record HotspotReportPagedRequest : ReportPagedRequest
 {
 
@@ -688,6 +702,26 @@ public record OrgVisitDetailListReq : PagedKeywordRequest
     /// 工单标签Code
     /// </summary>
     public string? OrderTagCode { get; set; }
+
+    /// <summary>
+    /// 来源渠道
+    /// </summary>
+    public string? SourceChannelCode { get; set; }
+
+    /// <summary>
+    /// 受理类型
+    /// </summary>
+    public string? AcceptTypeCode { get; set; }
+
+    /// <summary>
+    /// 不满意原因
+    /// </summary>
+    public string? OrgNoSatisfiedReason { get; set; }
+
+    /// <summary>
+    /// 区域
+    /// </summary>
+    public string? AreaCode {  get; set; }
 }
 
 

+ 6 - 5
src/Hotline.WeChat/Hotline.WeChat.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>net8.0</TargetFramework>
@@ -7,10 +7,11 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <PackageReference Include="Senparc.Weixin" Version="6.19.1" />
-    <PackageReference Include="Senparc.Weixin.AspNet" Version="1.3.1" />
-    <PackageReference Include="Senparc.Weixin.Open" Version="4.20.0" />
-    <PackageReference Include="Senparc.Weixin.WxOpen" Version="3.20.1" />
+    <PackageReference Include="Senparc.CO2NET.Cache.CsRedis" Version="2.2.0.1" />
+    <PackageReference Include="Senparc.Weixin" Version="6.22.0" />
+    <PackageReference Include="Senparc.Weixin.AspNet" Version="1.4.9" />
+    <PackageReference Include="Senparc.Weixin.Open" Version="4.21.11" />
+    <PackageReference Include="Senparc.Weixin.WxOpen" Version="3.23.4" />
   </ItemGroup>
 
   <ItemGroup>

+ 15 - 17
src/Hotline.WeChat/ServiceCollectionExtensions.cs

@@ -15,20 +15,17 @@ using Microsoft.Extensions.Options;
 using Senparc.CO2NET;
 using Senparc.Weixin;
 using Senparc.Weixin.Entities;
+using XF.Domain.Options;
 
 namespace Hotline.WeChat;
 public static class ServiceCollectionExtensions
 {
-    public static IServiceCollection AddWeChatService(this IServiceCollection services)
+    private readonly static string KeyName = "WxOpenAppId";
+    public static IServiceCollection AddWeChatService(this IServiceCollection services, ConfigurationManager configuration)
     {
-        var configuration = new ConfigurationManager();
-        configuration.AddInMemoryCollection(new Dictionary<string, string>
-        {
-            { "SenparcWeixinSetting:WxOpenAppId", "#{WxOpenAppId}#" },
-            { "SenparcWeixinSetting:WxOpenAppSecret", "#{WxOpenAppSecret}#" },
-            { "SenparcWeixinSetting:WxOpenToken", "#{WxOpenToken}#" },
-            { "SenparcWeixinSetting:WxOpenEncodingAESKey", "#{WxOpenEncodingAESKey}#" }
-        });
+        var config = configuration.GetSection(nameof(SenparcWeixinSetting));
+        if (config.GetSection(KeyName).Value == null) return services;
+        services.Configure<Configurations.SenparcWeixinSetting>(d => configuration.GetSection(nameof(SenparcWeixinSetting)).Bind(d));
         services.AddMemoryCache();
         services.AddSenparcWeixin(configuration);
         return services;
@@ -36,14 +33,15 @@ public static class ServiceCollectionExtensions
 
     public static void UseWeChat(this WebApplication app)
     {
+        if (app.Configuration.GetSection(nameof(SenparcWeixinSetting)).GetSection(KeyName).Value == null) return;
         var registerService = app.UseSenparcWeixin(app.Environment,
-          null /* 不为 null 则覆盖 appsettings  中的 SenpacSetting 配置*/,
-          null /* 不为 null 则覆盖 appsettings  中的 SenpacWeixinSetting 配置*/,
-          register => { },
-          (register, weixinSetting) =>
-          {
-              //注册公众号信息(可以执行多次,注册多个小程序)
-              register.RegisterWxOpenAccount(weixinSetting, "微信小程序");
-          });
+        null /* 不为 null 则覆盖 appsettings  中的 SenpacSetting 配置*/,
+        null /* 不为 null 则覆盖 appsettings  中的 SenpacWeixinSetting 配置*/,
+        register => { },
+        (register, weixinSetting) =>
+        {
+            //注册公众号信息(可以执行多次,注册多个小程序)
+            register.RegisterWxOpenAccount(weixinSetting, "微信小程序");
+        });
     }
 }

+ 5 - 0
src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs

@@ -101,5 +101,10 @@ namespace Hotline.Caching.Interfaces
         /// 额外扣除积分类型
         /// </summary>
         IReadOnlyCollection<SystemDicDataOutDto> ExtraDeductionPointsType { get; }
+
+        /// <summary>
+        /// 随手拍重办原因
+        /// </summary>
+        IReadOnlyList<SystemDicData> InstaShotSpecialReason { get; }
     }
 }

+ 5 - 0
src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs

@@ -70,6 +70,11 @@ namespace Hotline.Caching.Interfaces
         /// </summary>
         string WxOpenAppId { get; }
 
+        /// <summary>
+        /// 微信ApiHost
+        /// </summary>
+        string WxApiHost { get; }
+
         /// <summary>
         /// 文件服务器地址
         /// </summary>

+ 9 - 2
src/Hotline/Caching/Services/SysDicDataCacheManager.cs

@@ -34,9 +34,14 @@ namespace Hotline.Caching.Services
         }
 
         public IReadOnlyList<SystemDicDataOutDto> GetOrAdd(string code)
+        {
+            return GetOrAddDic(code).Adapt<IReadOnlyList<SystemDicDataOutDto>>();
+        }
+
+        public IReadOnlyList<SystemDicData> GetOrAddDic(string code)
         {
             var items = GetSysDicDataCache(code);
-            if (items.NotNullOrEmpty()) return items.Adapt<IReadOnlyList<SystemDicDataOutDto>>();
+            if (items.NotNullOrEmpty()) return items;
 
             var any = _sysDicDataRepository.Queryable().Where(m => m.DicTypeCode == code).Any();
             if (any) return [];
@@ -52,7 +57,7 @@ namespace Hotline.Caching.Services
             AssignChilderDicType(sysDicDatas.ToList(), code, sysDicType.Id);
 
             RemoveSysDicDataCache(code);
-            return GetSysDicDataCache(code).Adapt<IReadOnlyList<SystemDicDataOutDto>>();
+            return GetSysDicDataCache(code);
         }
 
         private void AssignChilderDicType(IList<SystemDicData> sysDicDatas, string code, string dicTypeId, string parentId = "")
@@ -155,6 +160,8 @@ namespace Hotline.Caching.Services
         /// </summary>
         public IReadOnlyCollection<SystemDicDataOutDto> XingTangOperationMap => GetOrAdd(SysDicTypeConsts.XingTangOperationMap);
 
+        public IReadOnlyList<SystemDicData> InstaShotSpecialReason => GetOrAddDic(SysDicTypeConsts.InstaShotSpecialReason);
+
         public void RemoveSysDicDataCache(string code)
         {
             _cacheSysDicData.Remove(code);

+ 25 - 3
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -1,8 +1,14 @@
 using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.Settings;
 using Hotline.Share.Tools;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
 using Newtonsoft.Json.Linq;
+using System.Reflection.Metadata.Ecma335;
 using XF.Domain.Cache;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
@@ -16,12 +22,14 @@ namespace Hotline.Caching.Services
         private readonly ILogger<SystemSettingCacheManager> _logger;
         private readonly ITypedCache<SystemSetting> _cacheSystemSetting;
         private readonly IRepository<SystemSetting> _systemSettingRepository;
+        private readonly IOptionsSnapshot<SenparcWeixinSetting> _senparcWeixin;
 
-        public SystemSettingCacheManager(ITypedCache<SystemSetting> cacheSystemSetting, IRepository<SystemSetting> systemSettingRepository, ILogger<SystemSettingCacheManager> logger)
+        public SystemSettingCacheManager(ITypedCache<SystemSetting> cacheSystemSetting, IRepository<SystemSetting> systemSettingRepository, ILogger<SystemSettingCacheManager> logger, IOptionsSnapshot<SenparcWeixinSetting> senparcWeixin)
         {
             _cacheSystemSetting = cacheSystemSetting;
             _systemSettingRepository = systemSettingRepository;
             _logger = logger;
+            _senparcWeixin = senparcWeixin;
         }
 
         public SystemSetting? GetSetting(string code)
@@ -166,6 +174,12 @@ namespace Hotline.Caching.Services
         public string WxOpenAppId =>
             GetOrDefault("08dccbbc-090a-4446-842f-be95fc74c95e", SettingConstants.WxOpenAppId, "微信小程序OpenId", "wx22e6092dd504b567", "微信小程序OpenId");
 
+        /// <summary>
+        /// 微信小程序WebApi地址
+        /// </summary>
+        public string WxApiHost =>
+            GetOrDefault("fafcd1b0-72fb-cfe0-7c82-3a1926c8a6cb", SettingConstants.WxApiHost, "微信小程序WebApi", "https://api.weixin.qq.com", "微信小程序WebApi");
+
         /// <summary>
         /// 文件服务器地址
         /// </summary>
@@ -203,8 +217,15 @@ namespace Hotline.Caching.Services
         /// <summary>
         /// 随手拍功能开关
         /// </summary>
-        public bool Snapshot =>
-            GetOrDefault("08dd0eca-66b8-4c98-8dec-0c76c29d77e3", SettingConstants.Snapshot, "随手拍功能开关", false, "随手拍功能开关");
+        public bool Snapshot
+        {
+            get
+            {
+                var switchBtn = GetOrDefault("08dd0eca-66b8-4c98-8dec-0c76c29d77e3", SettingConstants.Snapshot, "随手拍功能开关", false, "随手拍功能开关");
+                if (_senparcWeixin.Value.WxOpenAppId == null) return false;
+                return switchBtn;
+            }
+        }
 
         /// <summary>
         /// 是否开启自动填写办理意见至汇总节点
@@ -217,5 +238,6 @@ namespace Hotline.Caching.Services
         public bool IsNoPushCallNativeOutNoFile => GetOrDefault("08dd23d1-5c5b-4262-8c99-8c83710723ea", SettingConstants.IsNoPushCallNativeOutNoFile, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)", true, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)");
 
         public bool IsSendDissatisfiedScreenSms => GetOrDefault("08db29ad-9b54-44ca-8d4d-35c032748040", SettingConstants.IsSendDissatisfiedScreenSms, "回访不满意是否发送甄别短信", true, "true:发送;false:不发送");
+
     }
 }

+ 12 - 0
src/Hotline/Configurations/SenparcWeixinSetting.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Configurations;
+
+public class SenparcWeixinSetting
+{
+    public string WxOpenAppId { get; set; }
+}

+ 13 - 1
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -46,6 +46,15 @@ namespace Hotline.FlowEngine.Workflows
             Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,
             CancellationToken cancellationToken = default);
 
+        Task<(Workflow, WorkflowStep, StepDefine, List<WorkflowStep>)> NextAsync(
+            Workflow workflow,
+            NextWorkflowDto dto,
+            EHandleMode handleMode = EHandleMode.Normal,
+            DateTime? expiredTime = null, bool isAutoFillSummaryOpinion = false,
+            Action<Workflow, WorkflowStep, StepDefine>? currentStepConfig = null,
+            Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,
+            CancellationToken cancellationToken = default);
+
         /// <summary>
         /// 开启流程并办理至第一个节点
         /// </summary>
@@ -94,7 +103,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
                 WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)> PreviousAsync
-            (Workflow workflow, PreviousWorkflowDto dto, OperatorInfo operatorInfo, 
+            (Workflow workflow, PreviousWorkflowDto dto, OperatorInfo operatorInfo,
                 EHandleMode handleMode = EHandleMode.Previous,
                 Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
                 CancellationToken cancellationToken = default);
@@ -134,6 +143,9 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 撤回至开始节点
         /// </summary>
+        Task RecallToStartStepAsync(string workflowId, string opinion, DateTime? expiredTime, bool isOrderFiled, EHandleMode handleMode,
+    EFlowAssignType? flowAssignType = EFlowAssignType.Role, CancellationToken cancellationToken = default);
+
         Task RecallToStartStepAsync(Workflow workflow, string opinion, DateTime? expiredTime, bool isOrderFiled, EHandleMode handleMode,
             EFlowAssignType? flowAssignType = EFlowAssignType.Role, CancellationToken cancellationToken = default);
 

+ 91 - 44
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -16,17 +16,13 @@ using SqlSugar;
 using Hotline.EventBus;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
-using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using System.Text;
-using FluentValidation;
 using Hotline.Configurations;
 using Hotline.Share.Dtos.File;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
-using Hotline.Validators.FlowEngine;
 using Microsoft.Extensions.Options;
-using Microsoft.AspNetCore.Http;
 
 namespace Hotline.FlowEngine.Workflows
 {
@@ -293,6 +289,20 @@ namespace Hotline.FlowEngine.Workflows
         {
             var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
                 withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
+
+            return await NextAsync(workflow, dto, handleMode, expiredTime, isAutoFillSummaryOpinion, currentStepConfig,
+                newStepConfig, cancellationToken);
+        }
+
+        public async Task<(Workflow, WorkflowStep, StepDefine, List<WorkflowStep>)> NextAsync(
+            Workflow workflow,
+            NextWorkflowDto dto,
+            EHandleMode handleMode = EHandleMode.Normal,
+            DateTime? expiredTime = null, bool isAutoFillSummaryOpinion = false,
+            Action<Workflow, WorkflowStep, StepDefine>? currentStepConfig = null,
+            Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,
+            CancellationToken cancellationToken = default)
+        {
             CheckWhetherRunnable(workflow.Status);
 
             var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == dto.StepId);
@@ -477,7 +487,8 @@ namespace Hotline.FlowEngine.Workflows
                 }
             }
 
-            await Task.Run(() => currentStepConfig?.Invoke(workflow, currentStep, nextStepDefine), cancellationToken);
+            //await Task.Run(() => currentStepConfig?.Invoke(workflow, currentStep, nextStepDefine), cancellationToken);
+            currentStepConfig?.Invoke(workflow, currentStep, nextStepDefine);
             await _workflowStepRepository.UpdateRangeAsync(updateSteps, cancellationToken);
 
             //更新traces
@@ -622,11 +633,10 @@ namespace Hotline.FlowEngine.Workflows
             var nextDto = _mapper.Map<NextWorkflowDto>(dto);
             nextDto.WorkflowId = workflow.Id;
             nextDto.StepId = startStep.Id;
-            var (_, _, _, nextSteps) =
-                await NextAsync(nextDto,
-                    expiredTime: expiredTime,
-                    isAutoFillSummaryOpinion: true,
-                    newStepConfig: newStepConfig, cancellationToken: cancellationToken);
+            var (_, _, _, nextSteps) = await NextAsync(workflow, nextDto,
+                expiredTime: expiredTime,
+                isAutoFillSummaryOpinion: true,
+                newStepConfig: newStepConfig, cancellationToken: cancellationToken);
             return nextSteps;
         }
 
@@ -1056,7 +1066,7 @@ namespace Hotline.FlowEngine.Workflows
             PreviousAsync(PreviousWorkflowDto dto,
                 EHandleMode handleMode = EHandleMode.Previous,
                 Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
-            CancellationToken cancellationToken = default)
+                CancellationToken cancellationToken = default)
         {
             var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
                 withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
@@ -1402,10 +1412,10 @@ namespace Hotline.FlowEngine.Workflows
         {
             //根据汇总对象id找到被汇总节点
             var summaryTargetStep = workflow.Steps.Where(d =>
-                d.StepType == EStepType.Normal &&
-                d.Code == summaryTargetStepCode &&
-                d.Status == EWorkflowStepStatus.Handled &&
-                d.IsOrigin)
+                    d.StepType == EStepType.Normal &&
+                    d.Code == summaryTargetStepCode &&
+                    d.Status == EWorkflowStepStatus.Handled &&
+                    d.IsOrigin)
                 .MaxBy(d => d.CreationTime);
             if (summaryTargetStep is null)
                 throw UserFriendlyException.SameMessage("未查询到汇总对象节点");
@@ -1808,6 +1818,15 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 撤回至开始节点
         /// </summary>
+        public async Task RecallToStartStepAsync(string workflowId, string opinion, DateTime? expiredTime, bool isOrderFiled,
+            EHandleMode handleMode, EFlowAssignType? flowAssignType = EFlowAssignType.Role, CancellationToken cancellationToken = default)
+        {
+            var workflow = await GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, withTraces: true, withCountersigns: true,
+                cancellationToken: cancellationToken);
+
+            await RecallToStartStepAsync(workflow, opinion, expiredTime, isOrderFiled, handleMode, flowAssignType, cancellationToken);
+        }
+
         public async Task RecallToStartStepAsync(Workflow workflow, string opinion,
             DateTime? expiredTime, bool isOrderFiled, EHandleMode handleMode, EFlowAssignType? flowAssignType,
             CancellationToken cancellationToken = default)
@@ -1821,6 +1840,59 @@ namespace Hotline.FlowEngine.Workflows
             //await RecallToTargetStepAsync(workflow, startStep, opinion, current, cancellationToken);
 
             var startStepDefine = workflow.WorkflowDefinition.Steps.FirstOrDefault(d => d.StepType == EStepType.Start);
+
+            var stepAssignInfo = flowAssignType switch
+            {
+                EFlowAssignType.Org => new StepAssignInfo
+                {
+                    Key = startStep.HandlerOrgId,
+                    Value = startStep.HandlerOrgName,
+                    RoleId = startStep.RoleId,
+                    RoleName = startStep.RoleName,
+                    UserId = startStep.HandlerId,
+                    Username = startStep.HandlerName,
+                    OrgId = startStep.HandlerOrgId,
+                    OrgName = startStep.HandlerOrgName,
+                    FlowAssignType = EFlowAssignType.Org
+                },
+                EFlowAssignType.User => new StepAssignInfo
+                {
+                    Key = startStep.HandlerId,
+                    Value = startStep.HandlerName,
+                    RoleId = startStep.RoleId,
+                    RoleName = startStep.RoleName,
+                    UserId = startStep.HandlerId,
+                    Username = startStep.HandlerName,
+                    OrgId = startStep.HandlerOrgId,
+                    OrgName = startStep.HandlerOrgName,
+                    FlowAssignType = EFlowAssignType.User
+                },
+                EFlowAssignType.Role => new StepAssignInfo
+                {
+                    Key = startStep.RoleId,
+                    Value = startStep.RoleName,
+                    RoleId = startStep.RoleId,
+                    RoleName = startStep.RoleName,
+                    UserId = startStep.HandlerId,
+                    Username = startStep.HandlerName,
+                    OrgId = startStep.HandlerOrgId,
+                    OrgName = startStep.HandlerOrgName,
+                    FlowAssignType = EFlowAssignType.Role
+                },
+                EFlowAssignType.OrgAndRole => new StepAssignInfo
+                {
+                    Key = startStep.HandlerOrgId,
+                    Value = startStep.HandlerOrgName,
+                    RoleId = startStep.RoleId,
+                    RoleName = startStep.RoleName,
+                    UserId = startStep.HandlerId,
+                    Username = startStep.HandlerName,
+                    OrgId = startStep.HandlerOrgId,
+                    OrgName = startStep.HandlerOrgName,
+                    FlowAssignType = EFlowAssignType.OrgAndRole
+                },
+                _ => throw new ArgumentOutOfRangeException(nameof(flowAssignType), flowAssignType, null)
+            };
             var dto = new RecallDto
             {
                 Opinion = opinion,
@@ -1829,34 +1901,7 @@ namespace Hotline.FlowEngine.Workflows
                 BusinessType = startStep.BusinessType,
                 StepType = startStep.StepType,
                 HandlerType = startStepDefine.HandlerType,
-                NextHandlers = new List<StepAssignInfo>
-                {
-                    flowAssignType == EFlowAssignType.User
-                        ? new()
-                        {
-                            Key = startStep.HandlerId,
-                            Value = startStep.HandlerName,
-                            RoleId = startStep.RoleId,
-                            RoleName = startStep.RoleName,
-                            UserId = startStep.HandlerId,
-                            Username = startStep.HandlerName,
-                            OrgId = startStep.HandlerOrgId,
-                            OrgName = startStep.HandlerOrgName,
-                            FlowAssignType = EFlowAssignType.User
-                        }
-                        : new()
-                        {
-                            Key = startStep.RoleId,
-                            Value = startStep.RoleName,
-                            RoleId = startStep.RoleId,
-                            RoleName = startStep.RoleName,
-                            UserId = startStep.HandlerId,
-                            Username = startStep.HandlerName,
-                            OrgId = startStep.HandlerOrgId,
-                            OrgName = startStep.HandlerOrgName,
-                            FlowAssignType = EFlowAssignType.Role
-                        }
-                }
+                NextHandlers = new List<StepAssignInfo> { stepAssignInfo }
             };
 
             // var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.HandlerType, dto.IsStartCountersign,
@@ -2386,6 +2431,7 @@ namespace Hotline.FlowEngine.Workflows
                 Status = EWorkflowStatus.Runnable,
                 Steps = new(),
                 Traces = new(),
+                Countersigns = new(),
                 WorkflowDefinition = definition,
                 ExternalId = externalId ?? string.Empty,
                 FlowType = definition.FlowType,
@@ -3499,7 +3545,7 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private async Task<WorkflowTrace> CreateVisitTraceAsync(WorkflowTrace pubTrace, UserInfo acceptor, string orderVisitId,
-          DateTime creationTime, CancellationToken cancellation)
+            DateTime creationTime, CancellationToken cancellation)
         {
             if (string.IsNullOrEmpty(orderVisitId))
                 throw new UserFriendlyException($"参数异常,orderVisitId不能为空, pubTraceId: {pubTrace.Id}");
@@ -4148,6 +4194,7 @@ namespace Hotline.FlowEngine.Workflows
             };
         }
 
+
         #endregion
     }
 }

+ 21 - 4
src/Hotline/Orders/Order.cs

@@ -45,6 +45,17 @@ namespace Hotline.Orders
         public string? FirstVisitResultCode { get; set; }
 
         #region 来电信息
+        /// <summary>
+        /// 政治身份
+        /// </summary>
+        [SugarColumn(ColumnDescription = "政治身份")]
+        public string? PoliticalIdentityValue { get; set; }
+
+        /// <summary>
+        /// 政治身份
+        /// </summary>
+        [SugarColumn(ColumnDescription = "政治身份")]
+        public string? PoliticalIdentityName { get; set; }
 
         /// <summary>
         /// 来源渠道(电话、网站、APP等)
@@ -951,10 +962,16 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDescription = "重办次数")]
         public int? ReTransactNum { get; set; }
 
-        /// <summary>
-        /// 派单退回次数
-        /// </summary>
-        [SugarColumn(ColumnDescription = "派单退回次数")]
+		/// <summary>
+		/// 回访重办次数
+		/// </summary>
+		[SugarColumn(ColumnDescription = "重办次数")]
+		public int? VisitReTransactNum { get; set; }
+
+		/// <summary>
+		/// 派单退回次数
+		/// </summary>
+		[SugarColumn(ColumnDescription = "派单退回次数")]
         public int? SendBackNum { get; set; }
 
         /// <summary>

+ 7 - 1
src/Hotline/Orders/OrderCopy.cs

@@ -1,4 +1,5 @@
-using SqlSugar;
+using Hotline.Share.Enums.Order;
+using SqlSugar;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
@@ -30,5 +31,10 @@ namespace Hotline.Orders
 		///  修改时间
 		/// </summary>
 		public DateTime AuditTime { get; set; }
+
+		/// <summary>
+		/// 工单修改来源
+		/// </summary>
+		public EOrderUpdateSource? AuditSource { get; set; }
 	}
 }

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

@@ -340,27 +340,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         {
             try
             {
-                if (_appOptions.Value.IsZiGong)
-                {
-                    if (order.Source == ESource.ProvinceStraight)
-                    {
-                        //发送查询短信
-                        var messageDto = new Share.Dtos.Push.MessageDto
-                        {
-                            PushBusiness = EPushBusiness.SearchSms,
-                            ExternalId = visitId,
-                            OrderId = order.Id,
-                            PushPlatform = EPushPlatform.Sms,
-                            Remark = order.Title,
-                            Name = order.FromName,
-                            TemplateCode = "1021",
-                            Params = new List<string>() { order.No, order.Password },
-                            TelNumber = order.Contact,
-                        };
-                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
-                    }
-                }
-                else
+                if (_appOptions.Value.IsZiGong == false)
                 {
                     if (order.Source != ESource.ProvinceStraight && order.FileOrgIsCenter.Value == false)
                     {

+ 105 - 0
src/Hotline/Orders/OrderPublishTemp.cs

@@ -0,0 +1,105 @@
+using Hotline.Share.Dtos;
+using Hotline.Share.Enums.Order;
+using Hotline.Users;
+using SqlSugar;
+using System.ComponentModel;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders;
+
+/// <summary>
+/// 临时待发布
+/// </summary>
+[Description("临时待发布")]
+[SugarIndex("index_publish_orderId", nameof(OrderPublish.OrderId), OrderByType.Asc)]
+public class OrderPublishTemp : FullStateEntity
+{
+    public string OrderId { get; set; }
+
+    /// <summary>
+    /// 工单编码(冗余)
+    /// </summary>
+    public string No { get; set; }
+
+    /// <summary>
+    /// 发布范围
+    /// </summary>
+    public bool PublishState { get; set; }
+
+    /// <summary>
+    /// 整理标题
+    /// </summary>
+    public string ArrangeTitle { get; set; }
+
+    /// <summary>
+    /// 整理内容
+    /// </summary>
+    [SugarColumn(ColumnDataType = "text")]
+    public string ArrangeContent { get; set; }
+
+    /// <summary>
+    /// 整理结果
+    /// </summary>
+    [SugarColumn(ColumnDataType = "text")]
+    public string ArrangeOpinion { get; set; }
+
+    /// <summary>
+    /// 已发布工单
+    /// </summary>
+    [Navigate(NavigateType.OneToOne, nameof(OrderId))]
+    public Order Order { get; set; }
+
+    #region 省工单使用字段
+
+    /// <summary>
+    /// 省是否公开
+    /// </summary>
+    public bool? ProPublishState { get; set; }
+
+    /// <summary>
+    /// 反馈电话
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public string? FeedBackPhone { get; set; }
+
+    /// <summary>
+    /// 不公开原因
+    /// </summary>
+    [SugarColumn(IsNullable = true)]
+    public string? NoPubReason { get; set; }
+
+    /// <summary>
+    /// 是否联系
+    /// </summary>
+    public bool? IsContact { get; set; }
+
+    /// <summary>
+    /// 是否评价
+    /// </summary>
+    public bool? IsVisited { get; set; }
+
+    /// <summary>
+    /// 网民评价
+    /// </summary>
+    [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+    public Kv? NetizenEvaluate { get; set; }
+
+    /// <summary>
+    /// 评价内容
+    /// </summary>
+    public string? EvaluateContent { get; set; }
+
+    /// <summary>
+    /// 备注
+    /// </summary>
+    public string? Remark { get; set; }
+
+    /// <summary>
+    /// 答复口径
+    /// </summary>
+    [SugarColumn(ColumnDataType = "text", IsNullable = true)]
+    public string? AnswerContent { get; set; }
+    #endregion
+
+    public bool? Resolve { get; set; }
+}

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

@@ -8,7 +8,8 @@ namespace Hotline.Orders
     /// 撤销件
     /// </summary>
     [Description("撤销件")]
-    public class OrderRevocation : CreationEntity
+	[SugarIndex("index_revocation_orderId", nameof(OrderRevocation.OrderId), OrderByType.Desc)]
+	public class OrderRevocation : CreationEntity
     {
         /// <summary>
         /// 工单编号(冗余)

+ 17 - 0
src/Hotline/SeedData/SystemDicDataSeedData.cs

@@ -190,6 +190,19 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
                 new () { Id = "08dd6060-7913-4b4b-83cf-475f692e93ae", DicDataValue = "default", DicDataName = "LocalHeadImageDefault", Sort = 2}
                 ];
         }
+        if (dicTypeCode == SysDicTypeConsts.InstaShotSpecialReason)
+        {
+            return [
+                new() { Id= "08dcd790-af29-4815-83b2-35df6e9e3400", DicDataValue = "工单内容不规范", DicDataName = "工单内容不规范", Sort = 1},
+                new () { Id = "08dcd790-b7e2-4905-895d-05b04c5a522b", DicDataValue = "回访不满意", DicDataName = "回访不满意", Sort = 2},
+                new () { Id = "08dcd790-f209-440c-8639-3c8312fe00ae", DicDataValue = "随手拍无办理结果", DicDataName = "随手拍无办理结果", Sort = 3},
+                new () { Id = "08dcd790-fbe5-4aea-8036-d227ff3bc09f", DicDataValue = "随手拍乱回复", DicDataName = "随手拍乱回复", Sort = 4},
+                new () { Id = "08dcd791-0af7-4d24-8b7f-4712fb719fb0", DicDataValue = "未上传已整改图片", DicDataName = "未上传已整改图片", Sort = 5},
+                new () { Id = "08dcd790-c6f2-406c-85cb-63a5417218de", DicDataValue = "部门要求退回重办", DicDataName = "部门要求退回重办", Sort = 6},
+                new () { Id = "08dcd790-d67d-4617-8ec3-7b5d2be5e7bb", DicDataValue = "随手拍没有整改完成时间", DicDataName = "随手拍没有整改完成时间", Sort = 7},
+                new () { Id = "08dcd790-e54b-4da2-8a1a-bba70490b08c", DicDataValue = "随手拍整改时间过长", DicDataName = "随手拍整改时间过长", Sort = 8}
+                ];
+        }
 
         throw new NotImplementedException();
     }
@@ -197,6 +210,10 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
     public SystemDicType GetType(string dicTypeCode)
     {
         var dicType = new string[2];
+        if (dicTypeCode == SysDicTypeConsts.InstaShotSpecialReason)
+        {
+            dicType = ["81c202b7-5c50-45e5-bbde-fb1904957f85", "随手拍特提原因"];
+        }
         if (dicTypeCode == SysDicTypeConsts.HeaderImages)
         {
             dicType = ["08dd6ac1-024b-49cb-8ce0-723246d62767", "用户默认头像集合"];

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

@@ -790,5 +790,10 @@ namespace Hotline.Settings
         /// 高频预警许排除的工单标题
         /// </summary>
         public const string HighMatterWarningFilterTitle = "HighMatterWarningFilterTitle";
+
+        /// <summary>
+        /// ip白名单
+        /// </summary>
+        public const string WhiteIp = "WhiteIp";
     }
 }

+ 0 - 1
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -211,7 +211,6 @@ public class SysDicTypeConsts
     /// </summary>
     public const string InstaShotSpecialReason = "InstaShotSpecialReason";
 
-
     /// <summary>
     /// 网民评价类型
     /// </summary>

+ 3 - 1
src/Hotline/Snapshot/Services/SnapshotPointsDomainService.cs

@@ -30,7 +30,9 @@ public class SnapshotPointsDomainService : ISnapshotPointsDomainService, IScopeD
             .Where((snapshot, industry) => snapshot.Id == orderId)
             .Select((snapshot, industry) => new { snapshot.Id, industry.ReportPoints , industry.ArgeePoints , industry.RefusePoints,  industry.Name,
                 snapshot.CreatorId})
-            .FirstAsync() ?? throw new UserFriendlyException($"{orderId} 工单不存在");
+            .FirstAsync();
+        if (order == null) return;
+        
         if (order.ReportPoints.HasValue == false)
             throw new UserFriendlyException($"{order.Name} 行业未配置积分");
 

+ 2 - 2
src/Hotline/Snapshot/SupplementRecord.cs

@@ -106,13 +106,13 @@ public class SupplementRecord : FullStateEntity
     public bool IsSendSMS { get; set; }
 
     /// <summary>
-    /// 特殊红包审核,审批类型
+    /// 补充奖励类型
     /// </summary>
     [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
     public string? AuditType { get; set; }
 
     /// <summary>
-    /// 特殊红包审核,审批类型
+    /// 补充奖励类型
     /// </summary>
     [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
     public string? AuditTypeCode { get; set; }

+ 18 - 0
src/Hotline/Validators/Ippbx/TrOnDutyDtoValidator.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FluentValidation;
+using Hotline.Share.Dtos.TrCallCenter;
+
+namespace Hotline.Validators.Ippbx
+{
+    public class TrOnDutyDtoValidator : AbstractValidator<TrOnDutyDto>
+    {
+        public TrOnDutyDtoValidator()
+        {
+            RuleFor(d=>d.TelNo).NotEmpty().WithMessage("分机号不能为空");
+        }
+    }
+}

+ 23 - 1
src/Hotline/dataview.md

@@ -710,4 +710,26 @@ select * from order_send_back_audit WHERE "SendBackOrgId"='001023';
 
 --更新退回申请创建部门
 select * from order_send_back_audit WHERE "CreatorOrgId"='001023';
---update order_send_back_audit SET "CreatorOrgName"='珙县智慧信息服务中心' WHERE "CreatorOrgId"='001023';
+--update order_send_back_audit SET "CreatorOrgName"='珙县智慧信息服务中心' WHERE "CreatorOrgId"='001023';
+
+### 兴唐通讯记录查询
+
+SELECT cn."FromNo" as 主叫号码,"ToNo" as 被叫号码,o."No" as 工单编码,o."Title" AS 工单标题,cn."TelNo" as 响应分机,cn."StaffNo" as 工号,cn."CallNo" as 通话ID,cn."UserName" as 话务员,
+cn."GroupId" as 功能组号码,cn."Duration" as 通话时间,
+(CASE 
+	WHEN cn."EndBy" = 0 THEN
+		'主叫方结束'
+		WHEN cn."EndBy" = 1 THEN
+		'被叫方结束'
+	ELSE
+		'其他未知情况'
+END) as 挂断状态,cn."BeginIvrTime" as 开始时间,cn."AnsweredTime" as 接通时间,cn."EndTime" as 挂断时间
+ FROM call_native  cn 
+LEFT JOIN "order"  o on cn."Id" = o."CallId" 
+WHERE  cn."IsDeleted" =FALSE  
+--呼入
+-- and cn."Direction" = 0 and cn."AnsweredTime" is NOT NULL and  cn."FromNo" ='110' and  cn."ToNo" ='12345'
+--呼出
+and cn."Direction" = 1 and cn."AnsweredTime" is NOT NULL and  cn."FromNo" ='12345' and  cn."ToNo" ='110'
+and cn."CreationTime" >= '2025-01-01' and  cn."CreationTime" <'2025-04-01' ;
+

+ 9 - 0
test/Hotline.Tests/Application/IndustryApplicationTest.cs

@@ -18,6 +18,7 @@ using Hotline.ThirdAccountDomainServices;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Snapshot.IRepository;
 using Hotline.Application.Snapshot.Contracts;
+using Hotline.Application.Snapshot;
 
 namespace Hotline.Tests.Application;
 public class IndustryApplicationTest : TestBase
@@ -41,6 +42,14 @@ public class IndustryApplicationTest : TestBase
         items.ShouldNotBeNull();
     }
 
+    [Fact]
+    public async Task GetIndustryDetail_Test()
+    {
+        var industry = await _industryApplication.GetIndustres(new IndustryListInDto("电气焊", null)).FirstAsync();
+        var detail = await _industryApplication.GetIndustryDetailAsync(industry.Id, CancellationToken.None);
+        detail.Name.ShouldNotBeNull();
+    }
+
     [Fact]
     public async Task UpdateIndustry_Test()
     {

+ 34 - 4
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -30,6 +30,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using XF.Domain.Cache;
+using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 
 namespace Hotline.Tests.Application;
@@ -76,6 +77,26 @@ public class OrderSnapshotApplicationTest : TestBase
         };
     }
 
+    /// <summary>
+    /// 测试办理步骤中没有附件信息异常
+    /// </summary>
+    /// <returns></returns>
+    [Fact]
+    public async Task SnapshotOrder_Workflow_NextsStep_Document_Test()
+    {
+        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin)
+            .办理到派单员(SetZuoXi)
+            .办理到一级部门(SetPaiDanYuan)
+            .StepHandle(async order =>
+            {
+                Set一级部门();
+                var steps = await _orderController.GetNextStepsWithRecommend(order.Id);
+                steps.DocumentFiles.ShouldNotBeNull();
+                steps.DocumentFiles.NotNullOrEmpty().ShouldBeTrue();
+            })
+            .GetCreateResult();
+    }
+
     /// <summary>
     /// 随手拍网格员超时:
     /// </summary>
@@ -132,7 +153,7 @@ public class OrderSnapshotApplicationTest : TestBase
         var snapshotLabels = _systemDicDataCacheManager.SnapshotOrderLabel;
         var inputLable = snapshotLabels.Where(m => m.DicDataValue == "bss").ToList();
         var industryCase = await _industryCaseRepository.Queryable().Where(m => m.IsEnable == true).FirstAsync();
-        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin)
+        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
             .办理到网格员(SetZuoXi)
             .StepHandle(async (order, mock) =>
             {
@@ -230,7 +251,7 @@ public class OrderSnapshotApplicationTest : TestBase
                 baseData.AuditTypeCode.ShouldNotBeNull();
                 baseData.Amount.ShouldNotBeNull();
 
-                var specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(order.No, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 1) { PageIndex = 1, PageSize = 10 }).ToListAsync();
+                var specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10 , No = order.No, Status = 1}).ToListAsync();
                 var specialRedAudit = specialRedAuditItems.FirstOrDefault();
                 specialRedAudit.ShouldNotBeNull();
                 var a = _systemDicDataCacheManager.SnapshotReplenishType.First();
@@ -250,12 +271,21 @@ public class OrderSnapshotApplicationTest : TestBase
                     AuditType = b.DicDataName,
                 };
 
-                await _redPackApplication.UpdateRedPackSpecialRecordAsync(inDto);
-                specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(order.No, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 1) { PageIndex = 1, PageSize = 10 }).ToListAsync();
+                await _redPackApplication.UpdateRedPackSpecialRecordAsync(inDto); // 补充发放
+                specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10 , Status = 1, No = order.No}).ToListAsync();
                 specialRedAudit = specialRedAuditItems.First();
                 specialRedAudit.ShouldNotBeNull();
                 specialRedAudit.BankCardNo.ShouldBe(inDto.BankCardNo);
                 specialRedAudit.OpenBank.ShouldBe(inDto.OpenBank);
+
+                try
+                {
+                    await _redPackApplication.RevocationRedPackSpecialAuditAsync(new List<string> { specialRedAudit.Id });
+                }
+                catch (UserFriendlyException e)
+                {
+                    e.Message.ShouldBe("该工单已发放红包,不能撤销审批");
+                }
             })
             .GetCreateResult();
         order.Id.ShouldNotBeNull();

+ 1 - 1
test/Hotline.Tests/Application/RedPackApplicationTest.cs

@@ -172,7 +172,7 @@ public class RedPackApplicationTest : TestBase
         var items = await _redPackApplication.GetRedPackRecordSupplementItems(new SnapshotRedPackRecordSupplementItemsInDto()).ToListAsync();
         items.Any(m => m.FromName.NotNullOrEmpty()).ShouldBeTrue();
         items.Any(m => m.Remark.NotNullOrEmpty()).ShouldBeTrue();
-        items.Any(m => m.ReplenishType.NotNullOrEmpty()).ShouldBeTrue();
+        items.Any(m => m.AuditType.NotNullOrEmpty()).ShouldBeTrue();
         items.ShouldNotBeNull();
     }
 }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است