Kaynağa Gözat

Merge branch 'dev'

xf 11 ay önce
ebeveyn
işleme
55ed8faa07
33 değiştirilmiş dosya ile 904 ekleme ve 124 silme
  1. 308 16
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  2. 6 6
      src/Hotline.Api/Controllers/IPPbxController.cs
  3. 14 8
      src/Hotline.Api/Controllers/OrderController.cs
  4. 2 2
      src/Hotline.Api/config/appsettings.Development.json
  5. 2 2
      src/Hotline.Api/config/appsettings.json
  6. 0 20
      src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs
  7. 2 1
      src/Hotline.Application/Bigscreen/SeatStateDataService.cs
  8. 23 16
      src/Hotline.Application/CallCenter/Calls/TelsStatusRefreshService.cs
  9. 9 4
      src/Hotline.Application/CallCenter/Calls/TrApplication.cs
  10. 8 3
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  11. 5 0
      src/Hotline.Application/Orders/IOrderSecondaryHandlingApplication.cs
  12. 130 0
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  13. 2 2
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  14. 37 20
      src/Hotline.Application/Tels/TelApplication.cs
  15. 1 1
      src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/ProvinceSendDelayResultDto.cs
  16. 10 1
      src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs
  17. 226 0
      src/Hotline.Share/Dtos/Order/OrderBiDto.cs
  18. 6 0
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  19. 5 0
      src/Hotline.Share/Dtos/Order/OrderFlowDto.cs
  20. 6 4
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  21. 2 0
      src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs
  22. 2 2
      src/Hotline.Share/Dtos/Users/UserDto.cs
  23. 3 0
      src/Hotline.Share/Enums/CallCenter/EActionType.cs
  24. 1 1
      src/Hotline.Share/Hotline.Share.csproj
  25. 17 0
      src/Hotline.Share/Requests/PagedKeywordRequest.cs
  26. 2 3
      src/Hotline/Authentications/Police110SessionContext.cs
  27. 2 2
      src/Hotline/Authentications/ProvinceSessionContext.cs
  28. 2 2
      src/Hotline/Authentications/YbEnterpriseSessionContext.cs
  29. 1 1
      src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs
  30. 5 5
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  31. 6 0
      src/Hotline/Orders/Order.cs
  32. 58 0
      src/Hotline/Permissions/EPermission.cs
  33. 1 2
      src/XF.Domain/Authentications/DefaultSessionContext.cs

+ 308 - 16
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -1,4 +1,5 @@
-using Hotline.Caching.Interfaces;
+using Hotline.Application.Orders;
+using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
@@ -17,6 +18,7 @@ using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Requests;
+using Hotline.Tools;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using NPOI.SS.Formula.Functions;
@@ -49,8 +51,9 @@ namespace Hotline.Api.Controllers.Bi
         private readonly IRepository<OrderSpecialDetail> _orderSpecialDetailRepository;
         private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IRepository<OrderScreen> _orderScreenRepository;
+        private readonly IOrderSecondaryHandlingApplication _orderSecondaryHandlingApplication;
 
-        public BiOrderController(
+		public BiOrderController(
             IOrderRepository orderRepository,
             IRepository<Hotspot> hotspotTypeRepository,
             ISystemDicDataCacheManager sysDicDataCacheManager,
@@ -69,8 +72,9 @@ namespace Hotline.Api.Controllers.Bi
             IRepository<OrderSpecialDetail> orderSpecialDetailRepository,
             IRepository<WorkflowTrace> workflowTraceRepository,
             IRepository<OrderScreen> orderScreenRepository,
-            IRepository<WorkflowStepHandler> workflowStepHandleRepository
-            )
+            IRepository<WorkflowStepHandler> workflowStepHandleRepository,
+            IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication
+			)
         {
             _orderRepository = orderRepository;
             _hotspotTypeRepository = hotspotTypeRepository;
@@ -91,7 +95,9 @@ namespace Hotline.Api.Controllers.Bi
             _workflowTraceRepository = workflowTraceRepository;
             _orderScreenRepository = orderScreenRepository;
             _workflowStepHandleRepository = workflowStepHandleRepository;
-        }
+            _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication;
+
+		}
 
         /// <summary>
         /// 部门超期统计明细
@@ -1697,7 +1703,7 @@ namespace Hotline.Api.Controllers.Bi
                     HQZBOverdue = 0,
                     DelayEnd = 0,
                     DelayWait = 0,
-                    OrderDelayCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.DelayState != EDelayState.Withdraw, 1, 0)),
+                    OrderDelayCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.DelayState == EDelayState.Pass, 1, 0)),
                     ScreenCount = 0,
                     ScreenApproval = 0,
                     ScreenPass = 0,
@@ -1987,7 +1993,7 @@ namespace Hotline.Api.Controllers.Bi
              {
                  OrgCode = d.OrgCode,
                  // OrderCountNum = 0,//总量
-                 YBOrderCountNum = 0,//已办
+                 YBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status >= EWorkflowStepStatus.Handled, 1, 0)),//已办
                  ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EWorkflowStepStatus.Handled, 1, 0)),// 0,//在办
                  Archived = 0,
                  ToBeArchived = 0,
@@ -2043,7 +2049,7 @@ namespace Hotline.Api.Controllers.Bi
                     HQZBOverdue = 0,
                     DelayEnd = 0,
                     DelayWait = 0,
-                    OrderDelayCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.DelayState != EDelayState.Withdraw, 1, 0)),
+                    OrderDelayCount = SqlFunc.AggregateSum(SqlFunc.IIF(x.DelayState == EDelayState.Pass, 1, 0)),
                     ScreenCount = 0,
                     ScreenApproval = 0,
                     ScreenPass = 0,
@@ -2223,6 +2229,9 @@ namespace Hotline.Api.Controllers.Bi
             switch (dto.StatisticsType)
             {
                 case EStatisticsType.YBOrderCountNum:
+                    //工单
+                    stye = "0";
+                    break;
                 case EStatisticsType.ToBeArchived:
                 case EStatisticsType.Archived:
                 case EStatisticsType.YBOverdue:
@@ -2268,6 +2277,41 @@ namespace Hotline.Api.Controllers.Bi
                 default:
                     break;
             }
+            #region 工单已办
+            if (stye == "0")
+            {
+                var ybQuery = _orderRepository.Queryable()
+                                  .Where(it => it.CreationTime >= dto.StartDate && it.CreationTime <= dto.EndDate && it.Status > EOrderStatus.WaitForAccept)
+                                  .WhereIF(dto.OrgCode == "001", it => it.ActualHandleOrgCode == dto.OrgCode)
+                                  .WhereIF(dto.OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(dto.OrgCode))
+                                 .WhereIF(dto.StatisticsType == EStatisticsType.YBOrderCountNum, it => it.Status >= EOrderStatus.Filed)//已办
+                                 .Select(it => new SelectOrderId { Id = it.Id })
+                                 .MergeTable();
+
+                var hqybquery = _workflowStepHandleRepository.Queryable()
+                  .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
+                  .LeftJoin<Order>((x, o, p) => o.WorkflowId == p.WorkflowId)
+                  .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
+                  .WhereIF(dto.OrgCode == "001", (x, o, p) => x.OrgId == dto.OrgCode)
+                  .WhereIF(dto.OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(dto.OrgCode))
+                  .WhereIF(dto.StatisticsType == EStatisticsType.YBOrderCountNum, (x, o, p) => o.Status >= EWorkflowStepStatus.Handled && o.CountersignPosition > ECountersignPosition.None)//会签已办
+                   .Select((x, o, p) => new SelectOrderId { Id = p.Id })
+                  .MergeTable();
+
+                var queryData = await _orderRepository.OrderListUnionAll(ybQuery, hqybquery)
+                        .LeftJoin<Order>((x, o) => x.Id == o.Id)
+                         .Select((x, o) => new { o })
+                        .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);
+
+                var dtos = queryData.Select(d =>
+                {
+                    var dto = _mapper.Map<OrderDto>(d.o);
+                    return dto;
+                }).ToList();
+
+                return new PagedDto<OrderDto>(total, dtos);
+            }
+            #endregion
 
             #region 工单
             if (stye == "1")
