浏览代码

merge release -> dev

xf 8 月之前
父节点
当前提交
ed6ea8351e
共有 33 个文件被更改,包括 497 次插入324 次删除
  1. 0 8
      src/Hotline.Api/Controllers/Bi/BiCallController.cs
  2. 38 58
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  3. 27 41
      src/Hotline.Api/Controllers/CallController.cs
  4. 6 7
      src/Hotline.Api/Controllers/CommonPController.cs
  5. 2 2
      src/Hotline.Api/Controllers/ContingencyManagementController.cs
  6. 6 2
      src/Hotline.Api/Controllers/IPPbxController.cs
  7. 37 32
      src/Hotline.Api/Controllers/KnowledgeController.cs
  8. 33 29
      src/Hotline.Api/Controllers/OrderController.cs
  9. 3 0
      src/Hotline.Api/Controllers/PushMessageController.cs
  10. 20 4
      src/Hotline.Api/Controllers/TestController.cs
  11. 1 0
      src/Hotline.Api/Hotline.Api.csproj
  12. 1 1
      src/Hotline.Application/CallCenter/DefaultCallApplication.cs
  13. 2 2
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  14. 2 2
      src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs
  15. 6 2
      src/Hotline.Application/Handlers/FlowEngine/WorkflowPreviousHandler.cs
  16. 9 4
      src/Hotline.Application/Handlers/FlowEngine/WorkflowStartHandler.cs
  17. 1 0
      src/Hotline.Application/Hotline.Application.csproj
  18. 59 51
      src/Hotline.Application/Orders/IOrderApplication.cs
  19. 80 11
      src/Hotline.Application/Orders/OrderApplication.cs
  20. 3 5
      src/Hotline.Application/StatisticalReport/CallReportApplication.cs
  21. 2 2
      src/Hotline.Application/Subscribers/InternalCapSubscriber.cs
  22. 1 1
      src/Hotline.Repository.SqlSugar/CallCenter/TrCallRecordRepository.cs
  23. 1 1
      src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs
  24. 1 1
      src/Hotline.Share/Dtos/CallCenter/QueryCallsDetailDto.cs
  25. 8 4
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  26. 17 2
      src/Hotline.Share/Dtos/Push/MessagePagedDto.cs
  27. 1 1
      src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs
  28. 5 0
      src/Hotline.Share/Enums/CallCenter/ECallTransliterationState.cs
  29. 7 3
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  30. 5 5
      src/Hotline/KnowledgeBase/Knowledge.cs
  31. 31 28
      src/Hotline/KnowledgeBase/KnowledgeDomainService.cs
  32. 20 15
      src/Hotline/Orders/OrderDomainService.cs
  33. 62 0
      src/Hotline/dataview.md

+ 0 - 8
src/Hotline.Api/Controllers/Bi/BiCallController.cs

@@ -253,10 +253,6 @@ public class BiCallController : BaseController
     [HttpGet("query_incall_calls_list")]
     public async Task<PagedDto<TrCallDtoNew>> GetInCallCallListAsync([FromQuery] BiQueryCallsDto dto)
     {
-        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
-            throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         var (total, items) = await _callReportApplication.QueryCallsDetailInTotalAsync(dto)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
@@ -271,10 +267,6 @@ public class BiCallController : BaseController
     [HttpPost("query_incall_calls_list_export")]
     public async Task<FileStreamResult> GetInCallCallListExportAsync([FromBody] ExportExcelDto<BiQueryCallsDto> dto)
     {
-        if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue)
-            throw UserFriendlyException.SameMessage("请选择时间!");
-        dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
         var query = _callReportApplication.QueryCallsDetailInTotalAsync(dto.QueryDto);
         List<TrCallRecord> data;
         if (dto.IsExportAll)

+ 38 - 58
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -283,59 +283,39 @@ namespace Hotline.Api.Controllers.Bi
         [HttpGet("centre_data_list")]
         public async Task<List<OrderBiCentreDataListVo>> CentreDataList([FromQuery] ReportPagedRequest dto)
         {
-            if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
-
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-
-            var query = _orderRepository.Queryable(false, false, false)
-                .WhereIF(dto.StartTime.HasValue, it => it.CreationTime >= dto.StartTime)
-                .WhereIF(dto.EndTime.HasValue, it => it.CreationTime <= dto.EndTime)
-                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), it => it.SignerName.Contains(dto.Keyword!))
-                .GroupBy(it => new { it.SignerId, it.SignerName })
-                .Select(it => new OrderBiCentreDataListVo
-                {
-                    UserName = it.SignerName,
-                    UserId = it.SignerId,
-                    //Subtotal = SqlFunc.AggregateCount(x.AcceptorId),
-                    CentreArchive = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Zhiban && it.AcceptType != "无效", 1, 0)), //中心归档件
-                    //CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && (it.FileUserRole == EFileUserType.Org || it.FileUserRole == EFileUserType.Dispatch), 1, 0)), //转办信件
-                    CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType != "无效" && (it.ProcessType == EProcessType.Jiaoban || (it.ActualHandleStepName == "派单组" && it.Status < EOrderStatus.Filed) || (it.ActualHandleStepName == "班长审批" && it.Status < EOrderStatus.Filed)), 1, 0)),
-                    NoCentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType != "无效" && (it.Status <= EOrderStatus.SpecialToUnAccept), 1, 0)), //坐席待办 //中心领导?市领导? 是否在统计条件中
-                    //CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Jiaoban, 1, 0)),
-                    //NoCentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF((int)x.Status < 300 && x.ExpiredTime > x.FiledTime, 1, 0)),
-                    Invalid = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType == "无效", 1, 0)),
-                    Repeat = SqlFunc.AggregateSum(SqlFunc.IIF(it.DuplicateIds != null && SqlFunc.JsonArrayLength(it.DuplicateIds) > 0, 1, 0)),
-                    Subtotal = SqlFunc.AggregateSum(SqlFunc.IIF((it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Zhiban && it.AcceptType != "无效") || (it.AcceptType != "无效" && (it.ProcessType == EProcessType.Jiaoban || (it.ActualHandleStepName == "派单组" && it.Status < EOrderStatus.Filed) || (it.ActualHandleStepName == "班长审批" && it.Status < EOrderStatus.Filed))) || (it.Status <= EOrderStatus.SpecialToUnAccept) || it.AcceptType == "无效" || (it.DuplicateIds != null && SqlFunc.JsonArrayLength(it.DuplicateIds) > 0), 1, 0))
-                }).MergeTable();
-            switch (dto.SortField)
-            {
-                case "centreArchive":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreArchive) : query.OrderByDescending(x => x.CentreArchive);
-                    break;
-                case "centreCareOf":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreCareOf) : query.OrderByDescending(x => x.CentreCareOf);
-                    break;
-                case "noCentreCareOf":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.NoCentreCareOf) : query.OrderByDescending(x => x.NoCentreCareOf);
-                    break;
-                case "invalid":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Invalid) : query.OrderByDescending(x => x.Invalid);
-                    break;
-                case "repeat":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Repeat) : query.OrderByDescending(x => x.Repeat);
-                    break;
-                case "subtotal":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Subtotal) : query.OrderByDescending(x => x.Subtotal);
-                    break;
-            }
+            var query = _orderApplication.CentreDataList(dto);
+            var list = await query.Where(x => (x.CentreArchive + x.CentreCareOf + x.NoCentreCareOf + x.Invalid + x.Repeat) != 0).ToListAsync(HttpContext.RequestAborted);
+            return list;
+        }
 
-            if (string.IsNullOrEmpty(dto.SortField))
+        /// <summary>
+        /// 话务员办件统计--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("centre_data_list_export")]
+        public async Task<FileStreamResult> CentreDataListExport([FromBody] ExportExcelDto<ReportPagedRequest> dto)
+        {
+            var query = _orderApplication.CentreDataList(dto.QueryDto);
+            List<OrderBiCentreDataListVo> data = await query.Where(x => (x.CentreArchive + x.CentreCareOf + x.NoCentreCareOf + x.Invalid + x.Repeat) != 0).ToListAsync(HttpContext.RequestAborted);
+            data.Add(new OrderBiCentreDataListVo
             {
-                query = query.OrderByDescending(x => x.Subtotal);
-            }
+                UserName = "合计",
+                CentreArchive = data.Select(s => s.CentreArchive).Sum(),
+                CentreCareOf = data.Select(s => s.CentreCareOf).Sum(),
+                NoCentreCareOf = data.Select(s => s.NoCentreCareOf).Sum(),
+                Invalid = data.Select(s => s.Invalid).Sum(),
+                Repeat = data.Select(s => s.Repeat).Sum(),
+                Subtotal = data.Select(s => s.Subtotal).Sum()
+            });
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            var dtos = data
+             .Select(stu => _mapper.Map(stu, typeof(OrderBiCentreDataListVo), dynamicClass))
+             .Cast<object>()
+             .ToList();
 
-            var list = await query.Where(x => (x.CentreArchive + x.CentreCareOf + x.NoCentreCareOf + x.Invalid + x.Repeat) != 0).ToListAsync(HttpContext.RequestAborted);
-            return list;
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "话务员办件统计");
         }
 
         /// <summary>
@@ -1443,35 +1423,35 @@ namespace Hotline.Api.Controllers.Bi
                 OrgCode = "",
                 OrgType = "",
                 ZxAllCount = items.Sum(p => p.ZxAllCount),
-                ZxAllTimes = Math.Round(items.Sum(p => p.ZxAllTimes).Value,2),
+                ZxAllTimes = Math.Round(items.Sum(p => p.ZxAllTimes).Value, 2),
                 ZxAcceptanceTypeCode = "10",
 
                 JyAllCount = items.Sum(p => p.JyAllCount),
-                JyAllTimes = Math.Round(items.Sum(p => p.JyAllTimes).Value,2),
+                JyAllTimes = Math.Round(items.Sum(p => p.JyAllTimes).Value, 2),
                 JyAcceptanceTypeCode = "15",
 
                 QzAllCount = items.Sum(p => p.QzAllCount),
-                QzAllTimes = Math.Round(items.Sum(p => p.QzAllTimes).Value,2),
+                QzAllTimes = Math.Round(items.Sum(p => p.QzAllTimes).Value, 2),
                 QzAcceptanceTypeCode = "20",
 
                 ByAllCount = items.Sum(p => p.ByAllCount),
-                ByAllTimes = Math.Round(items.Sum(p => p.ByAllTimes).Value,2),
+                ByAllTimes = Math.Round(items.Sum(p => p.ByAllTimes).Value, 2),
                 ByAcceptanceTypeCode = "25",
 
                 JbAllCount = items.Sum(p => p.JbAllCount),
-                JbAllTimes = Math.Round(items.Sum(p => p.JbAllTimes).Value,2),
+                JbAllTimes = Math.Round(items.Sum(p => p.JbAllTimes).Value, 2),
                 JbAcceptanceTypeCode = "30",
 
                 TsAllCount = items.Sum(p => p.TsAllCount),
-                TsAllTimes = Math.Round(items.Sum(p => p.TsAllTimes).Value,2),
+                TsAllTimes = Math.Round(items.Sum(p => p.TsAllTimes).Value, 2),
                 TsAcceptanceTypeCode = "35",
 
                 QtAllCount = items.Sum(p => p.QtAllCount),
-                QtAllTimes = Math.Round(items.Sum(p => p.QtAllTimes).Value,2),
+                QtAllTimes = Math.Round(items.Sum(p => p.QtAllTimes).Value, 2),
                 QtAcceptanceTypeCode = "40",
 
                 YjAllCount = items.Sum(p => p.YjAllCount),
-                YjAllTimes = Math.Round(items.Sum(p => p.YjAllTimes).Value,2),
+                YjAllTimes = Math.Round(items.Sum(p => p.YjAllTimes).Value, 2),
                 YjAcceptanceTypeCode = "1"
             };
 

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

@@ -142,48 +142,34 @@ namespace Hotline.Api.Controllers
         [HttpPost("calls/transliteration")]
         public async Task CallTransliteration([FromBody] CallTransliteration dto)
         {
-	        string audioFile;
-	        string fromNo;
-	        DateTime? callStartTime = null;
-            string Id;
-			//if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.TianRun)
-	  //      {
-		    var call = await _callApplication.GetTianrunCallAsync(dto.Id, HttpContext.RequestAborted);
-		    if (call is null)
-			    throw UserFriendlyException.SameMessage("通话信息错误");
-		    if (call.TransliterationState  == ECallTransliterationState.Underway)
-			    throw UserFriendlyException.SameMessage("正在转写中,请勿重复点击,请稍作等待");
-		    if (call.TransliterationState == ECallTransliterationState.Succeed)
-			    throw UserFriendlyException.SameMessage("转写成功,不能重新转写");
-			call.InitTransliterationId();
-			await _callApplication.EditTransliterationStateAsync(call.Id, ECallTransliterationState.Underway, call.TransliterationId, HttpContext.RequestAborted);
-			audioFile = call.RecordingAbsolutePath;
-		    fromNo = call.CPN;
-		    callStartTime = call.CreatedTime;
-		    Id = call.TransliterationId;
-			//}
-	  //      else if (_callcenterOptions.Value.CallCenterType == AppDefaults.CallCenterType.XingTang)
-	  //      {
-		 //       var call = await _callApplication.GetCallAsync(dto.Id, HttpContext.RequestAborted);
-		 //       if (call is null)
-			//        throw UserFriendlyException.SameMessage("通话信息错误");
-			//	audioFile = call.AudioFile;
-		 //       fromNo = call.FromNo;
-		 //       callStartTime = call.BeginIvrTime;
-		 //       Id = call.Id;
-			//}
-	        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ViteRecordPrefix);
-	       
-	        var handler = new AiQualityHandler()
+	        foreach (var id in dto.Ids)
 	        {
-		        Id = Id,
-		        Source = "AiAnswered",
-		        AudioFile = audioFile,
-		        FromNo = fromNo,
-		        CallStartTime = callStartTime,
-		        ViteRecordPrefix = setting?.SettingValue[0],
-	        };
-	        await _publisher.PublishAsync(new AiOrderQualityNotify(handler), PublishStrategy.ParallelNoWait, HttpContext.RequestAborted);
+				var call = await _callApplication.GetTianrunCallAsync(id, HttpContext.RequestAborted);
+				if (call is null)
+					throw UserFriendlyException.SameMessage("通话信息错误");
+				if (call.TransliterationState == ECallTransliterationState.Underway)
+					throw UserFriendlyException.SameMessage("正在转写中,请勿重复点击,请稍作等待");
+				if (call.TransliterationState == ECallTransliterationState.Succeed)
+					throw UserFriendlyException.SameMessage("转写成功,不能重新转写");
+				call.InitTransliterationId();
+				await _callApplication.EditTransliterationStateAsync(call.Id, ECallTransliterationState.Underway, call.TransliterationId, HttpContext.RequestAborted);
+				var audioFile = call.RecordingAbsolutePath;
+				var fromNo = call.CPN;
+				var callStartTime = call.CreatedTime;
+				var Id = call.TransliterationId;
+				var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ViteRecordPrefix);
+
+				var handler = new AiQualityHandler()
+				{
+					Id = Id,
+					Source = "AiAnswered",
+					AudioFile = audioFile,
+					FromNo = fromNo,
+					CallStartTime = callStartTime,
+					ViteRecordPrefix = setting?.SettingValue[0],
+				};
+				await _publisher.PublishAsync(new AiOrderQualityNotify(handler), PublishStrategy.ParallelNoWait, HttpContext.RequestAborted);
+			}
         }
 	}
 }

+ 6 - 7
src/Hotline.Api/Controllers/CommonPController.cs

@@ -179,17 +179,16 @@ namespace Hotline.Api.Controllers
             //甄别
             var screenAudit = await _orderScreenRepository.Queryable(hasHandled: false)
                 .Where(x=>x.CreationTime < DateTime.Now && x.CreationTime > DateTime.Now.AddMonths(-2))
-                .Where(d => d.Status == EScreenStatus.Apply)
+                .Where(x => (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval || (x.Status == EScreenStatus.SendBack && x.SendBackApply == false)))
+                //.Where(d => d.Status == EScreenStatus.Apply)
                 .CountAsync();
             //var workTime = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
             var screenHandle = await _orderVisitedDetailRepository.Queryable(false, true)
                 .Includes(x => x.OrderVisit)
-                .LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId  && s.IsDeleted == false)
-                               //&& s.Status < EScreenStatus.End
-				.Where((x, s) => s.Id == null)
-                //.Where(x => x.OrderVisit.VisitTime < DateTime.Now && x.OrderVisit.VisitTime > workTime)
-                .Where((x, s) => x.OrderVisit.VisitState == EVisitState.Visited && x.OrderVisit.IsCanHandle)
-                .Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode == _sessionContext.OrgId && (
+                .Includes(x => x.OrderScreens)
+				.Where(x => x.OrderScreens.Any(s => s.Status == EScreenStatus.SendBack && s.SendBackApply == true) || x.OrderScreens.Any(s => (s.Status != EScreenStatus.SendBack && s.SendBackApply != true)) == false)
+                .Where(x => x.OrderVisit.VisitState == EVisitState.Visited && x.OrderVisit.IsCanHandle)
+                .Where(x=> x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode == _sessionContext.OrgId && (
                     SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" || SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" || SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2")).CountAsync();
             return new

+ 2 - 2
src/Hotline.Api/Controllers/ContingencyManagementController.cs

@@ -48,7 +48,7 @@ namespace Hotline.Api.Controllers
         public async Task<PagedDto<ContingencyManagementOrdersDto>> GetList([FromQuery] ContingencyManagementPagedKeywordRequest dto)
         {
             var (total, items) = await _contingencyManagementOrdersRepository.Queryable()
-                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.Contains(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.ArrangeTitle.Contains(dto.Title))
                 .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No.Contains(dto.No))
                 .WhereIF(!string.IsNullOrEmpty(dto.HotspotSpliceName), p => p.HotspotSpliceName.Contains(dto.HotspotSpliceName))
                 .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), p => p.AcceptType.Contains(dto.AcceptType))
@@ -72,7 +72,7 @@ namespace Hotline.Api.Controllers
         public async Task<FileStreamResult> GetListExport([FromBody] ExportExcelDto<ContingencyManagementPagedKeywordRequest> dto)
         {
             var query = _contingencyManagementOrdersRepository.Queryable()
-                .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Title), p => p.Title.Contains(dto.QueryDto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Title), p => p.ArrangeTitle.Contains(dto.QueryDto.Title))
                 .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.No), p => p.No.Contains(dto.QueryDto.No))
                 .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.HotspotSpliceName), p => p.HotspotSpliceName.Contains(dto.QueryDto.HotspotSpliceName))
                 .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.AcceptType), p => p.AcceptType.Contains(dto.QueryDto.AcceptType))

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

@@ -39,6 +39,7 @@ using Hotline.FlowEngine.Notifications;
 using Hotline.Quality.Notifications;
 using Hotline.Share.Dtos.Quality;
 using MongoDB.Driver;
+using Hotline.Repository.SqlSugar.CallCenter;
 
 namespace Hotline.Api.Controllers
 {
@@ -66,6 +67,7 @@ namespace Hotline.Api.Controllers
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
         private readonly IRepository<TelActionRecord> _telActionRecordRepository;
         private readonly ISystemMobilAreaApplication _systemMobilAreaApplication;
+        private readonly IRepository<Work> _workRepository;
         private readonly Publisher _publisher;
 
 		public IPPbxController(ITrClient trClient, IMapper mapper, IUserDomainService userDomainService,
@@ -78,7 +80,7 @@ namespace Hotline.Api.Controllers
             ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
             IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate, 
             ISystemSettingCacheManager systemSettingCacheManager,IRepository<TelActionRecord> telActionRecordRepository,
-            ISystemMobilAreaApplication systemMobilAreaApplication, Publisher publisher)
+            ISystemMobilAreaApplication systemMobilAreaApplication,IRepository<Work> workRepository ,Publisher publisher)
         {
             _trClient = trClient;
             _mapper = mapper;
@@ -102,6 +104,7 @@ namespace Hotline.Api.Controllers
             _systemSettingCacheManager = systemSettingCacheManager;
             _telActionRecordRepository = telActionRecordRepository;
             _systemMobilAreaApplication = systemMobilAreaApplication;
+            _workRepository = workRepository;
             _publisher = publisher;
 
 		}