@@ -2277,12 +2321,9 @@ namespace Hotline.Api.Controllers.Bi
                           .Where(it => it.CreationTime >= dto.StartDate && it.CreationTime <= dto.EndDate && it.Status > EOrderStatus.WaitForAccept)
                           .WhereIF(dto.OrgCode == "001", it => it.ActualHandleOrgCode == dto.OrgCode)
                           .WhereIF(dto.OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(dto.OrgCode))
-                         .WhereIF(dto.StatisticsType == EStatisticsType.YBOrderCountNum, it => it.Status >= EOrderStatus.Filed)//已办
-                           .WhereIF(dto.StatisticsType == EStatisticsType.ZBOrderCountNum, it => it.Status < EOrderStatus.Filed)//在办
                            .WhereIF(dto.StatisticsType == EStatisticsType.Archived, it => it.Status >= EOrderStatus.Filed)//已归档
                             .WhereIF(dto.StatisticsType == EStatisticsType.ToBeArchived, it => it.Status < EOrderStatus.WaitForAccept)//待归档--没得待归档数据
                            .WhereIF(dto.StatisticsType == EStatisticsType.YBOverdue, it => it.Status >= EOrderStatus.Filed && it.ActualHandleTime > it.ExpiredTime)//已办超期
-                           .WhereIF(dto.StatisticsType == EStatisticsType.ZBOverdue, it => it.Status < EOrderStatus.Filed && it.ExpiredTime < SqlFunc.GetDate())//待办超期
                            .OrderByDescending(it => it.CreationTime)
                            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
                 return new PagedDto<OrderDto>(totalOrder, _mapper.Map<IReadOnlyList<OrderDto>>(items));
@@ -2324,7 +2365,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Where((x, o) => x.CreationTime >= dto.StartDate && x.CreationTime <= dto.EndDate)
                 .WhereIF(dto.OrgCode == "001", (x, o) => x.ApplyOrgCode == dto.OrgCode)
                 .WhereIF(dto.OrgCode != "001", (x, o) => x.ApplyOrgCode.StartsWith(dto.OrgCode))
-              .WhereIF(dto.StatisticsType == EStatisticsType.OrderDelayCount, (x, o) => x.DelayState != EDelayState.Withdraw)//延期次数
+              .WhereIF(dto.StatisticsType == EStatisticsType.OrderDelayCount, (x, o) => x.DelayState == EDelayState.Pass)//延期次数
                 .OrderByDescending((x, o) => o.CreationTime)
                 .Select((x, o) => new { o })
                 .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);
@@ -2755,7 +2796,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Where((x, w, wfsh, su) => x.CreationTime <= dto.EndTime.Value)
                 .GroupBy((x, w, wfsh, su) => x.WorkflowId)
                 .Having((x, w, wfsh, su) => SqlFunc.AggregateCount(x.WorkflowId) > 1)
-			    .Select((x, w, wfsh, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(wfsh.CreationTime) })
+                .Select((x, w, wfsh, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(wfsh.CreationTime) })
                 .MergeTable()
                 .LeftJoin<WorkflowTrace>((a, wt) => a.Id == wt.WorkflowId)
                 .LeftJoin<Workflow>((a, wt, wf) => wt.WorkflowId == wf.Id)
@@ -2827,12 +2868,12 @@ namespace Hotline.Api.Controllers.Bi
                        .Where((x, w, wfsh, su) => x.CreationTime <= dto.EndTime.Value)
                        .GroupBy((x, w, wfsh, su) => x.WorkflowId)
                        .Having((x, w, wfsh, su) => SqlFunc.AggregateCount(x.WorkflowId) > 1)
-					   .Select((x, w, wfsh, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(wfsh.CreationTime) })
+                        .Select((x, w, wfsh, su) => new { Id = x.WorkflowId, CreationTime = SqlFunc.AggregateMin(wfsh.CreationTime) })
                        .MergeTable()
                        .LeftJoin<WorkflowTrace>((a, wt) => a.Id == wt.WorkflowId)
                        .LeftJoin<Workflow>((a, wt, wf) => wt.WorkflowId == wf.Id)
                        .LeftJoin<WorkflowStepHandler>((a, wt, wf, wsh) => wt.StepId == wsh.WorkflowStepId && wsh.CreationTime == a.CreationTime)
-					   .InnerJoin<SchedulingUser>((a, wt, wf, wsh, su) => wsh.UserId == su.UserId)
+                       .InnerJoin<SchedulingUser>((a, wt, wf, wsh, su) => wsh.UserId == su.UserId)
                        .Where((a, wt, wf, wsh, su) => su.UserId == dto.UserId)
                        .GroupBy((a, wt, wf, wsh, su) => wf.ExternalId)
                        .Select((a, wt, wf, wsh, su) => new { Id = wf.ExternalId })
@@ -2845,6 +2886,257 @@ namespace Hotline.Api.Controllers.Bi
         }
 
 
+		/// <summary>
+		/// 二次办理统计
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpGet("secondary_handling_report")]
+        public async Task<List<SecondaryHandlingVo>> SecondaryHandlingReport([FromQuery] QuerySecondaryHandlingRequest dto)
+        {
+	        var query = _orderSecondaryHandlingApplication.SecondaryHandlingReport(dto, HttpContext.RequestAborted);
+            return await query.ToListAsync();
+		}
+		/// <summary>
+		/// 二次办理统计导出
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("secondary_handling_report/_export")]
+        public async Task<FileStreamResult> SecondaryHandlingReportExport([FromBody] ExportExcelDto<QuerySecondaryHandlingRequest> dto)
+        {
+	        var query = _orderSecondaryHandlingApplication.SecondaryHandlingReport(dto.QueryDto, HttpContext.RequestAborted);
+	        List<SecondaryHandlingVo> secondaryHandling;
+			secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted);
+	        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+	        var dtos = secondaryHandling
+				.Select(stu => _mapper.Map(stu, typeof(SecondaryHandlingVo), dynamicClass))
+		        .Cast<object>()
+		        .ToList();
+
+	        var stream = ExcelHelper.CreateStream(dtos);
+
+	        return ExcelStreamResult(stream, "二次办理统计数据");
+        }
 
-    }
+		/// <summary>
+		/// 二次办理明细
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpGet("secondary_handling_detail_report")]
+		public async Task<PagedDto<OrderSecondaryHandlingDto>> SecondaryHandlingDetailReport([FromQuery] QuerySecondaryHandlingRequest dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingDetailReport(dto, HttpContext.RequestAborted);
+			var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);
+
+			return new PagedDto<OrderSecondaryHandlingDto>(total, _mapper.Map<IReadOnlyList<OrderSecondaryHandlingDto>>(items));
+		}
+		/// <summary>
+		/// 二次办理明细导出
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("secondary_handling_detail_report/_export")]
+		public async Task<FileStreamResult> SecondaryHandlingDetailReportExport([FromBody] ExportExcelDto<QuerySecondaryHandlingRequest> dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingDetailReport(dto.QueryDto, HttpContext.RequestAborted);
+			List<OrderSecondaryHandling> secondaryHandling;
+			if (dto.IsExportAll)
+			{
+				secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted);
+			}
+			else
+			{
+				var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+				secondaryHandling = items;
+			}
+
+			var secondaryHandlingDtos = _mapper.Map<ICollection<OrderSecondaryHandlingDto>>(secondaryHandling);
+
+			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+			var dtos = secondaryHandlingDtos
+				.Select(stu => _mapper.Map(stu, typeof(OrderSecondaryHandlingDto), dynamicClass))
+				.Cast<object>()
+				.ToList();
+
+			var stream = ExcelHelper.CreateStream(dtos);
+
+			return ExcelStreamResult(stream, "二次办理列表数据");
+		}
+
+
+		/// <summary>
+		/// 二次办理满意度统计
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpGet("secondary_handling_satisfaction_report")]
+		public async Task<List<SecondaryHandlingSatisfactionVo>> SecondaryHandlingSatisfactionReport([FromQuery] QuerySecondaryHandlingRequest dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingSatisfactionReport(dto, HttpContext.RequestAborted);
+			var list = await query.ToListAsync();
+            //总计
+            var total = new SecondaryHandlingSatisfactionVo
+            {
+                OrgId ="0",
+                OrgName ="总计",
+	            TotalSumCount = list.Select(x => x.TotalSumCount).Sum(),
+	            VerySatisfiedCount = list.Select(x => x.VerySatisfiedCount).Sum(),
+	            SatisfiedCount = list.Select(x => x.SatisfiedCount).Sum(),
+	            RegardedAsSatisfiedCount = list.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+	            DefaultSatisfiedCount = list.Select(x => x.DefaultSatisfiedCount).Sum(),
+	            NoSatisfiedCount = list.Select(x => x.NoSatisfiedCount).Sum(),
+	            NoEvaluateCount = list.Select(x => x.NoEvaluateCount).Sum(),
+	            NoPutThroughCount = list.Select(x => x.NoPutThroughCount).Sum()
+            };
+            list.Add(total);
+            //区县合计
+            var countyList = list.Where(x => x.OrgType == EOrgType.County).ToList();
+			var countyTotal = new SecondaryHandlingSatisfactionVo
+			{
+				OrgId = "0",
+				OrgName = "区县合计",
+				TotalSumCount = countyList.Select(x => x.TotalSumCount).Sum(),
+				VerySatisfiedCount = countyList.Select(x => x.VerySatisfiedCount).Sum(),
+				SatisfiedCount = countyList.Select(x => x.SatisfiedCount).Sum(),
+				RegardedAsSatisfiedCount = countyList.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+				DefaultSatisfiedCount = countyList.Select(x => x.DefaultSatisfiedCount).Sum(),
+				NoSatisfiedCount = countyList.Select(x => x.NoSatisfiedCount).Sum(),
+				NoEvaluateCount = countyList.Select(x => x.NoEvaluateCount).Sum(),
+				NoPutThroughCount = countyList.Select(x => x.NoPutThroughCount).Sum()
+			};
+			list.Add(countyTotal);
+			//市直合计
+			var cityList = list.Where(x => x.OrgType == EOrgType.City).ToList();
+			var cityTotal = new SecondaryHandlingSatisfactionVo
+			{
+				OrgId = "0",
+				OrgName = "市直合计",
+				TotalSumCount = cityList.Select(x => x.TotalSumCount).Sum(),
+				VerySatisfiedCount = cityList.Select(x => x.VerySatisfiedCount).Sum(),
+				SatisfiedCount = cityList.Select(x => x.SatisfiedCount).Sum(),
+				RegardedAsSatisfiedCount = cityList.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+				DefaultSatisfiedCount = cityList.Select(x => x.DefaultSatisfiedCount).Sum(),
+				NoSatisfiedCount = cityList.Select(x => x.NoSatisfiedCount).Sum(),
+				NoEvaluateCount = cityList.Select(x => x.NoEvaluateCount).Sum(),
+				NoPutThroughCount = cityList.Select(x => x.NoPutThroughCount).Sum()
+			};
+			list.Add(cityTotal);
+			return list;
+		}
+		/// <summary>
+		/// 二次办理满意度统计导出
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("secondary_handling_satisfaction_report/_export")]
+		public async Task<FileStreamResult> SecondaryHandlingSatisfactionReportExport([FromBody] ExportExcelDto<QuerySecondaryHandlingRequest> dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingSatisfactionReport(dto.QueryDto, HttpContext.RequestAborted);
+			List<SecondaryHandlingSatisfactionVo> secondaryHandling;
+			secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted);
+			//总计
+			var total = new SecondaryHandlingSatisfactionVo
+			{
+				OrgId = "0",
+				OrgName = "总计",
+				TotalSumCount = secondaryHandling.Select(x => x.TotalSumCount).Sum(),
+				VerySatisfiedCount = secondaryHandling.Select(x => x.VerySatisfiedCount).Sum(),
+				SatisfiedCount = secondaryHandling.Select(x => x.SatisfiedCount).Sum(),
+				RegardedAsSatisfiedCount = secondaryHandling.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+				DefaultSatisfiedCount = secondaryHandling.Select(x => x.DefaultSatisfiedCount).Sum(),
+				NoSatisfiedCount = secondaryHandling.Select(x => x.NoSatisfiedCount).Sum(),
+				NoEvaluateCount = secondaryHandling.Select(x => x.NoEvaluateCount).Sum(),
+				NoPutThroughCount = secondaryHandling.Select(x => x.NoPutThroughCount).Sum()
+			};
+			secondaryHandling.Add(total);
+			//区县合计
+			var countyList = secondaryHandling.Where(x => x.OrgType == EOrgType.County).ToList();
+			var countyTotal = new SecondaryHandlingSatisfactionVo
+			{
+				OrgId = "0",
+				OrgName = "区县合计",
+				TotalSumCount = countyList.Select(x => x.TotalSumCount).Sum(),
+				VerySatisfiedCount = countyList.Select(x => x.VerySatisfiedCount).Sum(),
+				SatisfiedCount = countyList.Select(x => x.SatisfiedCount).Sum(),
+				RegardedAsSatisfiedCount = countyList.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+				DefaultSatisfiedCount = countyList.Select(x => x.DefaultSatisfiedCount).Sum(),
+				NoSatisfiedCount = countyList.Select(x => x.NoSatisfiedCount).Sum(),
+				NoEvaluateCount = countyList.Select(x => x.NoEvaluateCount).Sum(),
+				NoPutThroughCount = countyList.Select(x => x.NoPutThroughCount).Sum()
+			};
+			secondaryHandling.Add(countyTotal);
+			//市直合计
+			var cityList = secondaryHandling.Where(x => x.OrgType == EOrgType.City).ToList();
+			var cityTotal = new SecondaryHandlingSatisfactionVo
+			{
+				OrgId = "0",
+				OrgName = "市直合计",
+				TotalSumCount = cityList.Select(x => x.TotalSumCount).Sum(),
+				VerySatisfiedCount = cityList.Select(x => x.VerySatisfiedCount).Sum(),
+				SatisfiedCount = cityList.Select(x => x.SatisfiedCount).Sum(),
+				RegardedAsSatisfiedCount = cityList.Select(x => x.RegardedAsSatisfiedCount).Sum(),
+				DefaultSatisfiedCount = cityList.Select(x => x.DefaultSatisfiedCount).Sum(),
+				NoSatisfiedCount = cityList.Select(x => x.NoSatisfiedCount).Sum(),
+				NoEvaluateCount = cityList.Select(x => x.NoEvaluateCount).Sum(),
+				NoPutThroughCount = cityList.Select(x => x.NoPutThroughCount).Sum()
+			};
+			secondaryHandling.Add(cityTotal);
+
+			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+			var dtos = secondaryHandling
+				.Select(stu => _mapper.Map(stu, typeof(SecondaryHandlingSatisfactionVo), dynamicClass))
+				.Cast<object>()
+				.ToList();
+
+			var stream = ExcelHelper.CreateStream(dtos);
+
+			return ExcelStreamResult(stream, "二次办理满意度统计数据");
+		}
+
+		/// <summary>
+		/// 二次办理满意度明细
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpGet("secondary_handling_satisfaction_detail_report")]
+		public async Task<PagedDto<OrderSecondaryHandlingDto>> SecondaryHandlingSatisfactionDetailReport([FromQuery] QuerySecondaryHandlingRequest dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingSatisfactionDetailReport(dto, HttpContext.RequestAborted);
+			var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);
+
+			return new PagedDto<OrderSecondaryHandlingDto>(total, _mapper.Map<IReadOnlyList<OrderSecondaryHandlingDto>>(items));
+		}
+		/// <summary>
+		/// 二次办理满意度明细导出
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("secondary_handling_satisfaction_detail_report/_export")]
+		public async Task<FileStreamResult> SecondaryHandlingSatisfactionDetailReport([FromBody] ExportExcelDto<QuerySecondaryHandlingRequest> dto)
+		{
+			var query = _orderSecondaryHandlingApplication.SecondaryHandlingSatisfactionDetailReport(dto.QueryDto, HttpContext.RequestAborted);
+			List<OrderSecondaryHandling> secondaryHandling;
+			if (dto.IsExportAll)
+			{
+				secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted);
+			}
+			else
+			{
+				var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+				secondaryHandling = items;
+			}
+
+			var secondaryHandlingDtos = _mapper.Map<ICollection<OrderSecondaryHandlingDto>>(secondaryHandling);
+
+			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+			var dtos = secondaryHandlingDtos
+				.Select(stu => _mapper.Map(stu, typeof(OrderSecondaryHandlingDto), dynamicClass))
+				.Cast<object>()
+				.ToList();
+
+			var stream = ExcelHelper.CreateStream(dtos);
+
+			return ExcelStreamResult(stream, "二次办理满意度列表数据");
+		}
+	}
 }

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