@@ -136,7 +139,8 @@ namespace Hotline.Api.Controllers
         public async Task<IReadOnlyList<TrTelStateDto>> TrQueryTelState([FromQuery] string? state)
         {
             var tels = await _trClient.QueryTelStateAsync(new QueryTelStateRequest() { State = state }, HttpContext.RequestAborted);
-            var workList = _userCacheManager.GetWorks();
+            //var workList = _userCacheManager.GetWorks();
+            var workList = await _workRepository.Queryable().Where(d=> 1 == 1 && !d.EndTime.HasValue).ToListAsync();
             var query = from tel in tels.AgentList
                         join works in workList on tel.TelNo equals works.TelNo into workD
                         from work in workD.DefaultIfEmpty()

+ 37 - 32
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -27,6 +27,7 @@ using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
+using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
 
 namespace Hotline.Api.Controllers
 {
@@ -136,22 +137,25 @@ namespace Hotline.Api.Controllers
             kn.InitId();
             if (dto.Data.Files.Any()) kn.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, kn.Id, "", HttpContext.RequestAborted);
             await _knowledgeRepository.AddAsync(kn, HttpContext.RequestAborted);
-            if (dto.Workflow != null && !string.IsNullOrEmpty(kn.Id))
+            if (dto.Data.KnowledgeType.Any())
+            {
+				List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
+				types.ForEach(x => x.KnowledgeId = kn.Id);
+				await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
+			}
+			if (dto.Workflow != null && !string.IsNullOrEmpty(kn.Id))
             {
                 var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                 startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeAdd;
                 startDto.Title = "知识库新增";
+                //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, kn.Id, cancellationToken: HttpContext.RequestAborted);
+
                 await StartFlow(kn.Id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, startDto);
-                var knowledge = await _knowledgeRepository.GetAsync(kn.Id);
-                knowledge.Status = EKnowledgeStatus.Auditing;
-                await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
+                //var knowledge = await _knowledgeRepository.GetAsync(kn.Id);
+                //knowledge.Status = EKnowledgeStatus.Auditing;
+                //await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
             }
-            if (dto.Data.KnowledgeType.Any())
-            {
-                List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
-                types.ForEach(x => x.KnowledgeId = kn.Id);
-				await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
-			}
+         
             return kn.Id;
         }
 
@@ -249,32 +253,37 @@ namespace Hotline.Api.Controllers
                 knowledge.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, knowledge.Id, "", HttpContext.RequestAborted);
             else
 	            knowledge.FileJson = new List<Share.Dtos.File.FileJson>();
-			if (dto.Workflow != null) knowledge.Renewaln = update.Status != EKnowledgeStatus.Drafts;
+			if (dto.Workflow != null) knowledge.Renewaln = knowledge.Status != EKnowledgeStatus.Drafts;
             await _knowledgeRepository.UpdateAsync(knowledge, HttpContext.RequestAborted);
-            if (dto.Workflow != null)
+            if (dto.Data.KnowledgeType.Any())
+            {
+	            var anyRelationTypes = await _knowledgeRelationTypeRepository.Queryable().Where(x => x.KnowledgeId == knowledge.Id).ToListAsync();
+	            if (anyRelationTypes.Any())
+		            await _knowledgeRelationTypeRepository.RemoveRangeAsync(anyRelationTypes);
+	            List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
+	            types.ForEach(x => x.KnowledgeId = update.Id);
+	            await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
+            }
+			if (dto.Workflow != null)
             {
-                if (update.Status == EKnowledgeStatus.Drafts)
+                if (knowledge.Status == EKnowledgeStatus.Drafts)
                 {
                     var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                     startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeAdd;
                     startDto.Title = "知识库新增";
-                    await StartFlow(update.Id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, startDto);
+                    //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
+                    await StartFlow(knowledge.Id, WorkflowModuleConsts.KnowledgeAdd, EKnowledgeApplyType.Add, startDto);
                 }
                 else
                 {
                     var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                     startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeUpdate;
                     startDto.Title = "知识库修改";
-                    await StartFlow(update.Id, WorkflowModuleConsts.KnowledgeUpdate, EKnowledgeApplyType.Update, startDto);
+                    //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
+                    await StartFlow(knowledge.Id, WorkflowModuleConsts.KnowledgeUpdate, EKnowledgeApplyType.Update, startDto);
                 }
             }
-            if (dto.Data.KnowledgeType.Any())
-            {
-                await _knowledgeRelationTypeRepository.RemoveAsync(t => t.KnowledgeId == update.Id);
-				List<KnowledgeRelationType> types = _mapper.Map<List<KnowledgeRelationType>>(dto.Data.KnowledgeType);
-                types.ForEach(x => x.KnowledgeId = update.Id);
-				await _knowledgeRelationTypeRepository.AddRangeAsync(types, HttpContext.RequestAborted);
-            }
+            
 		}
 
         /// <summary>
@@ -301,6 +310,7 @@ namespace Hotline.Api.Controllers
                 var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
                 startDto.DefinitionModuleCode = WorkflowModuleConsts.KnowledgeDelete;
                 startDto.Title = "知识库删除";
+                //await _workflowApplication.StartWorkflowAsync(startDto, _sessionContext, knowledge.Id, cancellationToken: HttpContext.RequestAborted);
                 await StartFlow(delete.Id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, startDto);
             }
         }
@@ -607,6 +617,7 @@ namespace Hotline.Api.Controllers
                 .Includes(x => x.Workflow)
                 .Where(x => x.KnowledgeId == pagedDto.id)
                 .Where(x => x.IsDeleted == false)
+                .OrderBy(x=>x.CreationTime)
                 .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize);
             return new PagedDto<KnowledgeWorkFlowDto>(total, _mapper.Map<IReadOnlyList<KnowledgeWorkFlowDto>>(temp));
         }
@@ -819,7 +830,7 @@ namespace Hotline.Api.Controllers
         /// <param name="eKnowledgeApplyType">申请类型</param>
         /// <param name="dto">流程开启参数</param>
         /// <returns></returns>
-        private async Task StartFlow(string id, string moduleCode, EKnowledgeApplyType eKnowledgeApplyType, StartWorkflowDto dto)
+        private async Task<string> StartFlow(string id, string moduleCode, EKnowledgeApplyType eKnowledgeApplyType, StartWorkflowDto dto)
         {
             var knowledge = await _knowledgeRepository.GetAsync(id, HttpContext.RequestAborted);
             if (knowledge == null)
@@ -829,21 +840,15 @@ namespace Hotline.Api.Controllers
             {
                 if (knowledge.IsDeleted == true)
                     throw UserFriendlyException.SameMessage("知识删除失败");
-
-                ////验证是否已经发起过知识删除流程
-                //var exists = await _knowledgeWorkFlowRepository.GetAsync(p => p.KnowledgeId == knowledge.Id && p.WorkflowModuleStatus == EKnowledgeApplyType.Delete
-                //&& (p.WorkFlowApplyStatus == EKnowledgeWorkFlowStatus.Success || p.WorkFlowApplyStatus == EKnowledgeWorkFlowStatus.Auditing) && p.WorkflowId != null);
-                //if (exists != null)
-                //	throw UserFriendlyException.SameMessage($"该知识已发起过{WorkflowModuleConsts.KnowledgeDelete}流程");//todo
             }
 
             //知识审批主表
-            var flowId = await _knowledgeDomainService.AddWorkFlowAsync(id, eKnowledgeApplyType, HttpContext.RequestAborted);
+            await _knowledgeDomainService.AddWorkFlowAsync(id, eKnowledgeApplyType, HttpContext.RequestAborted);
 
             dto.DefinitionModuleCode = moduleCode;
             dto.Title = knowledge.Title;
-            await _workflowApplication.StartWorkflowAsync(dto, _sessionContext, flowId, cancellationToken: HttpContext.RequestAborted);
-        }
+            return await _workflowApplication.StartWorkflowAsync(dto, _sessionContext, id, cancellationToken: HttpContext.RequestAborted);
+		}
         #endregion
 
         #region 知识库词库

+ 33 - 29
src/Hotline.Api/Controllers/OrderController.cs

@@ -1808,6 +1808,19 @@ public class OrderController : BaseController
     [HttpGet("screen")]
     public async Task<PagedDto<OrderScreenListDto>> ScreenList([FromQuery] ScreenListDto dto)
     {
+		var handler = dto.TabStatus is EScreenStatus.Apply;
+		ISugarQueryable<OrderScreen> query;
+		if (dto.source == 1)
+		{
+			query = _orderScreenRepository.Queryable(hasHandled: !handler);
+		}
+		else
+		{
+			query = _orderScreenRepository.Queryable()
+				.Where(x => x.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId));
+		}
+		query = query.Includes(d => d.Order)
+			.Includes(d => d.Order)
         var view = dto.source == 1;
         var handler = dto.source == 1 && dto.Status is EScreenStatus.Apply;
         var isAdmin = _orderDomainService.IsCheckAdmin();
@@ -1821,7 +1834,7 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Visit.Order.No.Contains(dto.No!));
         if (dto.TabStatus is EScreenStatus.Apply)
         {
-            query.Where(d => (d.Status == EScreenStatus.Apply || d.Status == EScreenStatus.Approval || (d.Status == EScreenStatus.SendBack || d.SendBackApply == false)));
+            query.Where(d => (d.Status == EScreenStatus.Apply || d.Status == EScreenStatus.Approval || (d.Status == EScreenStatus.SendBack && d.SendBackApply == false)));
         }
 
         if (dto.TabStatus.HasValue && dto.Status == EScreenStatus.MyHandle)
@@ -1831,7 +1844,7 @@ public class OrderController : BaseController
 
         var (total, items) = await query
             .WhereIF(dto.DataScope is 1, x => x.CreatorId == _sessionContext.RequiredUserId)
-            .WhereIF(dto.Status.HasValue, x => x.Status == dto.Status)
+            //.WhereIF(dto.Status.HasValue, x => x.Status == dto.Status)
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.Order!.AcceptTypeCode! == dto.AcceptType!)
             .WhereIF(!string.IsNullOrEmpty(dto.HotspotSpliceName), x => x.Order!.Hotspot.HotSpotFullName!.StartsWith(dto.HotspotSpliceName!))
             .WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), x => x.Order!.SourceChannelCode! == dto.SourceChannel!)