@@ -303,33 +303,33 @@ namespace Hotline.Api.Controllers
         #region 添添呼话后整理
 
         /// <summary>
-        /// 话后整理开始
+        /// 分机动作开始
         /// </summary>
         /// <returns></returns>
         [HttpGet("callennd-arrange-begin")]
-        public async Task CallEndArrangeBegin()
+        public async Task CallEndArrangeBegin(int actionType)
         {
             var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
 
             if (work is null)
                 throw UserFriendlyException.SameMessage("分机未签入,不能操作");
 
-            var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, EActionType.CallEndArrange);
+            var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, (EActionType)actionType);
             await _telActionRecordRepository.AddAsync(telAction, HttpContext.RequestAborted);
         }
 
         /// <summary>
-        /// 话后整理结束
+        /// 分机动作结束
         /// </summary>
         /// <returns></returns>
         [HttpGet("callend-arrange-end")]
-        public async Task CallEndArrangeEnd()
+        public async Task CallEndArrangeEnd(int actionType)
         {
             var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
             if (work is null)
                 throw UserFriendlyException.SameMessage("分机未签入,不能操作");
 
-            var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, HttpContext.RequestAborted);
+            var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == (EActionType)actionType && !x.EndTime.HasValue, HttpContext.RequestAborted);
             if (telAction != null)
             {
                 telAction.EndAction();

+ 14 - 8
src/Hotline.Api/Controllers/OrderController.cs

@@ -1557,7 +1557,7 @@ public class OrderController : BaseController
 
         var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyNum);
         int count = await _orderScreenRepository.CountAsync(x =>
-            x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse);
+            x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse && x.VisitDetailId == dto.Data.VisitDetailId);
         if (count > int.Parse(setting?.SettingValue[0]) && int.Parse(setting?.SettingValue[0]) > -1)
             throw UserFriendlyException.SameMessage("甄别申请已超过系统预定设置,不能申请");
 
@@ -3422,10 +3422,11 @@ public class OrderController : BaseController
             //if (dto.AlterTime)
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            //var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
-            //	ETimeType.WorkDay,
-            //	dto.TimeLimit.Value, order.AcceptTypeCode);
-            await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
+            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter? EProcessType.Zhiban : EProcessType.Jiaoban;
+			//var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
+			//	ETimeType.WorkDay,
+			//	dto.TimeLimit.Value, order.AcceptTypeCode);
+			await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime,ProcessType = processType })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
@@ -3556,7 +3557,10 @@ public class OrderController : BaseController
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
             }
-            await _workflowApplication.RecallAsync(recall, endTime, HttpContext.RequestAborted);
+            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+			await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType })
+	            .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
+			await _workflowApplication.RecallAsync(recall, endTime, HttpContext.RequestAborted);
             var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId);
             if (publish != null)
             {
@@ -3625,7 +3629,8 @@ public class OrderController : BaseController
             //if (dto.AlterTime)
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
+            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+			await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
@@ -3721,7 +3726,8 @@ public class OrderController : BaseController
                 //if (dto.AlterTime)
                 //{
                 var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-                await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
+                var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+				await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);

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

@@ -16,7 +16,7 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
     "Redis": "110.188.24.182:50179",
     "MongoDB": "mongodb://192.168.100.121:27017",
     "Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
@@ -25,7 +25,7 @@
     "Host": "110.188.24.182",
     "Port": 50179,
     //"Password": "fengwo22@@",
-    "Database": 1
+    "Database": 3
   },
   "Swagger": true,
   "Cors": {

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

@@ -16,7 +16,7 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "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;"
@@ -25,7 +25,7 @@
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo22@@",
-    "Database": 1
+    "Database": 3
   },
   "Swagger": true,
   "Cors": {

+ 0 - 20
src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs

@@ -1,29 +1,9 @@
 using Hotline.Caching.Interfaces;
-using Hotline.CallCenter.Calls;
-using Hotline.Orders;
 using Hotline.Realtimes;
-using Hotline.Share.Dtos.TrCallCenter;
-using MapsterMapper;
-using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
-using NewRock.Sdk.Events;
-using Org.BouncyCastle.Utilities;
-using Serilog.Core;
-using SqlSugar;
-using StackExchange.Redis;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Tr.Sdk;
-using Tr.Sdk.Tels;
 using XF.Domain.Constants;
-using XF.Domain.Repository;
 
 namespace Hotline.Application.Bigscreen
 {

+ 2 - 1
src/Hotline.Application/Bigscreen/SeatStateDataService.cs

@@ -52,8 +52,9 @@ namespace Hotline.Application.Bigscreen
 
 		public async Task<object> GetCallTop10(CancellationToken stoppingToken)
 		{
+
 			var callTop10 = await _callRepository.Queryable()
-				.Where(x => x.CreatedTime.Date == now
+				.Where(x => x.CreatedTime.Date == DateTime.Now.Date
 					&& x.CallOrderType == Share.Enums.CallCenter.ECallOrderType.Order
 				)
 				.GroupBy(x => x.UserName)

+ 23 - 16
src/Hotline.Application/CallCenter/Calls/TelsStatusRefreshService.cs

@@ -3,10 +3,8 @@ using Hotline.CallCenter.Tels;
 using Hotline.Realtimes;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Users;
-using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
-using System.Threading;
 using Tr.Sdk;
 using XF.Domain.Cache;
 using XF.Domain.Repository;
@@ -59,24 +57,33 @@ namespace Hotline.Application.CallCenter.Calls
                                 _cacheWork.Remove(item.GetKey(KeyMode.UserId));
                                 _cacheWork.Remove(item.GetKey(KeyMode.TelNo));
 
-                                #region 小休状态
-                                var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, stoppingToken);
-                                if (telAction != null)
-                                {
-                                    telAction.EndAction();
-                                    await _telActionRecordRepository.UpdateAsync(telAction);
-                                }
-                                #endregion
-                                #region 话后整理
 
-                                var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue,stoppingToken);
-                                if (telarrangeAction != null)
+                                var listx = await _telActionRecordRepository.Queryable().Where(x => x.TelNo == item.TelNo && !x.EndTime.HasValue).ToListAsync();
+                                foreach (var itemx in listx)
                                 {
-                                    telarrangeAction.EndAction();
-                                    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+                                    itemx.EndAction();
+                                    await _telActionRecordRepository.UpdateAsync(itemx);
                                 }
 
-                                #endregion
+
+                                //#region 小休状态
+                                //var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, stoppingToken);
+                                //if (telAction != null)
+                                //{
+                                //    telAction.EndAction();
+                                //    await _telActionRecordRepository.UpdateAsync(telAction);
+                                //}
+                                //#endregion
+                                //#region 话后整理
+
+                                //var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue,stoppingToken);
+                                //if (telarrangeAction != null)
+                                //{
+                                //    telarrangeAction.EndAction();
+                                //    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+                                //}
+
+                                //#endregion
                             }
                         }
                     }

+ 9 - 4
src/Hotline.Application/CallCenter/Calls/TrApplication.cs