@@ -1900,7 +1913,7 @@ public class OrderController : BaseController
         }
 
         var model = _mapper.Map<OrderScreen>(dto.Data);
-        model.Status = EScreenStatus.Apply;
+        model.Status = EScreenStatus.Approval;
         model.ApplyEndTime = endTime;
         model.TimeConsuming = _timeLimitDomainService.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false);
         model.InitId();
@@ -1945,13 +1958,17 @@ public class OrderController : BaseController
     public async Task InitialNextFlow([FromBody] ScreenNextFlowDto dto)
     {
         var screen = await _orderScreenRepository.GetAsync(dto.Data.Id);
-        _mapper.Map(dto.Data, screen);
+
         if (dto.Data.Files.Any())
             screen.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, screen.Id, "", HttpContext.RequestAborted);
         else
             screen.FileJson = new List<Share.Dtos.File.FileJson>();
 
-        screen.SendBackApplyNum++;
+        screen.Content = dto.Data.Content;
+        screen.TypeDicId = dto.Data.TypeDicId;
+        screen.TypeDicName = dto.Data.TypeDicName;
+        screen.SendBackApply = false;
+		screen.SendBackApplyNum++;
         await _orderScreenRepository.UpdateAsync(screen, HttpContext.RequestAborted);
         try
         {
@@ -1965,23 +1982,6 @@ public class OrderController : BaseController
         }
     }
 
-    /// <summary>
-    /// 甄别流程退回
-    /// </summary>
-    [HttpPost("screen/previous")]
-    public async Task ScreenPrevious([FromBody] PreviousWorkflowDto dto)
-    {
-        var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
-            cancellationToken: HttpContext.RequestAborted);
-        var screen = await _orderScreenRepository.Queryable().Where(x => x.WorkflowId == dto.WorkflowId).FirstAsync();
-        if (screen == null)
-            throw UserFriendlyException.SameMessage("甄别信息错误!");
-        screen.SendBackApply = workflow.Steps.Count <= 2;
-        await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
-        screen.Status = EScreenStatus.SendBack;
-        screen.SendBackNum++;
-        await _orderScreenRepository.UpdateAsync(screen, HttpContext.RequestAborted);
-    }
     /// <summary>
     /// 查询工单甄别流程开启参数
     /// </summary>
@@ -2075,7 +2075,9 @@ public class OrderController : BaseController
         //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
         rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
             _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
-        rspModel.Handle = false;
+        if (model.Status == EScreenStatus.SendBack && model.SendBackApply)
+            rspModel.IsCanHandle = false;
+		rspModel.Handle = false;
         if (!string.IsNullOrEmpty(rspModel.WorkflowId))
         {
             rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
@@ -3186,8 +3188,8 @@ public class OrderController : BaseController
                 expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne, dto.Opinion,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
                 canUpdateOrderSender);
-            //发送短信即将超期
-            _capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+            //TODO发送短信即将超期
+            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
         }
         else if (dto.FlowDirection is EFlowDirection.CenterToOrg)
         {
@@ -3199,16 +3201,17 @@ public class OrderController : BaseController
                 expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne, dto.Opinion,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
                 canUpdateOrderSender);
-            //发送短信即将超期
-            _capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
-
+            //TODO发送短信即将超期
+            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+           
         }
         else if (dto.FlowDirection is EFlowDirection.CenterToCenter)
         {
             expiredTimeConfig = _timeLimitDomainService.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToCenter, order.AcceptTypeCode);
             order.CenterToCenter(expiredTimeConfig.TimeText, expiredTimeConfig.Count,
                 expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, expiredTimeConfig.NearlyExpiredTime, expiredTimeConfig.NearlyExpiredTimeOne);
-            _capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+            //TODO发送短信即将超期
+            //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
         }
 
         _mapper.Map(expiredTimeConfig, order);
@@ -6227,6 +6230,7 @@ public class OrderController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("update-order-sourcechannel")]
+    [AllowAnonymous]
     public async Task UpdateOrderSourceChannel([FromBody] UpdateOrderSourceChannelDto dto)
     {
         if (dto == null || dto.Ids == null || dto.Ids.Count == 0)

+ 3 - 0
src/Hotline.Api/Controllers/PushMessageController.cs

@@ -129,6 +129,9 @@ namespace Hotline.Api.Controllers
                 .WhereIF(pagedDto.EndTime.HasValue, d => d.SendTime <= pagedDto.EndTime)
                 .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.SendOrg), d => d.CreatorOrgName.Contains(pagedDto.SendOrg))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.SendContent), d => d.Content.Contains(pagedDto.SendContent))
                 .OrderByDescending(it => it.CreationTime)
                 .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);
 

+ 20 - 4
src/Hotline.Api/Controllers/TestController.cs

@@ -10,6 +10,7 @@ using Hotline.Ai.Visit;
 using Hotline.Application.ExportExcel;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.JudicialManagement;
+using Hotline.Application.Orders;
 using Hotline.Application.Quality;
 using Hotline.Application.StatisticalReport;
 using Hotline.Authentications;
@@ -139,11 +140,12 @@ public class TestController : BaseController
 
     private readonly IRepository<ContingencyManagementHotspot> _contingencyManagementHotspotRepository;
     private readonly IRepository<Hotspot> _hotspotRepository;
-    //private readonly ITypedCache<List<User>> _cache;
-    //private readonly ICacheManager<User> _cache;
+    private readonly IOrderApplication _orderApplication;
+	//private readonly ITypedCache<List<User>> _cache;
+	//private readonly ICacheManager<User> _cache;
 
 
-    public TestController(
+	public TestController(
         INewRockClient client,
         ILogger<TestController> logger,
         IAuthorizeGenerator authorizeGenerator,
@@ -181,6 +183,7 @@ public class TestController : BaseController
         IEnforcementApplication enforcementApplication,
         IWorkflowDomainService workflowDomainService,
         IMapper mapper,
+        IOrderApplication orderApplication,
 
 
    IOptionsSnapshot<SendSmsConfiguration> sendSmsConfiguration,
@@ -234,7 +237,9 @@ IRepository<Hotspot> hotspotRepository
         _enforcementOrdersHandlerRepository = enforcementOrdersHandlerRepository;
         _contingencyManagementHotspotRepository = contingencyManagementHotspotRepository;
         _hotspotRepository = hotspotRepository;
-    }
+        _orderApplication = orderApplication;
+
+	}
 
 
     /// <summary>
@@ -1188,4 +1193,15 @@ IRepository<Hotspot> hotspotRepository
         _logger.LogInformation($"处理完成");
     }
 
+    /// <summary>
+    /// 处理工单流程错误数据   话务部直接归档件  没有归档节点
+    /// </summary>
+    /// <param name="StartTime"></param>
+    /// <param name="EndTime"></param>
+    /// <returns></returns>
+    [HttpGet("order_participle")]
+    [AllowAnonymous]
+    public async Task OrderParticiple() {
+		await _orderApplication.OrderParticiple("7月16日,刘先生看到兴文县县城第二人民医院对面新石海药业有限公司广场店药店套刷医保基金,将顾客不能刷统筹的药品替换为其他可以使用统筹的药品进行刷卡结算。\n    希望部门进行查处。", "1", DateTime.Now, HttpContext.RequestAborted);
+	}
 }

+ 1 - 0
src/Hotline.Api/Hotline.Api.csproj

@@ -11,6 +11,7 @@
   <ItemGroup>
     <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
     <PackageReference Include="Fw.Utility.Client" Version="1.0.0" />
+    <PackageReference Include="JiebaAspNetCore.Segmenter" Version="1.0.1" />
     <PackageReference Include="Mapster.DependencyInjection" Version="1.0.0" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.9" />
     <PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="7.0.14" />

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

@@ -204,7 +204,7 @@ public abstract class DefaultCallApplication : ICallApplication
     public virtual async Task<IReadOnlyList<CallNativeDto>> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
     {
         return await _callNativeRepository.Queryable(includeDeleted: true)
-            .LeftJoin<Order>((d, o) => d.CallNo == o.CallId)
+            .LeftJoin<Order>((d, o) => d.Id == o.CallId)
             .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), (d, o) => o.No == dto.OrderNo)
             .WhereIF(!string.IsNullOrEmpty(dto.FromNo), d => d.FromNo == dto.FromNo)
             .WhereIF(!string.IsNullOrEmpty(dto.ToNo), d => d.ToNo == dto.ToNo)

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

@@ -141,8 +141,8 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 case WorkflowModuleConsts.KnowledgeAdd://新增知识库
                 case WorkflowModuleConsts.KnowledgeUpdate://修改知识库
                 case WorkflowModuleConsts.KnowledgeDelete://删除知识库
-                    var knowledgeWork = await _knowledgeWorkFlowRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
-                    var knowledge = await _knowledgeRepository.Queryable().Where(x => x.Id == knowledgeWork.KnowledgeId).FirstAsync(cancellationToken);
+                    //var knowledgeWork = await _knowledgeWorkFlowRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
+                    var knowledge = await _knowledgeRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                     knowledge.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                     await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                     if (isReviewPass)

+ 2 - 2
src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs

@@ -245,8 +245,8 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                 case WorkflowModuleConsts.KnowledgeAdd:
                 case WorkflowModuleConsts.KnowledgeUpdate:
                 case WorkflowModuleConsts.KnowledgeDelete:
-                    var knowledgeWork = await _knowledgeWorkFlowRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
-                    var knowledge = await _knowledgeRepository.Queryable().Where(x => x.Id == knowledgeWork.KnowledgeId).FirstAsync(cancellationToken);
+                    //var knowledgeWork = await _knowledgeWorkFlowRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
+                    var knowledge = await _knowledgeRepository.Queryable().Where(x => x.Id == workflow.ExternalId).FirstAsync(cancellationToken);
                     knowledge.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                     await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
                     break;

+ 6 - 2
src/Hotline.Application/Handlers/FlowEngine/WorkflowPreviousHandler.cs

@@ -167,12 +167,16 @@ namespace Hotline.Application.Handlers.FlowEngine
                         }
                         break;
                     case WorkflowModuleConsts.OrderScreen:
-                        var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
+	                    var workflowSteps = await _workflowDomainService.GetWorkflowAsync(workflow.Id,withSteps: true,cancellationToken:cancellationToken);
+						var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
                         if (screen != null)
                         {
                             screen.Flowed(workflow.FlowedUserIds, workflow.FlowedOrgIds, workflow.HandlerUsers, workflow.HandlerOrgs);
                             screen.SendBackTime = DateTime.Now;
-                            await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
+                            screen.SendBackApply = workflowSteps.Steps.Any(x=>x is { Status: EWorkflowStepStatus.WaitForHandle or EWorkflowStepStatus.WaitForAccept, StepType: EStepType.Start,IsOrigin : true } );
+                            screen.Status = EScreenStatus.SendBack;
+                            screen.SendBackNum++;
+							await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                         }
                         OrderScreenDetail detail = new OrderScreenDetail
                         {

+ 9 - 4
src/Hotline.Application/Handlers/FlowEngine/WorkflowStartHandler.cs

@@ -6,12 +6,14 @@ using Hotline.CallCenter.Configs;
 using Hotline.CallCenter.Tels;
 using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
+using Hotline.FlowEngine.Workflows;
 using Hotline.KnowledgeBase;
 using Hotline.Orders;
 using Hotline.Push.Notifies;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.KnowledgeBase;
 using Hotline.Share.Enums.Push;
 using Hotline.Share.Enums.Quality;
 using Hotline.Share.Mq;
@@ -43,8 +45,9 @@ namespace Hotline.Application.Handlers.FlowEngine
         private readonly ICallApplication _callApplication;
         private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;
         private readonly IMediator _mediator;
+        private readonly IKnowledgeRepository _knowledgeRepository;
 
-        public WorkflowStartHandler(
+		public WorkflowStartHandler(
             IOrderDomainService orderDomainService,
             IKnowledgeDomainService knowledgeDomainService,
             ITelDomainService telDomainService,
@@ -59,8 +62,9 @@ namespace Hotline.Application.Handlers.FlowEngine
             IRepository<User> userRepository,
             ICallApplication callApplication,
             IOptionsSnapshot<CallCenterConfiguration> callcenterOptions,
-            IMediator mediator
-        )
+            IMediator mediator,
+            IKnowledgeRepository knowledgeRepository
+		)
         {
             _orderDomainService = orderDomainService;
             _knowledgeDomainService = knowledgeDomainService;
@@ -77,7 +81,8 @@ namespace Hotline.Application.Handlers.FlowEngine
             _callApplication = callApplication;
             _callcenterOptions = callcenterOptions;
             _mediator = mediator;
-        }
+            _knowledgeRepository = knowledgeRepository;
+		}
 
         /// <summary>Handles a notification</summary>
         /// <param name="notification">The notification</param>

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

@@ -7,6 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="JiebaAspNetCore.Segmenter" Version="1.0.1" />
     <PackageReference Include="JV.PanGu.Core" Version="1.0.1" />
     <PackageReference Include="NPOI" Version="2.7.0" />
     <PackageReference Include="XC.RSAUtil" Version="1.3.6" />

+ 59 - 51
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -29,7 +29,7 @@ namespace Hotline.Application.Orders
         /// 1.更新工单 2.更新流程
         /// </summary>
         /// <returns></returns>
-        Task DelayOrderExpiredTimeAsync(string orderId, int timeCount, ETimeType timeType,bool IsProDelay, CancellationToken cancellationToken);
+        Task DelayOrderExpiredTimeAsync(string orderId, int timeCount, ETimeType timeType, bool IsProDelay, CancellationToken cancellationToken);
 
         /// <summary>
         /// 新增工单办理流程记录
@@ -42,10 +42,10 @@ namespace Hotline.Application.Orders
         Task CancelOrderAsync(string orderId, string opinion, CancellationToken cancellationToken);
 
         ISugarQueryable<Order> GetToExpireAsync(AboutToExpireListDto dto);
-		//Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken);
-		ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto);
+        //Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken);
+        ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto);
         //Task<PagedDto<WorkflowOrderDto>> GetAboutToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken);
-        Task OrderParticiple(string inputStr, string orderId,DateTime time , CancellationToken cancellationToken);
+        Task OrderParticiple(string inputStr, string orderId, DateTime time, CancellationToken cancellationToken);
         Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken);
         /// <summary>
         /// 接收外部平台工单
@@ -92,12 +92,12 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
         ISugarQueryable<Order> QueryOrderSourceDetail(QueryOrderSourceDetailRequest dto);
 
-		/// <summary>
-		/// 部门超期统计
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		ISugarQueryable<OrderBiOrgDataListVo> QueryOrgDataList(ReportPagedRequest dto);
+        /// <summary>
+        /// 部门超期统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderBiOrgDataListVo> QueryOrgDataList(ReportPagedRequest dto);
 
         /// <summary>
         /// 部门超期统计明细
@@ -106,46 +106,46 @@ namespace Hotline.Application.Orders
         /// <returns></returns>
 		ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListDetailRequest dto);
 
-		/// <summary>
-		/// 部门全量超期统计明细
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListAllDetailRequest dto);
-
-		/// <summary>
-		/// 回退错件统计
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		ISugarQueryable<OrderReTransactVo> OrderReTransact(QueryOrderReTransactRequest dto);
-
-		/// <summary>
-		/// 回退错件明细统计
-        /// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		ISugarQueryable<OrderSpecialDetail> QueryOrderSourceDetail(QueryOrderReTransactDetailRequest dto);
-
-		/// <summary>
-		/// 部门满意度统计
-		/// </summary>
-		/// <returns></returns>
-		Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto);
-
-		/// <summary>
-		/// 子部门满意度
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto);
-
-		/// <summary>
-		/// 部门满意度明细
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		ISugarQueryable<OrderVisitDetail> VisitAndOrgSatisfactionDetail(VisitAndOrgSatisfactionDetailDto dto);
+        /// <summary>
+        /// 部门全量超期统计明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<Order> QueryOrgDataListDetail(OrgDataListAllDetailRequest dto);
+
+        /// <summary>
+        /// 回退错件统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderReTransactVo> OrderReTransact(QueryOrderReTransactRequest dto);
+
+        /// <summary>
+        /// 回退错件明细统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderSpecialDetail> QueryOrderSourceDetail(QueryOrderReTransactDetailRequest dto);
+
+        /// <summary>
+        /// 部门满意度统计
+        /// </summary>
+        /// <returns></returns>
+        Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgSatisfactionStatistics(PagedKeywordSonRequest dto);
+
+        /// <summary>
+        /// 子部门满意度
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<List<VisitAndOrgSatisfactionStatisticsDto>> VisitAndOrgStatisfactionOrgDetail(PagedKeywordSonRequest dto);
+
+        /// <summary>
+        /// 部门满意度明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderVisitDetail> VisitAndOrgSatisfactionDetail(VisitAndOrgSatisfactionDetailDto dto);
 
         /// <summary>
         /// 热点-区域统计
@@ -185,5 +185,13 @@ namespace Hotline.Application.Orders
         /// <param name="dto"></param>
         /// <returns></returns>
         ISugarQueryable<OrderVisitDetail> VisitAndHotspotSatisfactionDetail(VisitAndHotspotPagedKeywordRequest dto);
-	}
+
+        /// <summary>
+        /// 话务员办件统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<OrderBiCentreDataListVo> CentreDataList(ReportPagedRequest dto);
+
+    }
 }

+ 80 - 11
src/Hotline.Application/Orders/OrderApplication.cs

@@ -44,6 +44,9 @@ using Hotline.Share.Enums.FlowEngine;
 using Hotline.Authentications;
 using MediatR;
 using Hotline.Share.Mq;
+using JiebaNet.Segmenter;
+using Microsoft.AspNetCore.Http;
+using WordInfo = PanGu.WordInfo;
 
 namespace Hotline.Application.Orders;
 
@@ -131,8 +134,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         order.TimeLimitUnit = expiredTimeConfig.TimeType;
         order.ExpiredTime = expiredTimeConfig.ExpiredTime;
         order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
-        //发送即将超期(延时发送)
-        _capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms,new PublishNearlyExpiredTimeSmsDto() { OrderId= order.Id }) ;
+        //TODO发送短信即将超期
+        //_capPublisher.PublishDelay(expiredTimeConfig.NearlyExpiredTime - DateTime.Now, EventNames.HotlineOrderNearlyExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
         if (IsProDelay)
         {
             order.ExpiredTimeProvince = expiredTimeConfig.ExpiredTime;
@@ -334,6 +337,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             if (vector != null && vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, words, cancellationToken);
             else await _repositoryts.AddVectorAsync(orderId, time, words, cancellationToken);
         }
+        // 结巴分词
+        //var segmenter = new JiebaSegmenter();
+        //var segments1 = segmenter.Cut(inputStr, cutAll: true);
+        //var b = segments1;
+
+
         //var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("普通标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
         //var res = new List<string>();
         //if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
@@ -500,7 +509,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType)//受理类型
-                                                                                                //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
+                                                                                                    //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel)
             //.WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
             //.WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