@@ -1,4 +1,5 @@
 using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Tels;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.TrCallCenter;
@@ -25,8 +26,9 @@ namespace Hotline.Application.CallCenter.Calls
         private readonly ITelRestRepository _telRestRepository;
         private readonly ITypedCache<Work> _cacheWork;
         private readonly IRepository<TelCallModel> _telCallModelRepository;
+        private readonly IRepository<TelActionRecord> _telActionRecordRepository;
 
-        public TrApplication(ITrClient trClient, ISessionContext sessionContext,IWorkRepository workRepository,ISystemSettingCacheManager systemSettingCacheManager,IUserCacheManager userCacheManager, ITelRestRepository telRestRepository, ITypedCache<Work> cacheWork,IRepository<TelCallModel> telCallModelRepository)
+        public TrApplication(ITrClient trClient, ISessionContext sessionContext,IWorkRepository workRepository,ISystemSettingCacheManager systemSettingCacheManager,IUserCacheManager userCacheManager, ITelRestRepository telRestRepository, ITypedCache<Work> cacheWork,IRepository<TelCallModel> telCallModelRepository,IRepository<TelActionRecord> telActionRecordRepository)
         {
             _trClient = trClient;
             _sessionContext = sessionContext;
@@ -36,6 +38,7 @@ namespace Hotline.Application.CallCenter.Calls
             _telRestRepository = telRestRepository;
             _cacheWork = cacheWork;
             _telCallModelRepository = telCallModelRepository;
+            _telActionRecordRepository = telActionRecordRepository;
         }
 
         /// <summary>
@@ -94,16 +97,18 @@ namespace Hotline.Application.CallCenter.Calls
             {
                 
                 bool isRest = await _telRestRepository.AnyAsync(x => x.TelNo == work.TelNo && x.UserId == userId && !x.EndTime.HasValue,cancellationToken);
-                
+
+                bool isCallHold = await _telActionRecordRepository.AnyAsync(x => x.TelNo == work.TelNo && x.UserId == userId && !x.EndTime.HasValue, cancellationToken);
+
                 bool IsTelNeedVerify = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsTelNeedVerify).SettingValue[0]);
                 string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
                 if (IsTelNeedVerify)
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut= callOutQueueId, TelNo = work.TelNo, TelPwd = "", Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel };
+                    return new TrOnDutyResponseDto() { QueueCallOut= callOutQueueId, TelNo = work.TelNo, TelPwd = "", Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold };
                 }
                 else
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = work.TelNo, TelPwd = work.TelPwd, Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel };
+                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = work.TelNo, TelPwd = work.TelPwd, Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold };
                 }
                
             }

+ 8 - 3
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -50,7 +50,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
     private readonly IKnowledgeWorkFlowRepository _knowledgeWorkFlowRepository;
     private readonly IRepository<TrCallRecord> _trCallRecordRepository;
     private readonly IQualityApplication _qualityApplication;
-    private readonly IEnforcementApplication _enforcementApplication; 
+    private readonly IEnforcementApplication _enforcementApplication;
     private readonly ISessionContext _sessionContext;
 
     public WorkflowEndHandler(
@@ -163,7 +163,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 order.FileUserOrgName = notification.Trace.HandlerOrgName;
 
                 //记录冗余归档数据
-                if(notification.Workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
+                if (notification.Workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
                 {
                     order.FileUserRole = EFileUserType.Dispatch;
                 }
@@ -175,7 +175,10 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 {
                     order.FileUserRole = EFileUserType.Org;
                 }
-                               
+
+                //是否已解决
+                order.IsResolved = notification.External == null ? false : notification.External.IsResolved;
+
                 await _orderRepository.UpdateAsync(order, cancellationToken);
                 var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken);
                 var orderFlowDto = new OrderFlowDto
@@ -187,6 +190,8 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 {
                     orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
                 }
+                //这里需要判断是否是警情退回
+                orderFlowDto.IsNonPoliceReturn = notification.External == null ? false : notification.External.IsPoliceReturn;
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
                 //写入质检  针对受理之后直接结束的工单
                 await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, cancellationToken);

+ 5 - 0
src/Hotline.Application/Orders/IOrderSecondaryHandlingApplication.cs

@@ -1,5 +1,6 @@
 using Hotline.Orders;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Requests;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -18,5 +19,9 @@ namespace Hotline.Application.Orders
 		ISugarQueryable<OrderVisitDetail> ApplyQuery(MayScreenListDto dto, CancellationToken cancellationToken);
 		Task<OrderSecondaryHandling> Entity(string id, CancellationToken cancellationToken);
 		ISugarQueryable<OrderSecondaryHandling> Query(SecondaryHandlingListDto dto, CancellationToken cancellationToken);
+		ISugarQueryable<SecondaryHandlingVo> SecondaryHandlingReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken);
+		ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken);
+		ISugarQueryable<SecondaryHandlingSatisfactionVo> SecondaryHandlingSatisfactionReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken);
+		ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingSatisfactionDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken);
 	}
 }

+ 130 - 0
src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs

@@ -19,6 +19,9 @@ using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
+using Hotline.Share.Requests;
+using Hotline.Settings;
+using Novacode;
 
 namespace Hotline.Application.Orders
 {
@@ -288,5 +291,132 @@ namespace Hotline.Application.Orders
 				.FirstAsync(x => x.Id == id, cancellationToken);
 		}
 
+		/// <summary>
+		/// 二次办理统计
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		public  ISugarQueryable<SecondaryHandlingVo> SecondaryHandlingReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+		{
+			return _orderSecondaryHandlingRepository.Queryable()
+				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+				.Where(x => x.State == ESecondaryHandlingState.End)
+				.GroupBy(x => new { x.ApplyOrgId, x.ApplyOrgName })
+				.Select(x => new SecondaryHandlingVo
+				{
+					OrgId = x.ApplyOrgId,
+					OrgName = x.ApplyOrgName,
+					Num = SqlFunc.AggregateCount(x.Id)
+				})
+				.OrderByIF(dto.SortRule == 0, x => x.Num, OrderByType.Asc)
+				.OrderByIF(dto.SortRule == 1, x => x.Num, OrderByType.Desc);
+		}
+
+		/// <summary>
+		/// 二次办理统计明细
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+		{
+			return _orderSecondaryHandlingRepository.Queryable()
+				.Includes(x=>x.Order)
+				.Includes(x=>x.Visit)
+				.Includes(x=>x.VisitDetail)
+				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+				.Where(x=>x.ApplyOrgId == dto.OrgId)
+				.Where(x => x.State == ESecondaryHandlingState.End);
+		}
+
+
+		/// <summary>
+		/// 二次办理满意度统计
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		public ISugarQueryable<SecondaryHandlingSatisfactionVo> SecondaryHandlingSatisfactionReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken) 
+		{
+			return _orderSecondaryHandlingRepository.Queryable()
+				.Includes(x => x.Order)
+				.Includes(x => x.Visit)
+				.Includes(x => x.VisitDetail)
+				.Includes(x => x.Order, o => o.CallRecord)
+				.LeftJoin<SystemOrganize>((x, o) => x.ApplyOrgId == o.Id)
+				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+				.WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
+				.GroupBy((x,o) => new { x.ApplyOrgId, x.ApplyOrgName,o.OrgType })
+				.Select((x, o) => new SecondaryHandlingSatisfactionVo()
+				{
+					OrgId = x.ApplyOrgId,
+					OrgName = x.ApplyOrgName,
+					OrgType = o.OrgType,
+					TotalSumCount = SqlFunc.AggregateCount(x.Id),
+					VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
+					SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
+					RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
+					DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
+					NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
+					NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
+					NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
+				});
+		}
+
+		/// <summary>
+		///  二次办理满意度统计明细
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingSatisfactionDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+		{
+			var key = string.Empty;
+			if (!string.IsNullOrEmpty(dto.Header))
+			{
+				switch (dto.Header)
+				{
+					case "verySatisfiedCount":
+						key = "5";
+						break;
+					case "satisfiedCount":
+						key = "4";
+						break;
+					case "regardedAsSatisfiedCount":
+						key = "-1";
+						break;
+					case "defaultSatisfiedCount":
+						key = "0";
+						break;
+					case "noSatisfiedCount":
+						key = "2";
+						break;
+					case "noEvaluateCount":
+						key = "7";
+						break;
+					case "noPutThroughCount":
+						key = "6";
+						break;
+				}
+			}
+
+			return _orderSecondaryHandlingRepository.Queryable()
+				.Includes(x => x.Order)
+				.Includes(x => x.Visit)
+				.Includes(x => x.VisitDetail)
+				.Includes(x => x.Order, o => o.CallRecord)
+				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+				.WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
+				.WhereIF(dto.TypeId is 1 && !string.IsNullOrEmpty(key), x=> SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == key)
+				.WhereIF(dto.TypeId is 2 && !string.IsNullOrEmpty(key), x => SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == key)
+				.Where(x => x.ApplyOrgId == dto.OrgId)
+				.Where(x => x.State == ESecondaryHandlingState.End);
+		}
+
 	}
 }