@@ -820,8 +829,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
             .WhereIF(string.IsNullOrEmpty(dto.OrgName) == false, x => x.VisitOrgName.Contains(dto.OrgName))
             .WhereIF(string.IsNullOrEmpty(dto.LineNum) == false, x => x.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
-            .WhereIF(dto.TypeId != null && dto.TypeId == 1, x => x.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
-            .WhereIF(dto.TypeId != null && dto.TypeId == 2, x => x.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, x => x.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, x => x.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
             .WhereIF(IsCenter == false, x => x.VisitOrgCode.StartsWith(_sessionContext.OrgId));
 
         var data = new List<VisitAndOrgSatisfactionStatisticsDto>();
@@ -917,8 +926,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.OrgCode == "001", (x, it) => it.VisitOrgCode == dto.OrgCode)
             .WhereIF(dto.OrgCode != "001", (x, it) => it.VisitOrgCode.StartsWith(dto.OrgCode))
             .WhereIF(!string.IsNullOrEmpty(dto.LineNum), (x, it) => it.OrderVisit.Order.CallRecord.Gateway.Contains(dto.LineNum))
-            .WhereIF(dto.TypeId != null && dto.TypeId == 1, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
-            .WhereIF(dto.TypeId != null && dto.TypeId == 2, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, (x, it) => it.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
             .WhereIF(IsCenter == false, (x, it) => it.VisitOrgCode.StartsWith(_sessionContext.OrgId))
              .GroupBy((x, it) => new
              {
@@ -969,8 +978,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Includes(x => x.OrderVisit, o => o.Order, d => d.CallRecord)
             .Where(x => x.OrderVisit.VisitTime >= dto.StartTime && x.OrderVisit.VisitTime <= dto.EndTime && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited)
             .WhereIF(dto.OrgCode == "001", x => x.VisitOrgCode == dto.OrgCode)
-            .WhereIF(dto.TypeId != null && dto.TypeId == 1, x=> x.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
-            .WhereIF(dto.TypeId != null && dto.TypeId == 2, x => x.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 1, x => x.OrderVisit.Order.IdentityType == EIdentityType.Citizen)
+            .WhereIF(dto.TypeCode != null && dto.TypeCode == 2, x => x.OrderVisit.Order.IdentityType == EIdentityType.Enterprise)
             //.WhereIF(dto.OrgCode != "001", x => x.VisitOrgCode == dto.OrgCode).
             .WhereIF(dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
             .WhereIF(IsCenter == true && dto.IsOnlyMy == true, x => x.VisitOrgCode == dto.OrgCode)
@@ -1288,8 +1297,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Where(x => x.OrderVisit.VisitTime >= dto.StartTime.Value && x.OrderVisit.VisitTime <= dto.EndTime.Value && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
             .WhereIF(string.IsNullOrEmpty(dto.HotspotName) == false, (x, h) => h.HotSpotName == dto.HotspotName)
             .WhereIF(IsCenter == false, x => x.VisitOrgCode.StartsWith(_sessionContext.OrgId))
-            .WhereIF(dto.TypeId == 1 ,x=>x.OrgProcessingResults != null)
-			.WhereIF(dto.TypeId == 2, x => x.OrgHandledAttitude != null);
+            .WhereIF(dto.TypeId == 1, x => x.OrgProcessingResults != null)
+            .WhereIF(dto.TypeId == 2, x => x.OrgHandledAttitude != null);
 
         var data = new List<VisitAndHotspotSatisfactionStatisticsDto>();
 
@@ -1385,6 +1394,66 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.TypeId is 1, x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == key)
             .WhereIF(dto.TypeId is 2, x => SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == key);
     }
+
+    /// <summary>
+    /// 话务员办件统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    public ISugarQueryable<OrderBiCentreDataListVo> CentreDataList(ReportPagedRequest dto)
+    {
+        if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
+
+        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
+        var query = _orderRepository.Queryable(false, false, false)
+            .WhereIF(dto.StartTime.HasValue, it => it.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, it => it.CreationTime <= dto.EndTime)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), it => it.SignerName.Contains(dto.Keyword!))
+            .GroupBy(it => new { it.SignerId, it.SignerName })
+            .Select(it => new OrderBiCentreDataListVo
+            {
+                UserName = it.SignerName,
+                UserId = it.SignerId,
+                //Subtotal = SqlFunc.AggregateCount(x.AcceptorId),
+                CentreArchive = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Zhiban && it.AcceptType != "无效", 1, 0)), //中心归档件
+                                                                                                                                                                            //CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && (it.FileUserRole == EFileUserType.Org || it.FileUserRole == EFileUserType.Dispatch), 1, 0)), //转办信件
+                CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType != "无效" && (it.ProcessType == EProcessType.Jiaoban || (it.ActualHandleStepName == "派单组" && it.Status < EOrderStatus.Filed) || (it.ActualHandleStepName == "班长审批" && it.Status < EOrderStatus.Filed)), 1, 0)),
+                NoCentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType != "无效" && (it.Status <= EOrderStatus.SpecialToUnAccept), 1, 0)), //坐席待办 //中心领导?市领导? 是否在统计条件中
+                                                                                                                                                  //CentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Jiaoban, 1, 0)),
+                                                                                                                                                  //NoCentreCareOf = SqlFunc.AggregateSum(SqlFunc.IIF((int)x.Status < 300 && x.ExpiredTime > x.FiledTime, 1, 0)),
+                Invalid = SqlFunc.AggregateSum(SqlFunc.IIF(it.AcceptType == "无效", 1, 0)),
+                Repeat = SqlFunc.AggregateSum(SqlFunc.IIF(it.DuplicateIds != null && SqlFunc.JsonArrayLength(it.DuplicateIds) > 0, 1, 0)),
+                Subtotal = SqlFunc.AggregateSum(SqlFunc.IIF((it.Status >= EOrderStatus.Filed && it.ProcessType == EProcessType.Zhiban && it.AcceptType != "无效") || (it.AcceptType != "无效" && (it.ProcessType == EProcessType.Jiaoban || (it.ActualHandleStepName == "派单组" && it.Status < EOrderStatus.Filed) || (it.ActualHandleStepName == "班长审批" && it.Status < EOrderStatus.Filed))) || (it.Status <= EOrderStatus.SpecialToUnAccept) || it.AcceptType == "无效" || (it.DuplicateIds != null && SqlFunc.JsonArrayLength(it.DuplicateIds) > 0), 1, 0))
+            }).MergeTable();
+        switch (dto.SortField)
+        {
+            case "centreArchive":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreArchive) : query.OrderByDescending(x => x.CentreArchive);
+                break;
+            case "centreCareOf":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.CentreCareOf) : query.OrderByDescending(x => x.CentreCareOf);
+                break;
+            case "noCentreCareOf":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.NoCentreCareOf) : query.OrderByDescending(x => x.NoCentreCareOf);
+                break;
+            case "invalid":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.Invalid) : query.OrderByDescending(x => x.Invalid);
+                break;
+            case "repeat":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.Repeat) : query.OrderByDescending(x => x.Repeat);
+                break;
+            case "subtotal":
+                query = dto.SortRule is 0 ? query.OrderBy(x => x.Subtotal) : query.OrderByDescending(x => x.Subtotal);
+                break;
+        }
+
+        if (string.IsNullOrEmpty(dto.SortField))
+        {
+            query = query.OrderByDescending(x => x.Subtotal);
+        }
+        return query;
+    }
     #region private
 
     /// <summary>

+ 3 - 5
src/Hotline.Application/StatisticalReport/CallReportApplication.cs

@@ -31,9 +31,6 @@ namespace Hotline.Application.StatisticalReport
         /// <returns></returns>
         public async Task<List<QueryCallsDetailDto>> QueryCallsDetailAsync(BiQueryCallsDto dto)
         {
-            if (!dto.StartTime.HasValue || !dto.EndTime.HasValue)
-                throw UserFriendlyException.SameMessage("请选择时间!");
-            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
             //超时接通量
             int CallInOverConnRingTime = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOverConnRingTime)?.SettingValue[0]);
             //坐席超时挂断时间
@@ -48,7 +45,7 @@ namespace Hotline.Application.StatisticalReport
 
             var callData = await _trCallRecordRepository.Queryable()
                     .Where(p => p.CreatedTime >= dto.StartTime && p.CreatedTime <= dto.EndTime)
-                    .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
+                   // .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
                      .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.Gateway == dto.Keyword)
                      .GroupBy(p => p.CreatedTime.ToString("yyyy-MM-dd"))
                     .Select(p => new QueryCallsDetailDto
@@ -67,6 +64,7 @@ namespace Hotline.Application.StatisticalReport
                         OutTotal = SqlFunc.AggregateSum(SqlFunc.IIF(p.CallDirection == ECallDirection.Out, 1, 0)),//呼出总量
                         OutConnectionQuantity = SqlFunc.AggregateSum(SqlFunc.IIF(p.OnState == EOnState.On && p.CallDirection == ECallDirection.Out && p.AnsweredTime != null, 1, 0))
                     })
+                    .OrderBy(p => p.Date)
                     .ToListAsync();
 
             return callData;
@@ -87,7 +85,7 @@ namespace Hotline.Application.StatisticalReport
                      .Includes(p => p.Order)
                     .Where(p => p.CreatedTime >= dto.StartTime && p.CreatedTime <= dto.EndTime && p.CallDirection == ECallDirection.In)
                     .WhereIF(dto.TypeCode == "2", p => p.OnState == EOnState.On && p.AnsweredTime != null)
-                    .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
+                   // .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
                      .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.Gateway == dto.Keyword)
                      .OrderByDescending(p => p.CreatedTime)
                     .MergeTable();

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

@@ -90,8 +90,8 @@ namespace Hotline.Application.Subscribers
                         }
                     }
                 }
-                //发送超期短信(延时发送)
-                _capPublisher.PublishDelay(order.ExpiredTime.Value- DateTime.Now, EventNames.HotlineOrderExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
+                //TODO发送短信超期
+                //_capPublisher.PublishDelay(order.ExpiredTime.Value- DateTime.Now, EventNames.HotlineOrderExpiredTimeSms, new PublishNearlyExpiredTimeSmsDto() { OrderId = order.Id });
             }
         }
 

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

@@ -79,7 +79,7 @@ namespace Hotline.Repository.SqlSugar.CallCenter
 
             var list = Db.Queryable<TrCallRecord>()
                   .Where(p => p.CreatedTime >= beginDate && p.CreatedTime <= endDate)
-                  .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
+                 // .Where(p => p.Gateway != "82826886" && SqlFunc.Length(p.Gateway) != 4)
                   .WhereIF(!string.IsNullOrEmpty(Line), p => p.Gateway == Line)
                    .GroupBy(p => p.CreatedTime.Hour)
                    .Select(p => new

+ 1 - 1
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs

@@ -217,7 +217,7 @@ namespace Hotline.Repository.SqlSugar.Extensions
             {
                 //获取原生SQL推荐 5.1.4.63  性能OK
                 Log.Error(UtilMethods.GetNativeSql(exp.Sql, (SugarParameter[])exp.Parametres));
-                Log.Error(exp.InnerException.Message);
+                //Log.Error(exp.InnerException.Message);
                 //5.0.8.2 获取无参数化 SQL  对性能有影响,特别大的SQL参数多的,调试使用
                 //UtilMethods.GetSqlString(DbType.SqlServer, exp.sql, exp.parameters)
             };

+ 1 - 1
src/Hotline.Share/Dtos/CallCenter/QueryCallsDetailDto.cs

@@ -108,7 +108,7 @@
             if (Count <= 0 || Quantity <= 0)
                 return 0;
 
-            return Math.Round((Count / (double)Quantity) * 100, 3);
+            return Math.Round((Count / (double)Quantity), 3);
         }
 
         /// <summary>

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