+ 2 - 2
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -509,7 +509,7 @@ namespace Hotline.Application.Subscribers
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         [CapSubscribe(Hotline.Share.Mq.EventNames.SharingOrderDelayResult)]
-        public async Task OrderDelayWeb(DelayProvinceResultDto dto, CancellationToken cancellationToken)
+        public async Task OrderDelayWeb(ProvinceSendDelayResultDto dto, CancellationToken cancellationToken)
         {
             var order = await _orderRepository.GetAsync(x => x.ProvinceNo == dto.No, cancellationToken);
             if (order != null)
@@ -517,7 +517,7 @@ namespace Hotline.Application.Subscribers
                 //查询延期
                 var orderDelay = await _orderDelayRepository.GetAsync(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining, cancellationToken);
                 var current = SessionContextCreator.CreateSessionContext(dto.Source);
-                await _workflowApplication.HandleToEndAsync(current, orderDelay.WorkflowId, dto.Opinion, null,
+                await _workflowApplication.HandleToEndAsync(current, orderDelay.WorkflowId, dto.Opinion, dto.Files,
                     dto.IsPass ? Share.Enums.FlowEngine.EReviewResult.Approval : Share.Enums.FlowEngine.EReviewResult.Failed, cancellationToken);
             }
         }

+ 37 - 20
src/Hotline.Application/Tels/TelApplication.cs

@@ -53,19 +53,27 @@ public class TelApplication : ITelApplication, IScopeDependency
         _cacheWork.Remove(work.GetKey(KeyMode.UserId));
         _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
 
-        var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
-        if (telAction != null)
-        {
-            telAction.EndAction();
-            await _telActionRecordRepository.UpdateAsync(telAction);
-        }
 
-        var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
-        if (telarrangeAction != null)
+        var list = await _telActionRecordRepository.Queryable().Where(x => x.TelNo == work.TelNo && !x.EndTime.HasValue).ToListAsync();
+        foreach (var item in list)
         {
-            telarrangeAction.EndAction();
-            await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+            item.EndAction();
+            await _telActionRecordRepository.UpdateAsync(item);
         }
+
+        //var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
+        //if (telAction != null)
+        //{
+        //    telAction.EndAction();
+        //    await _telActionRecordRepository.UpdateAsync(telAction);
+        //}
+
+        //var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
+        //if (telarrangeAction != null)
+        //{
+        //    telarrangeAction.EndAction();
+        //    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+        //}
     }
 
     public async Task SignOutByTelNoAsync(string telNo,CancellationToken cancellationToken)
@@ -85,18 +93,27 @@ public class TelApplication : ITelApplication, IScopeDependency
         _cacheWork.Remove(work.GetKey(KeyMode.UserId));
         _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
 
-        var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
-        if (telAction != null)
-        {
-            telAction.EndAction();
-            await _telActionRecordRepository.UpdateAsync(telAction);
-        }
 
-        var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
-        if (telarrangeAction != null)
+
+        var list = await _telActionRecordRepository.Queryable().Where(x => x.TelNo == work.TelNo && !x.EndTime.HasValue).ToListAsync();
+        foreach ( var item in list )
         {
-            telarrangeAction.EndAction();
-            await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+            item.EndAction();
+            await _telActionRecordRepository.UpdateAsync(item);
         }
+
+        //var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
+        //if (telAction != null)
+        //{
+        //    telAction.EndAction();
+        //    await _telActionRecordRepository.UpdateAsync(telAction);
+        //}
+
+        //var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
+        //if (telarrangeAction != null)
+        //{
+        //    telarrangeAction.EndAction();
+        //    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+        //}
     }
 }

+ 1 - 1
src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/ProvinceSendDelayResultDto.cs

@@ -4,7 +4,7 @@ namespace Hotline.Share.Dtos.DataSharing.PusherHotlineDto
     /// <summary>
     /// 省延期结果通知
     /// </summary>
-    public class ProvinceSendDelayResultDto
+    public class ProvinceSendDelayResultDto: DsSource
     {
         /// <summary>
         /// 省工单编号

+ 10 - 1
src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs

@@ -63,11 +63,20 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// 审核结果(非审批流程无意义)
     /// </summary>
     public EReviewResult ReviewResult { get; set; }
-
 }
 
 public class External
 {
     public int? TimeLimit { get; set; }
     public ETimeType? TimeLimitUnit { get; set; }
+
+    /// <summary>
+    /// 警情退回
+    /// </summary>
+    public bool IsPoliceReturn { get; set; }
+
+    /// <summary>
+    /// 部门是否解决
+    /// </summary>
+    public bool IsResolved { get; set; }
 }

+ 226 - 0
src/Hotline.Share/Dtos/Order/OrderBiDto.cs

@@ -476,10 +476,19 @@ namespace Hotline.Share.Dtos.Order
 		public string UserId { get; set; }
 		public string UserName { get; set; }
 
+		/// <summary>
+		/// 派单量
+		/// </summary>
 		public int SendOrderNum { get; set; }
 
+		/// <summary>
+		/// 待派单量
+		/// </summary>
 		public int NoSendOrderNum { get; set; }
 
+		/// <summary>
+		/// 重办量
+		/// </summary>
 		public int ReSendOrderNum { get; set; }
 
 		public string AccuracyRate { get; set; }
@@ -487,11 +496,228 @@ namespace Hotline.Share.Dtos.Order
 
 	public class OrderReTransactVo
 	{
+		/// <summary>
+		/// 时间
+		/// </summary>
 		public string Time { get; set; }
+
+		/// <summary>
+		/// 部门名称
+		/// </summary>
+		public string OrgName { get; set; }
+
+		/// <summary>
+		/// 部门id
+		/// </summary>
+		public string OrgId { get; set; }
+
+		/// <summary>
+		/// 次数
+		/// </summary>
+		public int Num { get; set; }
+	}
+
+	public class SecondaryHandlingVo
+	{
+		/// <summary>
+		/// 部门名称
+		/// </summary>
 		public string OrgName { get; set; }
 
+
+		/// <summary>
+		/// 部门id
+		/// </summary>
 		public string OrgId { get; set; }
 
+		/// <summary>
+		/// 次数
+		/// </summary>
 		public int Num { get; set; }
 	}
+
+	public class SecondaryHandlingSatisfactionVo
+	{
+		/// <summary>
+		/// 部门名称
+		/// </summary>
+		public string OrgName { get; set; }
+
+
+		/// <summary>
+		/// 部门id
+		/// </summary>
+		public string OrgId { get; set; }
+
+		/// <summary>
+		/// 部门类型
+		/// </summary>
+		public EOrgType OrgType { get; set; }
+
+		public string OrgTypeText => OrgType.GetDescription();
+
+		/// <summary>
+		/// 总数
+		/// </summary>
+		public int TotalSumCount { get; set; }
+
+		/// <summary>
+		/// 总满意度
+		/// </summary>
+		public double TotalSumRate => Math.Round(VerySatisfiedRate + SatisfiedRate + RegardedAsSatisfiedRate + DefaultSatisfiedRate, 2);
+
+		public string TotalSumRateText => TotalSumRate + "%";
+
+		/// <summary>
+		/// 非常满意数
+		/// </summary>
+		public int VerySatisfiedCount { get; set; }
+
+		/// <summary>
+		/// 非常满意率
+		/// </summary>
+		public double VerySatisfiedRate => CalcVerySatisfiedRate();
+
+		public double CalcVerySatisfiedRate()
+		{
+			if (VerySatisfiedCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((VerySatisfiedCount / (double)TotalSumCount) * 100, 2);
+		}
+
+		public string VerySatisfiedRateText => VerySatisfiedRate + "%";
+
+		/// <summary>
+		/// 满意数
+		/// </summary>
+		public int SatisfiedCount { get; set; }
+
+		/// <summary>
+		/// 满意率
+		/// </summary>
+		public double SatisfiedRate => CalcSatisfiedRate();
+
+
+		public double CalcSatisfiedRate()
+		{
+			if (SatisfiedCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((SatisfiedCount / (double)TotalSumCount) * 100, 3);
+		}
+		public string SatisfiedRateText => SatisfiedRate + "%";
+
+		/// <summary>
+		/// 视为满意数
+		/// </summary>
+		public int RegardedAsSatisfiedCount { get; set; }
+
+
+		/// <summary>
+		/// 视为满意率
+		/// </summary>
+		public double RegardedAsSatisfiedRate => CalcRegardedAsSatisfiedRate();
+
+		public double CalcRegardedAsSatisfiedRate()
+		{
+			if (RegardedAsSatisfiedCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((RegardedAsSatisfiedCount / (double)TotalSumCount) * 100, 3);
+		}
+		public string RegardedAsSatisfiedRateText => RegardedAsSatisfiedRate + "%";
+
+		/// <summary>
+		/// 默认满意数
+		/// </summary>
+		public int DefaultSatisfiedCount { get; set; }
+
+		/// <summary>
+		/// 默认满意率
+		/// </summary>
+		public double DefaultSatisfiedRate => CalcDefaultSatisfiedRate();
+
+		public double CalcDefaultSatisfiedRate()
+		{
+			if (DefaultSatisfiedCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((DefaultSatisfiedCount / (double)TotalSumCount) * 100, 3);
+		}
+
+		public string DefaultSatisfiedRateText => DefaultSatisfiedRate + "%";
+
+		/// <summary>
+		/// 不满意数
+		/// </summary>
+		public int NoSatisfiedCount { get; set; }
+		/// <summary>
+		/// 不满意率
+		/// </summary>
+		public double NoSatisfiedRate => CalcNoSatisfiedRate();
+
+
+		public double CalcNoSatisfiedRate()
+		{
+			if (NoSatisfiedCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((NoSatisfiedCount / (double)TotalSumCount) * 100, 3);
+		}
+
+		public string NoSatisfiedRateText => NoSatisfiedRate + "%";
+
+
+
+		/// <summary>
+		/// 未做评价数
+		/// </summary>
+		public int NoEvaluateCount { get; set; }
+
+		/// <summary>
+		/// 未做评价率
+		/// </summary>
+		public double NoEvaluateRate => CalcNoEvaluateRate();
+
+
+		public double CalcNoEvaluateRate()
+		{
+			if (NoEvaluateCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((NoEvaluateCount / (double)TotalSumCount) * 100, 3);
+		}
+		public string NoEvaluateRateText => NoEvaluateRate + "%";
+
+
+		/// <summary>
+		/// 未接通数
+		/// </summary>
+		public int NoPutThroughCount { get; set; }
+
+		/// <summary>
+		/// 未接通率
+		/// </summary>
+		public double NoPutThroughRate => CalcNoPutThroughRate();
+
+
+		public double CalcNoPutThroughRate()
+		{
+			if (NoPutThroughCount == 0 || TotalSumCount == 0)
+			{
+				return 0.000;
+			}
+			return Math.Round((NoPutThroughCount / (double)TotalSumCount) * 100, 3);
+		}
+
+		public string NoPutThroughRateText => NoPutThroughRate + "%";
+
+	}
 }

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

@@ -436,6 +436,12 @@ namespace Hotline.Share.Dtos.Order
 
         public string IsProvinceText => IsProvince ? "省工单" : "市工单";
 
+        /// <summary>
+        /// 部门是否解决
+        /// </summary>
+        public bool IsResolved { get; set; }
+        public string IsResolvedText => IsResolved ? "已解决" : "未解决";
+
     }
 
     public class UpdateOrderDto : AddOrderDto

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

@@ -34,5 +34,10 @@ namespace Hotline.Share.Dtos.Order
         public int HandlerOrgLevel { get; set; }
 
         public TrCallDto? TrCallRecordDto { get; set; }
+
+        /// <summary>
+        /// 非警情退回
+        /// </summary>
+        public bool IsNonPoliceReturn { get; set; }
     }
 }

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

@@ -406,10 +406,12 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public Kv? OrgProcessingResults { get; set; }
 
-        /// <summary>
-        /// 不满意原因
-        /// </summary>
-        public List<Kv>? OrgNoSatisfiedReason { get; set; }
+        public string OrgProcessingResultsText => !(OrgProcessingResults is null) ? OrgProcessingResults.Value : "";
+
+		/// <summary>
+		/// 不满意原因
+		/// </summary>
+		public List<Kv>? OrgNoSatisfiedReason { get; set; }
 
         /// <summary>
         /// 不满意原因字符串

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

@@ -188,6 +188,8 @@ namespace Hotline.Share.Dtos.TrCallCenter
 
         public bool? IsRest { get; set; }
 
+        public bool? IsCallHold { get; set; }
+
         public int Second => CalcSecond();
 
         public ETelModel? TelModel { get; set; }

+ 2 - 2
src/Hotline.Share/Dtos/Users/UserDto.cs

@@ -23,7 +23,7 @@ public record UserDto : AddUserDto
 
     public bool IsDeleted { get; set; }
 
-    public string? FullOrgName { get; set; }
+    //public string? FullOrgName { get; set; }
 
 
     public IReadOnlyList<RoleDto> Roles { get; set; }
@@ -63,7 +63,7 @@ public record AddUserDto
     /// <summary>
     /// 部门全名
     /// </summary>
-    public string? FullOrgName { get; set; }
+    //public string? FullOrgName { get; set; }
 
     /// <summary>
     /// 用户类型

+ 3 - 0
src/Hotline.Share/Enums/CallCenter/EActionType.cs

@@ -10,5 +10,8 @@ namespace Hotline.Share.Enums.CallCenter
 
         [Description("话后整理")]
         CallEndArrange = 1,
+
+        [Description("电话保持")]
+        CallHold = 2,
     }
 }

+ 1 - 1
src/Hotline.Share/Hotline.Share.csproj

@@ -7,7 +7,7 @@
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
     <NoWarn>$(NoWarn);1591;8618;</NoWarn>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-    <Version>1.0.70</Version>
+    <Version>1.0.73</Version>
   </PropertyGroup>
 
   <ItemGroup>

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

@@ -153,6 +153,23 @@ public record QueryOrderReTransactRequest : ReportPagedRequest
 
 }
 