@@ -624,18 +624,22 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? VolveConent { get; set; }
 
-        public string ScreenSendBackText => GetScreenSendBack();
+        /// <summary>
+        /// 是否退回
+        /// </summary>
+        public string ScreenSendBackText => GetScreenSendBack() ? "是" : "否";
 
-        public string GetScreenSendBack() {
+        public bool GetScreenSendBack() {
             if (OrderScreens != null && OrderScreens.Any())
             {
                 if (OrderScreens.First().Status == EScreenStatus.SendBack && OrderScreens.First().SendBackApply)
                 {
-                    return "是";
+                    return true;
                 }
             }
-            return "否";
+            return false;
         }
+        public bool ScreenSendBack => GetScreenSendBack();
 
 	}
 

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

@@ -31,11 +31,26 @@ namespace Hotline.Share.Dtos.Push
         /// <summary>
         /// 电话号码
         /// </summary>
-        public string TelNumber { get; set; }
+        public string? TelNumber { get; set; }
 
         /// <summary>
         /// 接收人
         /// </summary>
-        public string UserName { get; set; }
+        public string? UserName { get; set; }
+
+        /// <summary>
+        /// 发送人
+        /// </summary>
+        public string? SendName { get; set; }
+
+        /// <summary>
+        /// 发送部门
+        /// </summary>
+        public string? SendOrg { get; set;}
+
+        /// <summary>
+        /// 发送内容
+        /// </summary>
+        public string? SendContent { get; set;}
     }
 }

+ 1 - 1
src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs

@@ -972,7 +972,7 @@ namespace Hotline.Share.Dtos.TrCallCenter
 		/// <summary>
 		/// 主叫
 		/// </summary>
-		public string? Id { get; set; }
+		public List<string> Ids { get; set; }
 	}
 	#endregion
 

+ 5 - 0
src/Hotline.Share/Enums/CallCenter/ECallTransliterationState.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -11,21 +12,25 @@ namespace Hotline.Share.Enums.CallCenter
 		/// <summary>
 		/// 未开始
 		/// </summary>
+		[Description("未开始")]
 		NoBegin = 0,
 
 		/// <summary>
 		/// 进行中	
 		/// </summary>
+		[Description("进行中")]
 		Underway = 1,
 
 		/// <summary>
 		/// 转写成功
 		/// </summary>
+		[Description("转写成功")]
 		Succeed = 2,
 
 		/// <summary>
 		/// 转写失败
 		/// </summary>
+		[Description("转写失败")]
 		Fail = 3,
 	}
 }

+ 7 - 3
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -659,7 +659,7 @@ namespace Hotline.FlowEngine.Workflows
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
             await _publisher.PublishAsync(new PreviousNotify(workflow, newPrevStep, dto, isOrgToCenter),
-                PublishStrategy.ParallelNoWait, cancellationToken);
+                PublishStrategy.ParallelWhenAll, cancellationToken);
 
             return GetFlowDirection(currentStep.BusinessType, prevStep.BusinessType);
         }
@@ -1051,7 +1051,7 @@ namespace Hotline.FlowEngine.Workflows
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
             await _publisher.PublishAsync(new RecallNotify(workflow, targetStep, dto, isOrgToCenter),
-                PublishStrategy.ParallelNoWait, cancellationToken);
+                PublishStrategy.ParallelWhenAll, cancellationToken);
         }
 
         /// <summary>
@@ -1122,7 +1122,7 @@ namespace Hotline.FlowEngine.Workflows
             var dto = _mapper.Map<RecallDto>(targetStep);
             dto.WorkflowId = workflow.Id;
             await _publisher.PublishAsync(new RecallNotify(workflow, targetStep, dto, isOrgToCenter),
-                PublishStrategy.ParallelNoWait, cancellationToken);
+                PublishStrategy.ParallelWhenAll, cancellationToken);
         }
 
         ///// <summary>
@@ -2720,6 +2720,10 @@ namespace Hotline.FlowEngine.Workflows
             step.IsOrigin = isOrigin;
             step.Name = stepName;
 
+            //新增需求: 部门汇总节点由部门办理//todo 待确认中心由部门处理还是由之前办理人办理
+            if (step.StepType == EStepType.Summary && step.BusinessType == EBusinessType.Department)
+                step.FlowAssignType = EFlowAssignType.Org;
+
             step.Assign(handler.UserId, handler.Username,
                 handler.OrgId, handler.OrgName,
                 handler.RoleId, handler.RoleName);

+ 5 - 5
src/Hotline/KnowledgeBase/Knowledge.cs

@@ -35,7 +35,7 @@ public class Knowledge : WorkflowEntity//   WorkflowEntity  FullStateEntity
 	/// 知识编号
 	/// </summary>
 	[SugarColumn(ColumnDescription = "知识编号")]
-	public string Code { get; set; }
+	public string? Code { get; set; }
 
 	/// <summary>
 	/// 标题
@@ -65,7 +65,7 @@ public class Knowledge : WorkflowEntity//   WorkflowEntity  FullStateEntity
 	/// 是否公开
 	/// </summary>
 	[SugarColumn(ColumnDescription = "是否公开")]
-	public bool IsPublic { get; set; }
+	public bool? IsPublic { get; set; }
 
 	/// <summary>
 	/// 文档状态
@@ -95,13 +95,13 @@ public class Knowledge : WorkflowEntity//   WorkflowEntity  FullStateEntity
     /// 关键词
     /// </summary>
     [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true, ColumnDescription = "关键词")]
-    public List<string> Keywords { get; set; }
+    public List<string>? Keywords { get; set; }
 
 	/// <summary>
 	/// 版本号
 	/// </summary>
 	[SugarColumn(ColumnDescription = "版本号")]
-	public int Version { get; set; } = 0;
+	public int? Version { get; set; } = 0;
 
     /// <summary>
     /// 外部数据(为前端提供级联功能)
@@ -113,7 +113,7 @@ public class Knowledge : WorkflowEntity//   WorkflowEntity  FullStateEntity
     /// 附件
     /// </summary>
     [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
-    public List<string> Additions { get; set; }
+    public List<string>? Additions { get; set; }
 
     /// <summary>
     /// 关联知识

+ 31 - 28
src/Hotline/KnowledgeBase/KnowledgeDomainService.cs

@@ -106,21 +106,21 @@ namespace Hotline.KnowledgeBase
             if (string.IsNullOrEmpty(workflowExternalId))
                 throw UserFriendlyException.SameMessage("无效知识编号");
             var knowledgeFlow =
-                await _knowledgeWorkFlowRepository.GetAsync(workflowExternalId, cancellationToken);
+                await _knowledgeWorkFlowRepository.Queryable().Where(x => x.KnowledgeId == workflowExternalId).FirstAsync(cancellationToken);
             if (knowledgeFlow == null)
                 throw new UserFriendlyException($"无效知识编号, knowledgeFlowId: {workflowExternalId}", "无效知识编号");
             knowledgeFlow.WorkflowId = workflowId;
             knowledgeFlow.Flowed(flowedUserIds, flowedOrgIds, handlerUsers, handlerOrgs);
             await _knowledgeWorkFlowRepository.UpdateAsync(knowledgeFlow, cancellationToken);
-            var knowledge = await _knowledgeRepository.GetAsync(knowledgeFlow.KnowledgeId, cancellationToken);
+            var knowledge = await _knowledgeRepository.Queryable().Where(x=>x.Id == workflowExternalId).FirstAsync(cancellationToken);
             if (knowledge == null)
-                throw new UserFriendlyException($"无效知识编号, knowledgeId: {knowledgeFlow.KnowledgeId}", "无效知识编号");
+                throw new UserFriendlyException($"无效知识编号, knowledgeId: {workflowExternalId}", "无效知识编号");
             knowledge.WorkflowId = workflowId;
             knowledge.Status = EKnowledgeStatus.Auditing;
             knowledge.Flowed(flowedUserIds, flowedOrgIds, handlerUsers, handlerOrgs);
             await _knowledgeRepository.UpdateAsync(knowledge, cancellationToken);
         }
-        
+
         /// <summary>
         /// 修改指派人
         /// </summary>
@@ -203,20 +203,21 @@ namespace Hotline.KnowledgeBase
         /// <exception cref="UserFriendlyException"></exception>
         public async Task TerminateWorkKnowledge(Workflow workflow, CancellationToken cancellationToken)
         {
-            //修改主表审批状态  根据流程ID查询审批主表
-            var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.WorkflowId == workflow.Id, cancellationToken);
-            if (workFlow == null)
-                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.Id}", "无效流程编号");
+	        //根据审批主表知识ID查询当前知识
+	        var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workflow.ExternalId, cancellationToken);
+	        if (knowledge == null)
+		        throw new UserFriendlyException($"知识查询失败");
 
-            //根据审批主表知识ID查询当前知识
-            var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workFlow.KnowledgeId, cancellationToken);
-            if (knowledge == null)
-                throw new UserFriendlyException($"知识查询失败");
+	        //修改主表审批状态  根据流程ID查询审批主表
+	        var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.KnowledgeId == workflow.ExternalId, cancellationToken);
+	        if (workFlow == null)
+		        throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.ExternalId}", "无效流程编号");
+
+			//修改业务数据状态
+			workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Revoke;
+	        workFlow.ActualOpinion = workflow.ActualOpinion;
+	        await _knowledgeWorkFlowRepository.UpdateAsync(workFlow, cancellationToken);
 
-            //修改业务数据状态
-            workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Revoke;
-            workFlow.ActualOpinion = workflow.ActualOpinion;
-            await _knowledgeWorkFlowRepository.UpdateAsync(workFlow);
 
             //现有知识状态更改为已撤回
             knowledge.Status = EKnowledgeStatus.Revert;
@@ -248,28 +249,30 @@ namespace Hotline.KnowledgeBase
         /// <exception cref="UserFriendlyException"></exception>
         public async Task EndWorkKnowledge(Workflow workflow, CancellationToken cancellationToken)
         {
-            //修改主表审批状态  根据流程ID查询审批主表
-            var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.WorkflowId == workflow.Id, cancellationToken);
-            if (workFlow == null)
-                throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.Id}", "无效流程编号");
 