+public record QuerySecondaryHandlingRequest : ReportPagedRequest
+{
+	public string? OrgName { get; set; }
+
+	public string? OrgId { get; set; }
+
+	/// <summary>
+	///  1  办件结果
+	/// </summary>
+	public int  TypeId { get; set; }
+
+	public string? CDPN { get; set; }
+
+	public string Header { get; set; }
+
+}
+
 public record QueryOrderReTransactDetailRequest : ReportPagedRequest
 {
 	public string? OrgName { get; set; }

+ 2 - 3
src/Hotline/Authentications/Police110SessionContext.cs

@@ -26,8 +26,7 @@ namespace Hotline.Authentications
         /// <summary>
         /// Id of current user or throw Exception for guest
         /// </summary>
-        /// <exception cref="AuthenticationException"></exception>
-        public string RequiredUserId { get; }
+        public string RequiredUserId => UserId ?? throw new ArgumentNullException();
         public string? UserName { get; }
         public string? Phone { get; }
 
@@ -36,7 +35,7 @@ namespace Hotline.Authentications
         /// </summary>
         public string[] Roles { get; }
         public string? OrgId { get; set; }
-        public string RequiredOrgId { get; }
+        public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
         public string? OrgName { get; set; }
         public int OrgLevel { get; set; }
         public string? OrgAreaCode { get; set; }

+ 2 - 2
src/Hotline/Authentications/ProvinceSessionContext.cs

@@ -22,7 +22,7 @@ namespace Hotline.Authentications
         /// Id of current user or throw Exception for guest
         /// </summary>
         /// <exception cref="AuthenticationException"></exception>
-        public string RequiredUserId { get; }
+        public string RequiredUserId => UserId ?? throw new ArgumentNullException();
         public string? UserName { get; }
         public string? Phone { get; }
 
@@ -31,7 +31,7 @@ namespace Hotline.Authentications
         /// </summary>
         public string[] Roles { get; }
         public string? OrgId { get; set; }
-        public string RequiredOrgId { get; }
+        public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
         public string? OrgName { get; set; }
         public int OrgLevel { get; set; }
         public string? OrgAreaCode { get; set; }

+ 2 - 2
src/Hotline/Authentications/YbEnterpriseSessionContext.cs

@@ -27,7 +27,7 @@ namespace Hotline.Authentications
         /// Id of current user or throw Exception for guest
         /// </summary>
         /// <exception cref="AuthenticationException"></exception>
-        public string RequiredUserId { get; }
+        public string RequiredUserId => UserId ?? throw new ArgumentNullException();
         public string? UserName { get; }
         public string? Phone { get; }
 
@@ -36,7 +36,7 @@ namespace Hotline.Authentications
         /// </summary>
         public string[] Roles { get; }
         public string? OrgId { get; set; }
-        public string RequiredOrgId { get; }
+        public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
         public string? OrgName { get; set; }
         public int OrgLevel { get; set; }
         public string? OrgAreaCode { get; set; }

+ 1 - 1
src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs

@@ -36,7 +36,7 @@ public record RedoNotify(Workflow Workflow, RecallDto Dto, bool IsOrgToCenter) :
 ///// </summary>
 //public record RejectNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotification;
 
-public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace) : INotification;
+public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace, External External) : INotification;
 
 public record TerminalWorkflowNotify(Workflow Workflow) : INotification;
 

+ 5 - 5
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -104,7 +104,7 @@ namespace Hotline.FlowEngine.Workflows
             ISessionContext current, CancellationToken cancellationToken)
         {
             //1. 创建first节点 (和trace)2.办理开始节点 
-            
+
             if (firstStepDefine.StepType is EStepType.End)
             {
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
@@ -323,7 +323,7 @@ namespace Hotline.FlowEngine.Workflows
 
             #region 办理当前节点
 
-            if (dto.Files.Any())
+            if (dto.Files != null && dto.Files.Any())
                 currentStep.FileJson = await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId,
                     currentStep.Id, cancellationToken);
 
@@ -719,8 +719,8 @@ namespace Hotline.FlowEngine.Workflows
                 .InnerJoin<WorkflowTrace>((wsh, wt) => wsh.WorkflowStepId == wt.StepId)
                 .LeftJoin<SystemOrganize>((wsh, wt, o) => wsh.OrgId == o.Id)
                 .Where((wsh, wt, o) => wsh.WorkflowId == workflowId &&
-                                    wt.BusinessType == EBusinessType.Department &&
-                                    wt.HandlerType == EHandlerType.OrgLevel &&
+                                    //wt.BusinessType == EBusinessType.Department &&
+                                    //wt.HandlerType == EHandlerType.OrgLevel &&
                                     !string.IsNullOrEmpty(wsh.OrgId) &&
                                     o.Level == 1)
                 .ToListAsync(cancellation);
@@ -1197,7 +1197,7 @@ namespace Hotline.FlowEngine.Workflows
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
-            await _mediator.Publish(new EndWorkflowNotify(workflow, endTrace), cancellationToken);
+            await _mediator.Publish(new EndWorkflowNotify(workflow, endTrace, dto.External), cancellationToken);
 
             return endTrace;
         }

+ 6 - 0
src/Hotline/Orders/Order.cs

@@ -728,6 +728,12 @@ namespace Hotline.Orders
         /// 是否行政执法类
         /// </summary>
         public bool? IsEnforcementOrder { get; set; }
+
+        /// <summary>
+        /// 部门是否解决
+        /// </summary>
+        [SugarColumn(DefaultValue = "f")]
+        public bool IsResolved { get; set; }
     }
 
 	public partial class Order

+ 58 - 0
src/Hotline/Permissions/EPermission.cs

@@ -388,6 +388,11 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName = "业务退回审批", Name = "业务退回审批", Description = "业务退回审批")]
         OrderPreviousAudit = 200502,
+        /// <summary>
+        /// 批量审批
+        /// </summary>
+        [Display(GroupName ="业务退回审批",Name ="批量审批",Description ="批量审批")]
+        OrderPreviousBatchAudit = 200503,
         #endregion
 
         #region 省退回申请
@@ -678,6 +683,54 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName = "ExaminOrderVisit", Name = "二次回访审核", Description = "二次回访审核")]
         ExaminOrderVisit = 201102,
+        #endregion
+
+        #region 二次办理
+        /// <summary>
+        /// 二次办理
+        /// </summary>
+        [Display(GroupName ="二次办理",Name ="二次办理",Description ="二次办理")]
+        SecondHandle = 201500,
+
+        #region 二次办理申请
+        /// <summary>
+        /// 二次办理申请
+        /// </summary>
+        [Display(GroupName = "二次办理申请",Name ="二次办理申请",Description ="二次办理申请")]
+        SecondHandleApply = 201501,
+
+        /// <summary>
+        /// 申请二次办理
+        /// </summary>
+        [Display(GroupName ="申请二次办理",Name ="申请二次办理",Description ="申请二次办理")]
+        ApplySecondHandle = 201502,
+        #endregion
+
+        #region 二次办理审批
+        /// <summary>
+        /// 二次办理审批
+        /// </summary>
+        [Display(GroupName ="二次办理审批",Name ="二次办理审批",Description ="二次办理审批")]
+        SecondHandleApproval = 201503,
+
+        /// <summary>
+        /// 二次办理退回
+        /// </summary>
+        [Display(GroupName ="二次办理退回",Name ="二次办理退回",Description ="二次办理退回")]
+        SecondHandleReturn = 201504,
+        /// <summary>
+        /// 二次办理审批
+        /// </summary>
+        [Display(GroupName ="二次办理审批",Name ="二次办理审批",Description ="二次办理审批")]
+        ApprovalSecondHandle  = 201505,
+        /// <summary>
+        /// 批量审批
+        /// </summary>
+        [Display(GroupName ="二次办理审批",Name ="批量审批",Description ="批量审批")]
+        BatchApprovalSecondHandle = 201506,
+
+        #endregion
+
         #endregion
         #endregion
 
@@ -1933,6 +1986,11 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName ="数据统计",Name ="热线号码统计",Description ="热线号码统计")]
         HotLineNumStatistics = 110107,
+        /// <summary>
+        /// 坐席动作类型统计
+        /// </summary>
+        [Display(GroupName ="数据统计",Name ="坐席动作类型统计",Description ="坐席动作类型统计")]
+        SeatActionTypeStatistics = 110108,
         #endregion
 
         #region 业务统计(11,02,00)

+ 1 - 2
src/XF.Domain/Authentications/DefaultSessionContext.cs

@@ -71,8 +71,7 @@ namespace XF.Domain.Authentications
         public string? AreaId { get; set; }
 
         public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
-
-        public string RequiredOrgCode => OrgCode ?? throw new ArgumentNullException();
+        
         public string? ClientId { get; }
 
         /// <summary>