-            //根据审批主表知识ID查询当前知识
-            //  var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workFlow.KnowledgeId, cancellationToken);
+	        //修改主表审批状态  根据流程ID查询审批主表
+	        var workFlow = await _knowledgeWorkFlowRepository.GetAsync(p => p.KnowledgeId == workflow.ExternalId, cancellationToken);
+	        if (workFlow == null)
+		        throw new UserFriendlyException($"知识查询失败, workflowId: {workflow.ExternalId}", "无效流程编号");
+
+	        //根据审批主表知识ID查询当前知识
+	        //  var knowledge = await _knowledgeRepository.GetAsync(p => p.Id == workFlow.KnowledgeId, cancellationToken);
+
+	        workFlow.HandleTime = DateTime.Now;
+	        workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Success;
+	        workFlow.ActualOpinion = workflow.ActualOpinion;
+	        await _knowledgeWorkFlowRepository.UpdateAsync(workFlow, cancellationToken);
 
-            var knowledge = await _knowledgeRepository.Queryable(false, false, false)
+			var knowledge = await _knowledgeRepository.Queryable(false, false, false)
                 .Includes(it => it.SystemOrganize)
                 .Includes(it => it.HotspotType)
                 .Includes(it => it.User)
-                .Where(p => p.Id == workFlow.KnowledgeId)
+                .Where(p => p.Id == workflow.ExternalId)
                 .FirstAsync();
 
             if (knowledge == null)
                 throw new UserFriendlyException($"知识查询失败");
 
-            workFlow.HandleTime = DateTime.Now;
-            workFlow.WorkFlowApplyStatus = EKnowledgeWorkFlowStatus.Success;
-            workFlow.ActualOpinion = workflow.ActualOpinion;
-			await _knowledgeWorkFlowRepository.UpdateAsync(workFlow, cancellationToken);
 
             string isSendType = "";//推送类别:新增0,修改1,删除2
 

+ 20 - 15
src/Hotline/Orders/OrderDomainService.cs

@@ -290,25 +290,30 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                 cancellationToken);
             if (steps.Any())
             {
-                List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)> handlers = new();
-                var avg = steps.Count / schedulings.Count;
+	            List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)> handlers = new();
+				var avg = steps.Count / schedulings.Count;
                 var remaining = steps.Count % schedulings.Count;
+                var skip = 0;
                 for (var i = 0; i < schedulings.Count; i++)
                 {
-                    var scheduling = schedulings[i];
+					var scheduling = schedulings[i];
                     var size = avg + (i < remaining ? 1 : 0);
-                    handlers.Add(new(
-                        scheduling.SchedulingUser.UserId,
-                        scheduling.SchedulingUser.UserName,
-                        scheduling.SchedulingUser.OrgId,
-                        scheduling.SchedulingUser.OrgIdName,
-                        null, null,
-                        steps.Take(size).ToList()));
-                    scheduling.SendOrderNum += size;
-                    await _schedulingRepository.Updateable()
-                        .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum })
-                        .Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
-                }
+                    if (size > 0)
+                    {
+						handlers.Add(new(
+							scheduling.SchedulingUser.UserId,
+							scheduling.SchedulingUser.UserName,
+							scheduling.SchedulingUser.OrgId,
+							scheduling.SchedulingUser.OrgIdName,
+							null, null,
+							steps.Skip(skip).Take(size).ToList()));
+                        skip += size;
+						scheduling.SendOrderNum += size;
+						await _schedulingRepository.Updateable()
+							.SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum })
+							.Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
+					}
+				}
                 if (handlers.Any())
                     await _workflowDomainService.ChangeHandlerBatchAsync(handlers, cancellationToken);
             }

+ 62 - 0
src/Hotline/dataview.md

@@ -244,3 +244,65 @@ left join order_visit bb on aa."OrderVisitId"=bb."Id"
 left join "order" cc on bb."OrderId"=cc."Id"
 --left join order_visit_detail dd on bb."Id"=dd."VisitId"
 where aa."CreationTime" >'2024-07-01' --and dd."VisitTarget"=20
+
+
+### 话务量统计
+SELECT  to_char("CreatedTime",'yyyy-MM-dd') AS "日期" , SUM(( CASE  WHEN ( "CallDirection" = 0 ) THEN 1  ELSE 0 END )) AS "呼入总量" ,
+SUM(( CASE  WHEN ((( "OnState" = 1 ) AND ( "CallDirection" = 0 )) AND ( "AnsweredTime" IS NOT NULL )) THEN 1  ELSE 0 END )) AS "接通总量" , 
+SUM(( CASE  WHEN ((( "Duration" = 0 ) AND ( "RingTimes" <= 5 )) AND ( "RingTimes" > 0 )) THEN 1  ELSE 0 END )) AS "未接通秒挂断" , 
+SUM(( CASE  WHEN ((( "CallDirection" = 0 ) AND ( "AnsweredTime" IS NOT NULL )) AND ( "OnState" = 1 )) THEN "Duration"  ELSE 0 END )) AS "呼入总时长" ,
+SUM(( CASE  WHEN ((( "CallDirection" = 0 ) AND ( "AnsweredTime" IS NOT NULL )) AND ( "Duration" >= 15 )) THEN 1  ELSE 0 END )) AS "有效接通量" ,
+SUM(( CASE  WHEN ((( "CallDirection" = 0 ) AND ( "Duration" > 0 )) AND ( "Duration" <= 5 )) THEN 1  ELSE 0 END )) AS "呼入接通秒挂" ,
+SUM(( CASE  WHEN (((( "OnState" = 1 ) AND ( "CallDirection" = 0 )) AND ( "AnsweredTime" IS NOT NULL )) AND ( "RingTimes" >= 15 )) THEN 1  ELSE 0 END )) AS "超时接通" , 
+SUM(( CASE  WHEN (((( "OnState" = 1 ) AND ( "CallDirection" = 0 )) AND ( "AnsweredTime" IS NOT NULL )) AND ( "Duration" >= 480 )) THEN 1  ELSE 0 END )) AS "超时挂断" ,
+SUM(( CASE  WHEN (((( "CallDirection" = 0 ) AND ( "QueueTims" > 0 )) AND ( "RingTimes" = 0 )) AND ( "OnState" = 2 )) THEN 1  ELSE 0 END )) AS "队列挂断" , 
+SUM(( CASE  WHEN ((((( "CallDirection" = 0 ) AND ( "BeginIvrTime" IS NOT NULL )) AND NOT( "BeginQueueTime" IS NOT NULL )) AND NOT( "BeginRingTime" IS NOT NULL )) AND ( "OnState" = 2 )) THEN 1  ELSE 0 END )) AS "IVR挂断" ,
+SUM(( CASE  WHEN ( "CallDirection" = 1 ) THEN 1  ELSE 0 END )) AS "呼出总量" , 
+SUM(( CASE  WHEN ((( "OnState" = 1 ) AND ( "CallDirection" = 1 )) AND ( "AnsweredTime" IS NOT NULL )) THEN 1  ELSE 0 END )) AS "呼出接通量"  
+FROM "tr_call_record"  WHERE (( "CreatedTime" >= '2024-07-01' ) AND ( "CreatedTime" <= '2024-08-01' ))  AND (( "Gateway" <> '82826886' ) AND (LENGTH("Gateway") <> 4 ))GROUP BY to_char("CreatedTime",'yyyy-MM-dd')
+order by "日期"
+
+
+
+### 回访不满意明细
+select 
+ordertemp."No",
+ordertemp."SourceChannel",
+ ordertemp."ReTransactNum",
+ (select CASE "screentemp"."Status"
+	WHEN 0 THEN '待办'
+	WHEN 1 THEN '审批中'
+	WHEN 2 THEN '审批完成'
+	WHEN 3 THEN '审批拒绝'
+	ELSE '未甄别'
+END AS "OrderScreenStatus"
+ from order_screen screentemp WHERE "OrderId"="ordertemp"."Id" order by "CreationTime" DESC LIMIT 1) as "OrderScreenStatus", 
+ ordervisitdetailtemp."VisitContent" as VisitContent,
+  to_char(ordertemp."CreationTime" , 'YYYY-MM-DD HH24:MI:SS')as "StartTime",
+ ordertemp."Title" as "Title",
+ (select "Name" from "user" usertemp WHERE usertemp."Id" = ordervisittemp."EmployeeId" limit 1) as "EmployeeId",
+ ordervisitdetailtemp."VisitOrgName" as "VisitOrgName",
+ to_char(ordertemp."FiledTime", 'YYYY-MM-DD HH24:MI:SS')  as "FiledTime",
+ CASE ordervisittemp."VisitType"
+	WHEN 10 THEN '人工回访'
+	WHEN 20 THEN '智能语音回访'
+	WHEN 30 THEN '短信回访'
+	WHEN 40 THEN '网站回访'
+	WHEN 50 THEN 'App回访'
+	WHEN 60 THEN '微信回访'
+	WHEN 70 THEN '电话回访'
+	ELSE
+		'其他'
+END as "VisitType",
+ordertemp."HotspotSpliceName" as "HotspotSpliceName",
+to_char(ordervisittemp."VisitTime", 'YYYY-MM-DD HH24:MI:SS') as "VisitTime",
+ordervisitdetailtemp."OrgProcessingResults"::JSON->>'Value' as "OrgProcessingResults",
+ordertemp."Content",
+"ActualOpinion" AS "ActualOpinion" ,
+"FileOpinion" AS "FileOpinion" ,
+"OrgLevelOneName" AS "OrgLevelOneName" , 
+"ActualHandleOrgName" AS "ActualHandleOrgName" 
+ from order_visit_detail ordervisitdetailtemp 
+left join order_visit ordervisittemp on ordervisitdetailtemp."VisitId"=ordervisittemp."Id"
+left join "order" ordertemp on ordervisittemp."OrderId" = ordertemp."Id"
+WHERE ordervisitdetailtemp."VisitTarget" = 20 and ordervisittemp."VisitTime">='2024-07-01' and ordervisittemp."VisitTime"<'2024-08-01' and (ordervisitdetailtemp."OrgProcessingResults"->>'Key')::INT=2 and ordervisittemp."VisitState"=30