Pārlūkot izejas kodu

Merge branch 'test' into test_Guardian

田爽 1 mēnesi atpakaļ
vecāks
revīzija
60dd9a344e
43 mainītis faili ar 1251 papildinājumiem un 341 dzēšanām
  1. 8 3
      src/Hotline.Api/Controllers/ArticleController.cs
  2. 122 16
      src/Hotline.Api/Controllers/FwThirdController.cs
  3. 31 27
      src/Hotline.Api/Controllers/OrderController.cs
  4. 14 28
      src/Hotline.Api/Controllers/PbxController.cs
  5. 210 0
      src/Hotline.Api/Controllers/TelRestController.cs
  6. BIN
      src/Hotline.Api/Documents/luzhou/泸州12345平台工单查询接口(V1.0-20250312) .docx
  7. 0 0
      src/Hotline.Api/Documents/zigong/丰窝12345平台工单接入接口(V1.1-20250225) .docx
  8. 8 8
      src/Hotline.Api/StartupHelper.cs
  9. 1 1
      src/Hotline.Api/config/appsettings.Development.json
  10. 17 3
      src/Hotline.Application/CallCenter/DefaultCallApplication.cs
  11. 15 0
      src/Hotline.Application/CallCenter/IPbxApplication.cs
  12. 61 0
      src/Hotline.Application/CallCenter/PbxApplication.cs
  13. 21 0
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  14. 39 17
      src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs
  15. 5 0
      src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs
  16. 2 1
      src/Hotline.Application/Orders/Handlers/OrderScreenHandler/OrderScreenEndWorkflowHandler.cs
  17. 1 0
      src/Hotline.Application/Orders/Handlers/OrderScreenHandler/OrderScreenNextWorkflowHandler.cs
  18. 76 20
      src/Hotline.Application/Orders/OrderApplication.cs
  19. 3 4
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  20. 1 1
      src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs
  21. 0 72
      src/Hotline.Application/Subscribers/CallSubscriber.cs
  22. 174 100
      src/Hotline.Application/Subscribers/InternalCapSubscriber.cs
  23. 1 1
      src/Hotline.Share/Dtos/CallCenter/CallNativeDto.cs
  24. 10 0
      src/Hotline.Share/Dtos/CallCenter/QueryCallsFixedDto.cs
  25. 140 0
      src/Hotline.Share/Dtos/CallCenter/TelRestApplyAddDto.cs
  26. 2 0
      src/Hotline.Share/Dtos/Order/OrderWordDto.cs
  27. 4 0
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  28. 13 0
      src/Hotline.Share/Dtos/WebPortal/ArticleDetailsDto.cs
  29. 98 0
      src/Hotline.Share/Dtos/WebPortal/GetOrderCodePwd.cs
  30. 28 0
      src/Hotline.Share/Enums/CallCenter/ETelRestAuditStatus.cs
  31. 3 0
      src/Hotline.Share/Enums/Push/EPushBusiness.cs
  32. 10 5
      src/Hotline.Share/Mq/EventNames.Order.cs
  33. 2 0
      src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs
  34. 4 2
      src/Hotline/Caching/Services/SystemSettingCacheManager.cs
  35. 49 6
      src/Hotline/CallCenter/Tels/TelRestApply.cs
  36. 12 10
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  37. 12 2
      src/Hotline/Orders/OrderVisitDomainService.cs
  38. 5 0
      src/Hotline/Settings/SettingConstants.cs
  39. 5 5
      src/Hotline/Snapshot/ThirdAccount.cs
  40. 29 6
      src/Hotline/dataview.md
  41. 1 1
      src/XingTang.Sdk/XingtangSatisfaction.cs
  42. 12 1
      test/Hotline.Tests/Application/XingTangCallsSyncJobTest.cs
  43. 2 1
      test/Hotline.Tests/Startup.cs

+ 8 - 3
src/Hotline.Api/Controllers/ArticleController.cs

@@ -424,8 +424,13 @@ namespace Hotline.Api.Controllers
                     await _circularRecordDomainService.RecordOrgHandle(new List<string> { _sessionContext.RequiredOrgId }, false, "", "", cancellationToken: HttpContext.RequestAborted);
                 }
             }
-
-            return _mapper.Map<CircularDto>(model);
+            var res = _mapper.Map<CircularDto>(model);
+			if (res.FileJson != null && res.FileJson.Any())
+			{
+				var ids = res.FileJson.Select(x => x.Id).ToList();
+				res.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+			}
+			return res;
         }
 
         /// <summary>
@@ -497,7 +502,7 @@ namespace Hotline.Api.Controllers
                 BulletinDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
             }
 
-            return _mapper.Map<BulletinDto>(BulletinDto);
+            return BulletinDto;
         }
 
         /// <summary>

+ 122 - 16
src/Hotline.Api/Controllers/FwThirdController.cs

@@ -1,4 +1,4 @@
-using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml.Office.CoverPageProps;
 using Hotline.Application.Bulletin;
 using Hotline.Application.Identity;
 using Hotline.Application.Orders;
@@ -7,38 +7,25 @@ using Hotline.Caching.Interfaces;
 using Hotline.Configurations;
 using Hotline.KnowledgeBase;
 using Hotline.Orders;
-using Hotline.Push.Notifies;
 using Hotline.Repository.SqlSugar.Extensions;
-using Hotline.Repository.SqlSugar.Knowledge;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos;
-using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
 using Hotline.Share.Dtos.Identity;
-using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.Schedulings;
 using Hotline.Share.Dtos.WebPortal;
 using Hotline.Share.Enums.KnowledgeBase;
 using Hotline.Share.Enums.Order;
-using Hotline.Share.Enums.Push;
-using Hotline.Share.Tools;
 using Hotline.Tools;
+using Hotline.Users;
 using Hotline.WebPortal;
-using Hotline.YbEnterprise.Sdk;
 using MapsterMapper;
-using MathNet.Numerics;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
-using MongoDB.Driver.Core.WireProtocol.Messages;
-using Newtonsoft.Json.Linq;
-using Senparc.Weixin.WxOpen.AdvancedAPIs.WxApp.WxAppJson;
-using Senparc.Weixin.WxOpen.Entities;
-using SharpCompress.Common;
+using NPOI.XWPF.UserModel;
 using SqlSugar;
-using System.Text.Json;
-using System.Threading;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Filters;
@@ -62,6 +49,8 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<OrderPublish> _orderPublishRepository;
         private readonly IOrderRepository _orderRepository;
         private readonly IRepository<OrderVisit> _orderVisitRepository;
+        private readonly IRepository<Order> _orderListRepository;
+        private readonly IRepository<User> _userRepository;
         private readonly IOrderApplication _orderApplication;
         private readonly ISessionContext _sessionContext;
         private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
@@ -89,6 +78,8 @@ namespace Hotline.Api.Controllers
             IRepository<OrderPublish> orderPublishRepository,
             IOrderRepository orderRepository,
             IRepository<OrderVisit> orderVisitRepository,
+            IRepository<Order> orderListRepository,
+            IRepository<User> userRepository,
             IOrderApplication orderApplication,
             ISessionContext sessionContext,
             IRepository<OrderVisitDetail> orderVisitDetailRepository,
@@ -117,6 +108,8 @@ namespace Hotline.Api.Controllers
             _orderPublishRepository = orderPublishRepository;
             _orderRepository = orderRepository;
             _orderVisitRepository = orderVisitRepository;
+            _userRepository = userRepository;
+            _orderListRepository = orderListRepository;
             _orderApplication = orderApplication;
             _sessionContext = sessionContext;
             _orderVisitDetailRepository = orderVisitDetailRepository;
@@ -146,6 +139,9 @@ namespace Hotline.Api.Controllers
 
         #endregion
 
+
+        #region 自贡门户查询接口
+
         #region 受理统计
 
         /// <summary>getacceptancetypestatisticsbymonth
@@ -773,5 +769,115 @@ namespace Hotline.Api.Controllers
         }
 
         #endregion
+
+        #endregion
+
+        #region 泸州电信查询接口
+
+        #region 工单信息
+
+        /// <summary>
+        /// 工单信息
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("getOrderResultList")]
+        public async Task<OpenResponse> GetOrderResultList([FromBody] DateDto dto)
+        {
+            TimeSpan timeSpan = dto.EndTime - dto.StartTime;
+            if (timeSpan.TotalHours > 24)
+            {
+                return OpenResponse.Ok(WebPortalDeResponse<IReadOnlyList<Hotline.Share.Dtos.WebPortal.OrderResultDto>>.Failed("0", "开始结束时间不能大于24小时!"));
+            }
+
+            var items = await _orderListRepository.Queryable()
+                .Where(x => x.CreationTime >= dto.StartTime)
+                .Where(x => x.CreationTime <= dto.EndTime)
+                .OrderByDescending(x => x.CreationTime)
+                .Select(it => new
+                {
+                    Id = it.Id,
+                    No = it.No,
+                    Title = it.Title,
+                    Content = it.Content,
+                    ActualHandleOrgName = it.ActualHandleOrgName,
+                    CreationTime = it.CreationTime,
+                    FromName = it.FromName,
+                    FromPhone = string.IsNullOrEmpty(it.FromPhone) ? it.FromPhone : it.Contact
+                })
+                .ToListAsync();
+
+            var OrderDto = _mapper.Map<IReadOnlyList<Hotline.Share.Dtos.WebPortal.OrderResultDto>>(items);
+            return OpenResponse.Ok(WebPortalDeResponse<IReadOnlyList<Hotline.Share.Dtos.WebPortal.OrderResultDto>>.Success(OrderDto, "成功"));
+        }
+
+        #endregion
+
+        #region 评价信息
+
+        /// <summary>
+        /// 评价信息
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("getVisitResultList")]
+        public async Task<OpenResponse> GetVisitResultList([FromBody] DateDto dto)
+        {
+            TimeSpan timeSpan = dto.EndTime - dto.StartTime;
+            if (timeSpan.TotalHours > 24)
+            {
+                return OpenResponse.Ok(WebPortalDeResponse<IReadOnlyList<Hotline.Share.Dtos.WebPortal.VisitResultDto>>.Failed("0", "开始结束时间不能大于24小时!"));
+            }
+
+            var items = await _orderVisitRepository.Queryable()
+                .Includes(x => x.OrderVisitDetails)
+                .LeftJoin<OrderPublish>((x, op) => x.OrderId == op.OrderId)
+                .Where(x => x.CreationTime >= dto.StartTime)
+                .Where(x => x.CreationTime <= dto.EndTime)
+                .OrderByDescending(x => x.CreationTime)
+                .Select((x, op) => new
+                {
+                    OrderID = x.OrderId,
+                    NowEvaluate = x.NowEvaluate,
+                    VisitContent = x.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org || n.VisitTarget == EVisitTarget.Seat).Select(s => s.VisitContent).First(),
+                    VisitTime = x.VisitTime,
+                    VisitName = x.Employee.Name,
+                    PublishState = op.PublishState
+                })
+                .ToListAsync();
+
+            var VisitDto = _mapper.Map<IReadOnlyList<Hotline.Share.Dtos.WebPortal.VisitResultDto>>(items);
+            return OpenResponse.Ok(WebPortalDeResponse<IReadOnlyList<Hotline.Share.Dtos.WebPortal.VisitResultDto>>.Success(VisitDto, "成功"));
+        }
+
+        #endregion
+
+        #region 账号信息
+
+        /// <summary>
+        /// 账号信息
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("getUserResultList")]
+        public async Task<OpenResponse> GetUserResultList()
+        {
+            var items = await _userRepository.Queryable()
+                .OrderByDescending(x => x.CreationTime)
+                .Select(it => new
+                {
+                    UUID = it.Id,
+                    Name = it.Name
+                })
+                .ToListAsync();
+
+            var UserDto = _mapper.Map<IReadOnlyList<Hotline.Share.Dtos.WebPortal.UserResultDto>>(items);
+            return OpenResponse.Ok(WebPortalDeResponse<IReadOnlyList<Hotline.Share.Dtos.WebPortal.UserResultDto>>.Success(UserDto, "成功"));
+        }
+
+        #endregion
+
+        #endregion
+
     }
 }

+ 31 - 27
src/Hotline.Api/Controllers/OrderController.cs

@@ -1336,7 +1336,9 @@ public class OrderController : BaseController
             Histories = histories,
             IsCanUpdate = isCanUpdate
         };
-        if (_appOptions.Value.IsLuZhou && rsp.OrderVisitModel.Order.IsSecret)
+        if (_appOptions.Value.IsLuZhou 
+            && !_sessionContext.OrgIsCenter
+            && rsp.OrderVisitModel.Order.IsSecret)
         {
             rsp.OrderVisitModel.Order.FromPhone = "****";//rsp.OrderVisitModel.Order.FromPhone?.Replace(rsp.OrderVisitModel.Order.FromPhone.Substring(3, 4), "****");
             rsp.OrderVisitModel.Order.Contact = "****"; //rsp.OrderVisitModel.Order.Contact?.Replace(rsp.OrderVisitModel.Order.Contact.Substring(3, 4), "****");
@@ -2061,10 +2063,10 @@ public class OrderController : BaseController
             }
         }
 
-		if (_appOptions.Value.IsLuZhou && delaydto.DelayNum > order.TimeLimitCount) throw UserFriendlyException.SameMessage("申请天数需小于等于工单办理时限!");
+        if (_appOptions.Value.IsLuZhou && delaydto.DelayNum > order.TimeLimitCount) throw UserFriendlyException.SameMessage("申请天数需小于等于工单办理时限!");
 
-		//验证延期次数
-		var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
+        //验证延期次数
+        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
         if (int.Parse(setting?.SettingValue[0]) != 0 && !_sessionContext.OrgIsCenter)
         {
             int count = await _orderDelayRepository.CountAsync(x =>
@@ -2103,7 +2105,7 @@ public class OrderController : BaseController
             }
 
             model.AfterDelay = (await _expireTime
-                .CalcEndTime(model.BeforeDelay.Value, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+                .CalcEndTime(DateTime.Now, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
         }
 
         model.ApplyDelayTime = DateTime.Now;
@@ -2557,7 +2559,8 @@ public class OrderController : BaseController
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
         var data = _mapper.Map<List<OrderVisitDetailDto>>(items);
         var isAdmin = _orderDomainService.IsCheckAdmin();
-        data.ForEach(d => d.IsShowOperate = dto.ScreenType == EOrderScreenType.Org && (isAdmin == true || (d.VisitOrgCode == _sessionContext.OrgId)));
+        data.ForEach(d => d.IsShowOperate = (dto.ScreenType == EOrderScreenType.Org && d.VisitOrgCode == _sessionContext.OrgId)
+        || isAdmin == true || (dto.ScreenType == EOrderScreenType.Seat));
         return new PagedDto<OrderVisitDetailDto>(total, data);
     }
 
@@ -2976,11 +2979,11 @@ public class OrderController : BaseController
         var screen = await _orderScreenRepository.GetAsync(id);
         var steps = await _workflowStepRepository.Queryable().Where(x => x.WorkflowId == screen.WorkflowId).ToListAsync();
         var allFiles = new List<FileDto>();
-        if (screen != null)
-        {
-            var ids = screen.FileJson.Select(x => x.Id).ToList();
-            allFiles = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
-        }
+        //if (screen != null)
+        //{
+        //    var ids = screen.FileJson.Select(x => x.Id).ToList();
+        //    allFiles = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+        //}
         foreach (var step in steps)
         {
             if (step.FileJson != null && step.FileJson.Any())
@@ -4633,7 +4636,7 @@ public class OrderController : BaseController
                         startTime = dOrder.CenterToOrgTime.Value;
                     }
                     delayOrder.AfterDelay = (await _expireTime
-                        .CalcEndTime(delayOrder.BeforeDelay.Value, startTime, delayOrder.DelayUnit, delayOrder.DelayNum, dOrder.AcceptTypeCode))?.EndTime; //todo
+                        .CalcEndTime(startTime, startTime, delayOrder.DelayUnit, delayOrder.DelayNum, dOrder.AcceptTypeCode))?.EndTime; //todo
                     await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delayOrder.AfterDelay })
                         .Where(x => x.Id == delayOrder.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 }
@@ -6226,15 +6229,14 @@ public class OrderController : BaseController
             var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync(recall,
                 dto.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall,
                 order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall,
-                async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
+                (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                 {
                     var basicWorkflowDto = _mapper.Map<BasicWorkflowDto>(dto);
                     var stepAssignInfo = _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
-                        basicWorkflowDto, HttpContext.RequestAborted).Result;
+                        basicWorkflowDto, HttpContext.RequestAborted).Result; //todo 优化异步
                     if (stepAssignInfo is null) return;
                     var validator = new StepAssignInfoValidator();
-                    await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted);
-
+                    validator.ValidateAndThrow(stepAssignInfo);
                     targetStepNew.Assign(stepAssignInfo);
                 },
                 HttpContext.RequestAborted);
@@ -6392,7 +6394,6 @@ public class OrderController : BaseController
                 HandlerType = dto.HandlerType,
                 BusinessType = dto.BusinessType,
             };
-            DateTime endTime = order.ExpiredTime!.Value;
             //todo
             //宜宾需求:1. 坐席申请特提:指派给申请人办理 2. 派单员申请特提:所有派单员都能办 3.其他特提场景:按节点原配置办理
             order.ProcessType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
@@ -6402,7 +6403,9 @@ public class OrderController : BaseController
             if (dto.AlterTime)
             {
                 DateTime startTime = DateTime.Now;
-                if (order.CenterToOrgTime.HasValue && order.FileOrgIsCenter.HasValue &&  !order.FileOrgIsCenter.Value)
+                DateTime beginTime = DateTime.Now;
+
+                if (order.CenterToOrgTime.HasValue && order.FileOrgIsCenter.HasValue && !order.FileOrgIsCenter.Value)
                 {
                     startTime = order.CenterToOrgTime.Value;
                 }
@@ -6414,13 +6417,14 @@ public class OrderController : BaseController
                 if (_appOptions.Value.IsLuZhou)
                 {
                     startTime = order.ExpiredTime.Value;
-				}
-                
-                var expiredTime = await _expireTime.CalcEndTime(DateTime.Now, startTime, order.AcceptTypeCode);
+                    beginTime = startTime;
+                }
+
+                var expiredTime = await _expireTime.CalcEndTime(beginTime, startTime, order.AcceptTypeCode);
                 if (dto.TimeLimit.HasValue && dto.TimeLimit.Value > 0)
                 {
                     var config = new TimeConfig(dto.TimeLimit.Value, ETimeType.WorkDay);
-                    expiredTime = await _expireTime.CalcEndTime(DateTime.Now, startTime, config, order.AcceptTypeCode);
+                    expiredTime = await _expireTime.CalcEndTime(beginTime, startTime, config, order.AcceptTypeCode);
                 }
 
                 //if (expiredTime.EndTime < order.ExpiredTime.Value)
@@ -6458,19 +6462,19 @@ public class OrderController : BaseController
             //             { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username })
             //         .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             // }
-
+            DateTime endTime = order.ExpiredTime!.Value;
             var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) =
                 await _workflowDomainService.RecallAsync(
                     recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Redo,
                     endTime, order.Status >= EOrderStatus.Filed, EHandleMode.Redo,
-                    async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
+                    (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                     {
                         var stepAssignInfo = recall.NextHandlers.FirstOrDefault()
-                                             ?? await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
-                                                 recall, HttpContext.RequestAborted);
+                                             ?? _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
+                                                 recall, HttpContext.RequestAborted).Result; //todo 优化异步
                         if (stepAssignInfo is null) return;
                         var validator = new StepAssignInfoValidator();
-                        await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted);
+                        validator.ValidateAndThrow(stepAssignInfo);
                         targetStepNew.Assign(stepAssignInfo);
                     }, HttpContext.RequestAborted);
 

+ 14 - 28
src/Hotline.Api/Controllers/PbxController.cs

@@ -1,39 +1,33 @@
 using Hotline.Application.FlowEngine;
 using Hotline.Caching.Interfaces;
 using Hotline.CallCenter.Calls;
+using Hotline.CallCenter.Configs;
+using Hotline.CallCenter.Devices;
 using Hotline.CallCenter.Ivrs;
 using Hotline.CallCenter.Tels;
-using Hotline.Permissions;
+using Hotline.Configurations;
+using Hotline.FlowEngine.WorkflowModules;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Settings;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Trunk;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Requests;
 using Hotline.Users;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
 using SqlSugar;
 using Wex.Sdk;
 using Wex.Sdk.Tel;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
-using XF.Domain.Constants;
 using XF.Domain.Exceptions;
-using XF.Utility.EnumExtensions;
-using System.Linq;
-using Hotline.CallCenter.Configs;
-using Hotline.CallCenter.Devices;
-using Hotline.FlowEngine.WorkflowModules;
-using Hotline.NewRock;
-using Hotline.Share.Dtos;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.Extensions.Options;
 using XF.Domain.Repository;
-using Tr.Sdk;
-using Hotline.Configurations;
-using Hotline.FlowEngine.Workflows;
-using Hotline.Share.Dtos.FlowEngine.Workflow;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Api.Controllers
 {
@@ -67,7 +61,6 @@ namespace Hotline.Api.Controllers
         private readonly IWexClient _wexClient;
         private readonly IWexTelGroupRepository _wexTelGroupRepository;
         private readonly IOptionsSnapshot<CallCenterConfiguration> _options;
-        private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
 
 
         public PbxController(
@@ -96,8 +89,7 @@ namespace Hotline.Api.Controllers
             IWexClient wexClient,
             IWexTelGroupRepository wexTelGroupRepository,
             IOptionsSnapshot<AppConfiguration> appOptions,
-            IOptionsSnapshot<CallCenterConfiguration> options,
-            ISystemDicDataCacheManager systemDicDataCacheManager)
+            IOptionsSnapshot<CallCenterConfiguration> options)
         {
             _telRepository = telRepository;
             _telRestRepository = telRestRepository;
@@ -123,20 +115,14 @@ namespace Hotline.Api.Controllers
             _wexClient = wexClient;
             _wexTelGroupRepository = wexTelGroupRepository;
             _options = options;
-            _systemDicDataCacheManager = systemDicDataCacheManager;
             if (appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XunShi)
             {
                 _newRockDeviceManager = serviceProvider.GetRequiredService<INewRockDeviceManager>();
             }
         }
 
-
-
-
         #region 话机
 
-
-
         /// <summary>
         /// 根据设备自动同步分机数据到数据库
         /// </summary>
@@ -305,8 +291,8 @@ namespace Hotline.Api.Controllers
                 startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
                 startWorkflowDto.Opinion = dto.Reason;
                 startWorkflowDto.Title = "分机休息申请流程";
-				// await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
-				//await _workflowDomainService.StartAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
+                // await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
+                //await _workflowDomainService.StartAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
                 await _workflowDomainService.StartToFirstStepAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
             }
         }
@@ -343,8 +329,8 @@ namespace Hotline.Api.Controllers
             startWorkflowDto.DefinitionModuleCode = WorkflowModuleConsts.TelRestApply;
             startWorkflowDto.Opinion = dto.Reason;
             startWorkflowDto.Title = "分机休息申请流程";
-			// await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
-			//await _workflowDomainService.StartAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
+            // await _workflowApplication.StartWorkflowAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
+            //await _workflowDomainService.StartAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
             await _workflowDomainService.StartToFirstStepAsync(startWorkflowDto, telRest.Id, cancellationToken: HttpContext.RequestAborted);
         }
 

+ 210 - 0
src/Hotline.Api/Controllers/TelRestController.cs

@@ -0,0 +1,210 @@
+using Hotline.Application.CallCenter;
+using Hotline.Article;
+using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.Tels;
+using Hotline.Realtimes;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Settings;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Article;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Article;
+using Hotline.Share.Enums.CallCenter;
+using Hotline.Tools;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using System.Threading;
+using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Api.Controllers
+{
+    public class TelRestController : BaseController
+    {
+        private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+        private readonly IRepository<TelRestApply> _telRestApplyRepository;
+        private readonly IPbxApplication _pbxApplication;
+        private readonly ISessionContext _sessionContext;
+        private readonly ITelDomainService _telDomainService;
+        private readonly IMapper _mapper;
+        private readonly IRealtimeService _realtimeService;
+        private readonly ICircularRecordDomainService _circularRecordDomainService;
+
+        public TelRestController(ISystemDicDataCacheManager systemDicDataCacheManager,
+             IRepository<TelRestApply> telRestApplyRepository,
+              IPbxApplication pbxApplication,
+              ISessionContext sessionContext,
+              ITelDomainService telDomainService,
+              IMapper mapper,
+              IRealtimeService realtimeService,
+              ICircularRecordDomainService circularRecordDomainService)
+        {
+            _systemDicDataCacheManager = systemDicDataCacheManager;
+            _telRestApplyRepository = telRestApplyRepository;
+            _pbxApplication = pbxApplication;
+            _sessionContext = sessionContext;
+            _telDomainService = telDomainService;
+            _mapper = mapper;
+            _realtimeService = realtimeService;
+            _circularRecordDomainService = circularRecordDomainService;
+        }
+
+        #region 小休审批
+
+        /// <summary>
+        /// 列表页面基础数据
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("base-data")]
+        public async Task<object> BaseData()
+        {
+            var rsp = new
+            {
+                RestReason = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.RestReason),
+                AuditStatus = EnumExts.GetDescriptions<ETelRestAuditStatus>()
+            };
+            return rsp;
+        }
+
+        /// <summary>
+        /// 小休申请
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        /// <exception cref="UserFriendlyException"></exception>
+        [HttpPost("addtelrest")]
+        public async Task<string> AddTelRest([FromBody] TelRestApplyAddDto dto)
+        {
+            if (string.IsNullOrEmpty(dto.TelNo))
+                return "分机号不能为空!";
+            if (dto.Reason == null)
+                return "小休原因不能为空!";
+
+            var data = await _telRestApplyRepository.GetAsync(p => p.TelNo == dto.TelNo && p.CreatorId == _sessionContext.RequiredUserId &&
+            p.AuditStatus == ETelRestAuditStatus.NoAudit, HttpContext.RequestAborted);
+            if (data != null)
+                return "小休申请审批中,暂时无法操作!";
+
+            TelRestApply telRestApply = new()
+            {
+                TelNo = dto.TelNo,
+                Reason = dto.Reason.Value,
+                ReasonId = dto.Reason.Key,
+                StaffNo = _sessionContext.StaffNo,
+                AuditStatus = ETelRestAuditStatus.NoAudit
+            };
+            var id = await _telRestApplyRepository.AddAsync(telRestApply, HttpContext.RequestAborted);
+            if (!string.IsNullOrEmpty(id))
+                return "小休申请成功!";
+            else
+                return "小休申请失败!";
+
+        }
+
+        /// <summary>
+        /// 小休审批
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        /// <exception cref="UserFriendlyException"></exception>
+        [HttpPost("telrest_apply_audit")]
+        public async Task<string> TelRestApplyAudit([FromBody] TelRestApplyAuditDto dto)
+        {
+            if (dto.IsPass != true && string.IsNullOrEmpty(dto.AuditOpinion))
+                return "审批原因不能为空!";
+            foreach (var item in dto.Ids)
+            {
+                var data = await _telRestApplyRepository.GetAsync(item, HttpContext.RequestAborted);
+                if (data != null)
+                {
+                    data.AuditUserName = _sessionContext.UserName;
+                    data.AuditUserId = _sessionContext.RequiredUserId;
+                    data.AuditOrgId = _sessionContext.RequiredOrgId;
+                    data.AuditOrgName = _sessionContext.OrgName;
+                    data.AuditTime = DateTime.Now;
+                    data.AuditOpinion = dto.AuditOpinion;
+                    data.AuditStatus = dto.IsPass == true ? ETelRestAuditStatus.Pass : ETelRestAuditStatus.NoPass;
+                    await _telRestApplyRepository.UpdateAsync(data, HttpContext.RequestAborted);
+
+                    //发送消息
+                    var ispasstext = dto.IsPass == true ? "已通过" : "不通过";
+                    AddCircularDto circularDto = new()
+                    {
+                        Title = "小休审批",
+                        Content = "您在" + data.CreationTime.ToString("yyyy-MM-dd HH:mm:ss") + "申请的小休审批" + ispasstext,
+                        CircularTypeId = "7",
+                        CircularTypeName = "小休审批",
+                        IsMustRead = true,
+                        SourceOrgId = _sessionContext.RequiredOrgId,
+                        SourceOrgName = _sessionContext.OrgName,
+                        CircularType = ECircularType.Person
+                    };
+                    List<CircularReadGroupDto> users = [];
+                    users.Add(new CircularReadGroupDto()
+                    {
+                        UserId = data.CreatorId,
+                        UserName = data.CreatorName
+                    });
+                    circularDto.CircularReadGroups = users;
+                    //调用推送消息通用接口
+                    await _circularRecordDomainService.AddCircularMessage(circularDto, HttpContext.RequestAborted);
+                    if (dto.IsPass)
+                    {
+                        //通知前端休息通过
+                        await _realtimeService.RestApplyPassAsync(data.CreatorId, HttpContext.RequestAborted);
+                    }
+                }
+            }
+            return "审批完成";
+        }
+
+        /// <summary>
+        /// 小修申请记录
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get_restapply_list")]
+        public async Task<PagedDto<TelRestApplyListDto>> GetRestApplyList([FromQuery] TelRestApplyRequestDto dto)
+        {
+            var (total, items) = await _pbxApplication.GetRestApplyList(dto).ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+            return new PagedDto<TelRestApplyListDto>(total, items);
+        }
+
+        /// <summary>
+        /// 小修申请记录--导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get_restapply_list_export")]
+        public async Task<FileStreamResult> GetRestApplyListExport([FromBody] ExportExcelDto<TelRestApplyRequestDto> dto)
+        {
+            var query = _pbxApplication.GetRestApplyList(dto.QueryDto);
+
+            List<TelRestApplyListDto> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(TelRestApplyListDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+            return ExcelStreamResult(stream, "小修申请记录数据");
+        }
+
+
+        #endregion
+    }
+}

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


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


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

@@ -325,14 +325,14 @@ namespace Hotline.Api
                             .WithCronSchedule("0/10 * * * * ?")
                         );
 
-                        //var getCallSatisfactionJobKey = new JobKey(nameof(XingTangCallSatisfactionSyncJob));
-                        //d.AddJob<XingTangCallSatisfactionSyncJob>(getCallSatisfactionJobKey);
-                        //d.AddTrigger(t => t
-                        //    .WithIdentity("get-callsatisfaction-trigger")
-                        //    .ForJob(getCallSatisfactionJobKey)
-                        //    .StartNow()
-                        //    .WithCronSchedule("0/30 * * * * ?")
-                        //);
+                        var getCallSatisfactionJobKey = new JobKey(nameof(XingTangCallSatisfactionSyncJob));
+                        d.AddJob<XingTangCallSatisfactionSyncJob>(getCallSatisfactionJobKey);
+                        d.AddTrigger(t => t
+                            .WithIdentity("get-callsatisfaction-trigger")
+                            .ForJob(getCallSatisfactionJobKey)
+                            .StartNow()
+                            .WithCronSchedule("0/30 * * * * ?")
+                        );
 
                         break;
                 }

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

@@ -1,7 +1,7 @@
 {
   "AllowedHosts": "*",
   "AppConfiguration": {
-    "AppScope": "ZiGong",
+    "AppScope": "YiBin",
     "YiBin": {
       "AreaCode": "511500",
       "CallCenterType": "TianRun", //XunShi、WeiErXin、TianRun、XingTang

+ 17 - 3
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -259,6 +259,8 @@ public abstract class DefaultCallApplication : ICallApplication
     /// </summary>
     public virtual ISugarQueryable<CallNativeDto> QueryCallsFixedAsync(QueryCallsFixedDto dto, CancellationToken cancellationToken)
     {
+        if (dto.SortField.NotNullOrEmpty())
+            dto.SortField = dto.SortField.ToLower();
         var query = _callNativeRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((d, o) => d.Id == o.CallId)
             .LeftJoin<OrderVisit>((d, o, v) => d.Id == v.CallId)
@@ -278,7 +280,9 @@ public abstract class DefaultCallApplication : ICallApplication
             .WhereIF(dto.WaitDurationEnd != null && dto.WaitDurationEnd > 0, d => d.WaitDuration <= dto.WaitDurationEnd)
             .WhereIF(dto.IsMissOrder != null && dto.IsMissOrder.Value == true, (d, o, v) => string.IsNullOrEmpty(o.Id) == true)
             .WhereIF(dto.IsMissOrder != null && dto.IsMissOrder.Value == false, (d, o, v) => string.IsNullOrEmpty(o.Id) == false)
-            .OrderByDescending(d => d.Id);
+            .OrderByIF(dto.SortField.IsNullOrEmpty(), (d, o, v) => d.BeginIvrTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortField: "waitduration", SortRule: 0 }, (d, o, v) =>  d.WaitDuration , OrderByType.Asc)
+            .OrderByIF(dto is { SortField: "waitduration", SortRule: 1 }, (d, o, v) => d.WaitDuration, OrderByType.Desc);
 
         query = query.WhereIF(dto.Type == 3, (d, o, v) => d.AnsweredTime == null);
         query = query.WhereIF(dto.Type == 1, (d, o, v) => d.Direction == ECallDirection.In && d.AnsweredTime != null);
@@ -306,8 +310,18 @@ public abstract class DefaultCallApplication : ICallApplication
                 Title = o.Title,
                 IsVisit = !SqlFunc.IsNullOrEmpty(v.Id),
                 IsOrder = !SqlFunc.IsNullOrEmpty(o.Id),
-                StaffNo = SqlFunc.IsNull(SqlFunc.Subqueryable<CallNative>().Where(s => s.CallNo == d.CallNo && SqlFunc.IsNullOrEmpty(s.CallNo) == false && s.CallNo != "0").Select(s => s.StaffNo), "0"),
-                TelNo = SqlFunc.IsNull(SqlFunc.Subqueryable<CallNative>().Where(s => s.CallNo == d.TelNo && SqlFunc.IsNullOrEmpty(s.TelNo) == false && s.TelNo != "0").Select(s => s.TelNo), "0"),
+                StaffNo = SqlFunc.Coalesce(
+                    SqlFunc.IIF(d.StaffNo == "0", null, d.StaffNo),
+                    SqlFunc.Subqueryable<CallNative>()
+                        .Where(m => m.CallNo == d.CallNo && m.StaffNo != "0")
+                        .Max(m => m.StaffNo)
+                    ),
+                TelNo = SqlFunc.Coalesce(
+                    SqlFunc.IIF(d.TelNo == "0", null, d.TelNo),
+                    SqlFunc.Subqueryable<CallNative>()
+                        .Where(m => m.CallNo == d.CallNo && m.TelNo != "0")
+                        .Max(m => m.TelNo)
+                    ),
             }, true);
         }
         return query.Select((d, o, v) => new CallNativeDto

+ 15 - 0
src/Hotline.Application/CallCenter/IPbxApplication.cs

@@ -0,0 +1,15 @@
+using Hotline.Share.Dtos.CallCenter;
+using SqlSugar;
+
+namespace Hotline.Application.CallCenter
+{
+    public interface IPbxApplication
+    {
+        /// <summary>
+        /// 小修申请记录
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<TelRestApplyListDto> GetRestApplyList(TelRestApplyRequestDto dto);
+    }
+}

+ 61 - 0
src/Hotline.Application/CallCenter/PbxApplication.cs

@@ -0,0 +1,61 @@
+using Hotline.CallCenter.Tels;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Enums.CallCenter;
+using SqlSugar;
+using XF.Domain.Dependency;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.CallCenter
+{
+    public class PbxApplication : IPbxApplication, IScopeDependency
+    {
+        private readonly IRepository<TelRestApply> _telRestApplyRepository;
+
+        public PbxApplication(IRepository<TelRestApply> telRestApplyRepository)
+        {
+            _telRestApplyRepository = telRestApplyRepository;
+        }
+
+        /// <summary>
+        /// 小修申请记录
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<TelRestApplyListDto> GetRestApplyList(TelRestApplyRequestDto dto)
+        {
+            var query = _telRestApplyRepository.Queryable()
+                .WhereIF(dto.Type is 0, p => p.AuditStatus == ETelRestAuditStatus.NoAudit)
+                .WhereIF(dto.Type is 1, p => p.AuditStatus == ETelRestAuditStatus.Pass || p.AuditStatus == ETelRestAuditStatus.NoPass)
+                .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), p => p.CreatorName == dto.ApplyUserName)
+                .WhereIF(dto.ApplyStartTime.HasValue, p => p.CreationTime >= dto.ApplyStartTime)
+                .WhereIF(dto.ApplyEndTime.HasValue, p => p.CreationTime <= dto.ApplyEndTime)
+                .WhereIF(dto.AuditStatus.HasValue, p => p.AuditStatus == dto.AuditStatus)
+                .WhereIF(!string.IsNullOrEmpty(dto.AuditUserName), p => p.AuditUserName == dto.AuditUserName)
+                .WhereIF(dto.AuditStartTime.HasValue, p => p.AuditTime >= dto.AuditStartTime)
+                .WhereIF(dto.AuditEndTime.HasValue, p => p.AuditTime <= dto.AuditEndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.ReasonId), p => p.ReasonId == dto.ReasonId)
+                .Select(p => new TelRestApplyListDto
+                {
+                    Id = p.Id,
+                    ApplyUserName = p.CreatorName,
+                    ApplyTime = p.CreationTime,
+                    Reason = p.Reason,
+                    ReasonId = p.ReasonId,
+                    AuditUserName = p.AuditUserName,
+                    AuditUserId = p.AuditUserId,
+                    AuditOrgName = p.AuditOrgName,
+                    AuditOrgId = p.AuditOrgId,
+                    AuditTime = p.AuditTime,
+                    AuditStatus = p.AuditStatus,
+                    AuditOpinion = p.AuditOpinion
+                })
+                .OrderByIF(dto is { SortField: "applyTime", SortRule: 0 }, p => p.ApplyTime, OrderByType.Asc) //申请时间升序
+                .OrderByIF(dto is { SortField: "applyTime", SortRule: 1 }, p => p.ApplyTime, OrderByType.Desc) //申请时间降序
+                .OrderByIF(dto is { SortField: "auditTime", SortRule: 0 }, p => p.AuditTime, OrderByType.Asc) //审核时间升序
+                .OrderByIF(dto is { SortField: "auditTime", SortRule: 1 }, p => p.AuditTime, OrderByType.Desc) //审核时间降序
+                .OrderByIF(string.IsNullOrEmpty(dto.SortField), p => p.ApplyTime, OrderByType.Desc)
+               ;
+            return query;
+        }
+    }
+}

+ 21 - 0
src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs

@@ -19,6 +19,7 @@ using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.CallCenter;
+using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Tools;
 using Hotline.Snapshot.Notifications;
@@ -171,6 +172,26 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     order.FileOrgIsCenter = notification.Trace.HandlerOrgIsCenter;
                     order.FileOpinion = notification.Dto.Opinion;
 
+                    /*
+                     *需求:
+                     *1、判断工单属于哪种归档类型,需由谁归档来判断,热线中心归档的就叫中心归档件,部门归档就叫做部门归档件
+                       2、若工单发起过部门会签,最后由热线中心归档,应属于叫中心归档件和非会签件
+                       3、若工单发起过中心会签,最后由部门归档,应属于部门归档件和非会签件
+                     */
+                    if (_appOptions.Value.IsYiBin)
+                    {
+                        if (order.FileOrgIsCenter.Value)
+                        {
+                            if (order.CounterSignType is ECounterSignType.Department)
+                                order.CounterSignType = null;
+                        }
+                        else
+                        {
+                            if (order.CounterSignType is ECounterSignType.Center)
+                                order.CounterSignType = null;
+                        }
+                    }
+
                     //记录冗余归档数据
                     if (notification.Workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
                     {

+ 39 - 17
src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs

@@ -1,6 +1,9 @@
-using DotNetCore.CAP;
+using DocumentFormat.OpenXml.Office.CustomUI;
+using DotNetCore.CAP;
 using Hotline.CallCenter.Calls;
+using Hotline.Repository.SqlSugar;
 using Hotline.Share.Mq;
+using Hotline.Share.Tools;
 using MapsterMapper;
 using Microsoft.Extensions.Logging;
 using Quartz;
@@ -20,23 +23,20 @@ namespace Hotline.Application.Jobs
     /// </summary>
     public class XingTangCallSatisfactionSyncJob : IJob, IDisposable
     {
-        private readonly IRepository<CallNative> _callRepository;
+        private readonly IRepository<CallNative> _callNativeRepository;
         private readonly ISqlSugarClient _db;
         private readonly IRepository<CallSatisfaction> _callSatisfactionRepository;
         private readonly IMapper _mapper;
         private readonly ILogger<XingTangCallSatisfactionSyncJob> _logger;
-        private readonly ICapPublisher _capPublisher;
 
-        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISqlSugarClient db,
-            IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger,
-            ICapPublisher capPublisher)
+        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISugarUnitOfWork<XingTangDbContext> uow,
+            IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger)
         {
-            _callRepository = callRepository;
-            _db = db;
+            _callNativeRepository = callRepository;
+            _db = uow.Db;
             _callSatisfactionRepository = callSatisfactionRepository;
             _mapper = mapper;
             _logger = logger;
-            _capPublisher = capPublisher;
         }
 
         public void Dispose()
@@ -51,7 +51,7 @@ namespace Hotline.Application.Jobs
                 .Take(10)
                 .ToListAsync(context.CancellationToken);
 
-            if (!callSatisfactions.Any()) return;
+            if (callSatisfactions.IsNullOrEmpty()) return;
             var occupyCallSatisfactions = new List<XingtangSatisfaction>();
             foreach (var callSatisfaction in callSatisfactions)
             {
@@ -64,22 +64,44 @@ namespace Hotline.Application.Jobs
                     occupyCallSatisfactions.Add(callSatisfaction);
             }
 
-            if (!occupyCallSatisfactions.Any()) return;
+            if (occupyCallSatisfactions.IsNullOrEmpty()) return;
             try
             {
                 var callStatisfactions = _mapper.Map<List<CallSatisfaction>>(occupyCallSatisfactions);
-                foreach (var item in callSatisfactions)
+                var callNos = callSatisfactions.Select(m => m.CallNo).ToList();
+                var callNative = await _callNativeRepository.Queryable().Where(x => callNos.Contains(x.CallNo) && string.IsNullOrEmpty(x.AudioFile) == false).Select(x => new { x.Id, x.CallNo }).ToListAsync();
+                var failSyncList = new List<XingtangSatisfaction>();
+                var newCallNative = new List<CallSatisfaction>();
+                foreach (var item in callStatisfactions)
                 {
-                    var call = _callRepository.Queryable().Where(x => x.CallNo == item.CallNo).FirstAsync();
-                    if (call != null)
+                    var call = callNative.FirstOrDefault(m => m.CallNo == item.CallNo);
+                    if (call == null)
                     {
+                        var goSync = (occupyCallSatisfactions.FirstOrDefault(m => m.CallNo == item.CallNo)?.Tries ?? 0) == 50;
+                        if (goSync)
+                        {
+                            newCallNative.Add(item);
+                        }
+                        else
+                        {
+                            var fail = callSatisfactions.First(m => m.CallNo == item.CallNo);
+                            fail.IsSync = false;
+                            failSyncList.Add(fail);
+                        }
+                    }
+                    else
+                    {
+                        newCallNative.Add(item);
                         item.Id = call.Id;
+                        await _callNativeRepository.Updateable()
+                            .SetColumns(m => m.ReplyTxt, item.Result)
+                            .Where(m => m.CallNo == call.CallNo)
+                            .ExecuteCommandAsync();
                     }
                 }
 
-                await _callSatisfactionRepository.AddRangeAsync(callStatisfactions, context.CancellationToken);
-                await _capPublisher.PublishAsync(EventNames.HotlineCallSatisfactionAdd, callStatisfactions,
-                    cancellationToken: context.CancellationToken);
+                await _db.Updateable(failSyncList).UpdateColumns(m => new { m.IsSync }).ExecuteCommandAsync();
+                await _callSatisfactionRepository.AddRangeAsync(newCallNative, context.CancellationToken);
             }
             catch (Exception e)
             {

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

@@ -116,6 +116,11 @@ namespace Hotline.Application.Jobs
                             }
                         }
 
+                        if (call.AnsweredTime == null && call.Direction == ECallDirection.In && call.WaitDuration == 0)
+                        {
+                            call.WaitDuration = call.EndTime.GetDifferenceSeconds(call.BeginIvrTime.Value);
+                        }
+
                         if (call.GroupId == "0" && call.CallState != ECallState.IVRNoAccept)
                         {
                             call.CallState = ECallState.Invalid;

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

@@ -4,6 +4,7 @@ using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Orders;
 using Hotline.Push.Notifies;
+using Hotline.SeedData;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
@@ -155,7 +156,7 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
                 if (_appOptions.Value.IsZiGong)
                 {
                     var user = await _userRepository.GetAsync(p => p.Id == screen.CreatorId, cancellationToken);
-                    if (user != null)
+                    if (user != null && user.OrgId != OrgSeedData.CenterId)
                     {
                         var isReviewPassText = isReviewPass == true ? "审批通过" : "审批拒绝";
                         var messageDto = new Share.Dtos.Push.MessageDto

+ 1 - 0
src/Hotline.Application/Orders/Handlers/OrderScreenHandler/OrderScreenNextWorkflowHandler.cs

@@ -82,6 +82,7 @@ public class OrderScreenNextWorkflowHandler : INotificationHandler<NextStepNotif
                                 {
                                     screenDto.Content = notification.Dto.Opinion;
 									screenDto.Files = new List<Share.Dtos.File.FileDto>();
+                                    screenDto.FileJson = screenDto.ProvinceFileJson;
 									if (screenDto.ProvinceFileJson.Any())
                                     {
                                         var fileIds = screenDto.ProvinceFileJson.Select(x => x.Id).ToList();

+ 76 - 20
src/Hotline.Application/Orders/OrderApplication.cs

@@ -63,6 +63,9 @@ using J2N.Text;
 using Hotline.Application.FlowEngine;
 using Hotline.Article;
 using Hotline.Share.Dtos.CallCenter;
+using DocumentFormat.OpenXml.Bibliography;
+using Hotline.Identity.Accounts;
+using Hotline.Identity.Roles;
 
 namespace Hotline.Application.Orders;
 
@@ -113,6 +116,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<KnowledgeQuote> _knowledgeQuoteRepository;
     private readonly IRepository<OrderSpecial> _orderSpecialRepository;
     private readonly IRepository<User> _userRepository;
+    private readonly IRepository<Role> _roleRepository;
     private readonly IWorkflowApplication _workflowApplication;
     private readonly ICircularRecordDomainService _circularRecordDomainService;
     private readonly ISessionContextManager _sessionContextManager;
@@ -167,7 +171,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         ICircularRecordDomainService circularRecordDomainService,
         ISessionContextCreator sessionContextCreator,
         ISessionContextManager sessionContextManager,
-        IOrderVisitApplication orderVisitApplication
+        IOrderVisitApplication orderVisitApplication,
+        IRepository<Role> roleRepository
         )
     {
         _orderDomainService = orderDomainService;
@@ -218,7 +223,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _circularRecordDomainService = circularRecordDomainService;
         _sessionContextManager = sessionContextManager;
         _orderVisitApplication = orderVisitApplication;
-    }
+        _roleRepository = roleRepository;
+	}
 
     /// <summary>
     /// 更新工单办理期满时间(延期调用,其他不调用)
@@ -1183,6 +1189,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
             if (bool.Parse(enabled))
             {
+                //自动延期催办短信发送
+                await _capPublisher.PublishDelayAsync(expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(2),
+                    EventNames.HotlineOrderAutomaticSendSmsDelay, new PublishAutomaticDelayDto() { OrderId = order.Id }, cancellationToken: cancellationToken);
+
                 await _capPublisher.PublishDelayAsync(
                     expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(1),
                     EventNames.HotlineOrderAutomaticDelay,
@@ -1216,6 +1226,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
             if (bool.Parse(enabled))
             {
+                //自动延期催办短信发送
+                await _capPublisher.PublishDelayAsync(expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(2),
+                    EventNames.HotlineOrderAutomaticSendSmsDelay, new PublishAutomaticDelayDto() { OrderId = order.Id }, cancellationToken: cancellationToken);
+
                 _capPublisher.PublishDelay(expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay,
                     new PublishAutomaticDelayDto() { OrderId = order.Id });
             }
@@ -1235,6 +1249,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
                 if (bool.Parse(enabled))
                 {
+                    //自动延期催办短信发送
+                    await _capPublisher.PublishDelayAsync(expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(2),
+                        EventNames.HotlineOrderAutomaticSendSmsDelay, new PublishAutomaticDelayDto() { OrderId = order.Id }, cancellationToken: cancellationToken);
+
                     _capPublisher.PublishDelay(expiredTimeConfig.ExpiredTime - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay,
                         new PublishAutomaticDelayDto() { OrderId = order.Id });
                 }
@@ -1397,9 +1415,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             await _qualityApplication.AddQualityAsync(EQualitySource.Visit, visit.Order.Id, visit.Id,
                 cancellationToken);
 
-            //回访成功后,写入回访记录信息
             if (_appOptions.Value.IsZiGong == true)
             {
+                //回访成功后,写入回访记录信息
                 await _orderVisitApplication.AddOrderVisitRecordAsync(new OrderVisitRecordDto()
                 {
                     No = visit.No,
@@ -1408,6 +1426,46 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                     EmployeeId = visit.EmployeeId,
                     VisitTime = visit.VisitTime
                 }, cancellationToken);
+
+                //回访成功后结果不满意发送甄别提醒短信
+                var isOpenSendEndSms = _systemSettingCacheManager.IsSendDissatisfiedScreenSms;
+                if (isOpenSendEndSms)
+                {
+                    try
+                    {
+                        if (first.VisitOrgCode != OrgSeedData.CenterId &&
+                            (first.OrgProcessingResults.Value == "不满意" || first.OrgProcessingResults.Value == "非常不满意"))
+                        {
+                            var roleJingBanRen = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                            var userList = await _userRepository
+                                            .Queryable()
+                                            .Where(d => d.OrgId == first.VisitOrgCode &&
+                                                   d.Roles.Any(x => roleJingBanRen.Contains(x.Id)) &&
+                                                   string.IsNullOrEmpty(d.PhoneNo) == false)
+                                            .ToListAsync();
+
+                            foreach (var item in userList)
+                            {
+                                var messageDto = new Share.Dtos.Push.MessageDto
+                                {
+                                    PushBusiness = EPushBusiness.DissatisfiedScreen,
+                                    ExternalId = first.VisitId,
+                                    OrderId = visit.Order.Id,
+                                    PushPlatform = EPushPlatform.Sms,
+                                    Remark = visit.Order.Title,
+                                    Name = item.Name,
+                                    TemplateCode = "1020",
+                                    Params = new List<string>() { visit.Order.No },
+                                    TelNumber = item.PhoneNo,
+                                };
+                                await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                            }
+                        }
+                    }
+                    catch (Exception)
+                    {
+                    }
+                }
             }
         }
     }
@@ -1565,8 +1623,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .WhereIF(!string.IsNullOrEmpty(dto.AreaCode) && dto.AreaCode.LastIndexOf("00") > 0,
                     d => d.AreaCode.StartsWith(SqlFunc.Substring(dto.AreaCode, 0, 4)))
                 .WhereIF(!string.IsNullOrEmpty(dto.AreaCode) && dto.AreaCode.LastIndexOf("00") <= 0, d => d.AreaCode.StartsWith(dto.AreaCode))
-                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.IsProvince == true)
-                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.IsProvince == false)
+                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true && dto.ProvinceSearch != true, d => d.IsProvince == true)
+                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false && dto.ProvinceSearch != true, d => d.IsProvince == false)
+                .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true && dto.ProvinceSearch == true, d => d.Source == ESource.ProvinceStraight)
                 .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), d => SqlFunc.JsonArrayAny(d.Sensitive, dto.SensitiveWord))
                 .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true,
                     d => d.Sensitive != null && SqlFunc.JsonArrayLength(d.Sensitive) > 0)
@@ -1587,8 +1646,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTagCode == dto.OrderTagCode)// 工单标签
                 .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode)) //工单标签
                 .WhereIF(!string.IsNullOrEmpty(dto.FocusOnEvents),
-                    d => d.FocusOnEvents.Contains(dto
-                        .FocusOnEvents)) //!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
+                    d => d.FocusOnEvents.Contains(dto.FocusOnEvents)) //!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
                 .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) //默认排序时间为创建时间
                 .OrderByIF(dto is { SortField: "no", SortRule: 0 }, d => d.No, OrderByType.Asc) //工单编号升序
                 .OrderByIF(dto is { SortField: "no", SortRule: 1 }, d => d.No, OrderByType.Desc) //工单编号降序
@@ -4189,14 +4247,14 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             await _workflowDomainService.RecallAsync(
                 recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall,
                 order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall,
-                async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
+                (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                 {
                     var stepAssignInfo = recall.NextHandlers.FirstOrDefault()
                                          ?? GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
-                                             recall, cancellation).Result;
+                                             recall, cancellation).Result; //todo 优化异步
                     if (stepAssignInfo is null) return;
                     var validator = new StepAssignInfoValidator();
-                    await validator.ValidateAndThrowAsync(stepAssignInfo, cancellation);
+                    validator.ValidateAndThrow(stepAssignInfo);
                     targetStepNew.Assign(stepAssignInfo);
                 },
                 cancellation);
@@ -5275,13 +5333,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             (_, currentStep, _, prevStep, newStep, flowDirection) =
                 await _workflowApplication.PreviousAsync(sendBack.SendBackData,
                     userId, orgId, roles, handleMode,
-                    async (workflow1, currentStep1, prevStepDefine, prevStep1, newStep) =>
+                    (workflow1, currentStep1, prevStepDefine, prevStep1, newStep) =>
                     {
-                        var stepAssignInfo =
-                            GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, cancellationToken).Result;
+                        var stepAssignInfo = GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, cancellationToken).Result;//todo 优化异步
                         if (stepAssignInfo is null) return;
                         var validator = new StepAssignInfoValidator();
-                        await validator.ValidateAndThrowAsync(stepAssignInfo);
+                        validator.Validate(stepAssignInfo);
                         newStep.Assign(stepAssignInfo);
                     },
                     cancellationToken);
@@ -5331,15 +5388,14 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 
         if (_appOptions.Value.IsYiBin && order.IsProvince && sendBack.ApplyOrgId.Length == 6 && sendBack.SendBackOrgId == OrgSeedData.CenterId)
         {
-            if (currentStep.FlowAssignType == EFlowAssignType.User)
+            if (newStep.FlowAssignType == EFlowAssignType.User)
             {
-                await _circularRecordDomainService.OrderSendBackCircularMessage(currentStep.HandlerId, currentStep.HandlerName, order, cancellationToken);
+                await _circularRecordDomainService.OrderSendBackCircularMessage(newStep.HandlerId, newStep.HandlerName, order, cancellationToken);
             }
-            else if (currentStep.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(currentStep.RoleId))
+            else if (newStep.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(newStep.RoleId))
             {
-
-                var users = await _userRepository.Queryable().Includes(x => x.Roles).Where(x => x.Roles.Where(x => x.Id == currentStep.RoleId).Any()).ToListAsync();
-                foreach (var user in users)
+                var role = await _roleRepository.Queryable().Includes(x=> x.Accounts).FirstAsync(x => x.Name == newStep.RoleId, cancellationToken);
+                foreach (var user in role.Accounts)
                 {
                     await _circularRecordDomainService.OrderSendBackCircularMessage(user.Id, user.Name, order, cancellationToken);
                 }

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

@@ -236,15 +236,14 @@ namespace Hotline.Application.Orders
                 var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync(recall,
                         recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.SecondHandle,
                         order.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.SecondaryHandle,
-                        async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
+                        (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) =>
                         {
                             var basicWorkflowDto = _mapper.Map<BasicWorkflowDto>(dto);
                             var stepAssignInfo = _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep,
-                                basicWorkflowDto, cancellationToken).Result;
+                                basicWorkflowDto, cancellationToken).Result; //todo 优化异步
                             if (stepAssignInfo is null) return;
                             var validator = new StepAssignInfoValidator();
-                            await validator.ValidateAndThrowAsync(stepAssignInfo, cancellationToken);
-
+                            validator.ValidateAndThrow(stepAssignInfo);
                             targetStepNew.Assign(stepAssignInfo);
                         },
                         cancellationToken);

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

@@ -294,7 +294,7 @@ public abstract class CallReportApplicationBase : ICallReportApplication
                   InAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null, 1, 0)), // 呼入接通量
                   OutAnswered = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.Out && c.AnsweredTime != null, 1, 0)), // 呼出接通量
                   InHangupImmediate = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime == null && c.RingDuration < noConnectByeTimes, 1, 0)), // 呼入秒挂
-                  InHanguped = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.CallState == ECallState.Missed, 1, 0)), //呼入未接
+                  InHanguped = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.RingDuration >= noConnectByeTimes, 1, 0)), //呼入未接
                   InDurationAvg = SqlFunc.Ceil(SqlFunc.AggregateAvg(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null, c.Duration, 0))), // 呼入平均时长
                   OutDurationAvg = SqlFunc.Ceil(SqlFunc.AggregateAvg(SqlFunc.IIF(c.Direction == ECallDirection.Out && c.AnsweredTime != null, c.Duration, 0))), // 呼出平均时长
                   InAvailableAnswer = SqlFunc.AggregateSum(SqlFunc.IIF(c.Direction == ECallDirection.In && c.AnsweredTime != null && c.Duration >= effectiveTimes, 1, 0)), // 有效接通量

+ 0 - 72
src/Hotline.Application/Subscribers/CallSubscriber.cs

@@ -1,72 +0,0 @@
-using DotNetCore.CAP;
-using Hotline.CallCenter.Calls;
-using Hotline.Orders;
-using Hotline.Share.Dtos.TrCallCenter;
-using Hotline.Share.Enums.Order;
-using Hotline.Share.Mq;
-using Hotline.Share.Tools;
-using Polly;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Dependency;
-using XF.Domain.Exceptions;
-using XF.Domain.Repository;
-
-namespace Hotline.Application.Subscribers;
-public class CallSubscriber : ICapSubscribe, ITransientDependency
-{
-    private readonly IRepository<CallNative> _callRepository;
-    private readonly IRepository<Order> _orderRepository;
-    private readonly IRepository<OrderVisit> _orderVisitrepository;
-    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
-    private readonly IOrderVisitRepository _orderVisitRepository;
-
-    public CallSubscriber(IRepository<CallNative> callRepository, IRepository<Order> orderRepository, IRepository<OrderVisit> orderVisitrepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, IOrderVisitRepository orderVisitRepository)
-    {
-        _callRepository = callRepository;
-        _orderRepository = orderRepository;
-        _orderVisitrepository = orderVisitrepository;
-        _orderVisitDetailRepository = orderVisitDetailRepository;
-        _orderVisitRepository = orderVisitRepository;
-    }
-
-    /// <summary>
-    /// 挂断电话
-    /// </summary>
-    /// <param name="dto"></param>
-    /// <param name="cancellationToken"></param>
-    /// <returns></returns>
-    /// <exception cref="UserFriendlyException"></exception>
-    //[CapSubscribe(EventNames.HotlineCallBye)]
-    //public async Task HotlineCallBye(PublishCallRecrodDto dto, CancellationToken cancellationToken)
-    //{
-    //    var callId = await _orderRepository.Queryable()
-    //        .Where(m => m.Id == dto.Order.Id)
-    //        .Select(m => m.CallId)
-    //        .FirstAsync() ??
-    //        throw new UserFriendlyException($"订单Id:{dto.Order.Id} 的 CallId 为空");
-    //    var replyTxt = string.Empty;
-    //    RetryHelper.Retry(() =>
-    //    {
-    //        return false;
-    //    }, 5, 1000);
-    //}
-
-    /// <summary>
-    /// 如果有新的电话回复记录, 就更新回访记录
-    /// </summary>
-    /// <param name="callSatisfactions"></param>
-    /// <param name="cancellationToken"></param>
-    /// <returns></returns>
-    //[CapSubscribe(EventNames.HotlineCallSatisfactionAdd)]
-    //public async Task HotlineCallSatisfactionAdd(List<CallSatisfaction> callSatisfactions, CancellationToken cancellationToken)
-    //{
-    //    foreach (var callSatisfaction in callSatisfactions)
-    //    {
-    //        await _orderVisitRepository.UpdateVoiceReplyAsync(callSatisfaction, cancellationToken);
-    //    }
-    //}
-}

+ 174 - 100
src/Hotline.Application/Subscribers/InternalCapSubscriber.cs

@@ -1,6 +1,7 @@
 using DotNetCore.CAP;
 using Hotline.Application.Orders;
 using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Orders;
 using Hotline.Push;
@@ -18,6 +19,7 @@ using Hotline.Users;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
 using NPOI.SS.Formula.Functions;
 using StackExchange.Redis;
 using XF.Domain.Authentications;
@@ -39,8 +41,9 @@ namespace Hotline.Application.Subscribers
         private readonly IWorkflowDomainService _workflowDomainService;
         private readonly ICalcExpireTime _expireTime;
         private readonly IMapper _mapper;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
-		public InternalCapSubscriber(
+        public InternalCapSubscriber(
             IOrderRepository orderRepository,
             IMediator mediator,
             IRepository<User> userRepository,
@@ -52,7 +55,8 @@ namespace Hotline.Application.Subscribers
             IWorkflowDomainService workflowDomainService,
             ICalcExpireTime expireTime,
             IMapper mapper
-			)
+,
+            IOptionsSnapshot<AppConfiguration> appOptions)
         {
             _orderRepository = orderRepository;
             _mediator = mediator;
@@ -65,7 +69,8 @@ namespace Hotline.Application.Subscribers
             _workflowDomainService = workflowDomainService;
             _expireTime = expireTime;
             _mapper = mapper;
-		}
+            _appOptions = appOptions;
+        }
 
         /// <summary>
         /// 工单即将超期短信发送(延迟消息)
@@ -240,117 +245,186 @@ namespace Hotline.Application.Subscribers
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         [CapSubscribe(EventNames.HotlineOrderAutomaticDelay)]
-        public async Task AutomaticDelay(PublishAutomaticDelayDto dto, CancellationToken cancellationToken) 
+        public async Task AutomaticDelay(PublishAutomaticDelayDto dto, CancellationToken cancellationToken)
         {
             var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
             if (bool.Parse(enabled))
             {
-				var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-				var expiredTime = DateTime.Now.AddHours(2);
-				if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
-				{
-					if (order.ExpiredTime <= expiredTime)
-					{
-						var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
-						if (!delayAny)
-						{
-							var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.AutomaticDelayNum > 0).ToListAsync(cancellationToken);
-							var delay = new OrderDelay();
-							if (delays.Any())
-							{
-								delay = delays.First();
+                var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
+                var expiredTime = DateTime.Now.AddHours(2);
+                if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
+                {
+                    if (order.ExpiredTime <= expiredTime)
+                    {
+                        var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
+                        if (!delayAny)
+                        {
+                            var delays = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.AutomaticDelayNum > 0).ToListAsync(cancellationToken);
+                            var delay = new OrderDelay();
+                            if (delays.Any())
+                            {
+                                delay = delays.First();
                                 var startTime = DateTime.Now;
                                 if (order.CenterToOrgTime.HasValue)
                                 {
                                     startTime = order.CenterToOrgTime.Value;
                                 }
-								delay.AfterDelay = (await _expireTime
-									.CalcEndTime(delay.BeforeDelay.Value,startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
-								await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delay.AfterDelay })
-									.Where(x => x.Id == delay.Id).ExecuteCommandAsync(cancellationToken);
-							}
-							else
-							{
-								delay.OrderId = order.Id;
-								delay.EmployeeId = "";
-								delay.EmployeeName = "系统自动延期";
-								delay.ApplyOrgName = OrgSeedData.CenterName;
-								delay.ApplyOrgCode = OrgSeedData.CenterId;
-								delay.DelayApplyType = EDelayApplyType.LocalApply;
-								delay.BeforeDelay = order.ExpiredTime;
-								delay.DelayState = EDelayState.Pass;
-								delay.DelayReason = "系统自动延期";
-								delay.ApplyDelayTime = DateTime.Now;
-								delay.No = order.No;
-								delay.AutomaticDelayNum = 1;
-								delay.DelayNum = 1;
-								delay.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
-								delay.IsProDelay = false;
-								delay.CreatorOrgId = OrgSeedData.CenterId;
-								delay.CreatorOrgName = OrgSeedData.CenterName;
-								delay.CreatorName = "系统自动延期";
+                                var beforeDelay = DateTime.Now;
+                                if (!_appOptions.Value.IsYiBin)
+                                {
+                                    beforeDelay = order.ExpiredTime.Value;
+                                }
+                                delay.AfterDelay = (await _expireTime
+                                    .CalcEndTime(beforeDelay, startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+                                await _orderDelayRepository.Updateable().SetColumns(x => new OrderDelay() { AutomaticDelayNum = x.AutomaticDelayNum + 1, ApplyDelayTime = DateTime.Now, AfterDelay = delay.AfterDelay })
+                                    .Where(x => x.Id == delay.Id).ExecuteCommandAsync(cancellationToken);
+                            }
+                            else
+                            {
+                                delay.OrderId = order.Id;
+                                delay.EmployeeId = "";
+                                delay.EmployeeName = "系统自动延期";
+                                delay.ApplyOrgName = OrgSeedData.CenterName;
+                                delay.ApplyOrgCode = OrgSeedData.CenterId;
+                                delay.DelayApplyType = EDelayApplyType.LocalApply;
+                                delay.BeforeDelay = order.ExpiredTime;
+                                delay.DelayState = EDelayState.Pass;
+                                delay.DelayReason = "系统自动延期";
+                                delay.ApplyDelayTime = DateTime.Now;
+                                delay.No = order.No;
+                                delay.AutomaticDelayNum = 1;
+                                delay.DelayNum = 1;
+                                delay.DelayUnit = Share.Enums.Settings.ETimeType.WorkDay;
+                                delay.IsProDelay = false;
+                                delay.CreatorOrgId = OrgSeedData.CenterId;
+                                delay.CreatorOrgName = OrgSeedData.CenterName;
+                                delay.CreatorName = "系统自动延期";
                                 var startTime = DateTime.Now;
                                 if (order.CenterToOrgTime.HasValue)
                                 {
                                     startTime = order.CenterToOrgTime.Value;
                                 }
-								if (delay.BeforeDelay != null)
-								{
-									delay.AfterDelay = (await _expireTime
-										.CalcEndTime(delay.BeforeDelay.Value,startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
-								}
-								await _orderDelayRepository.AddAsync(delay, false, cancellationToken);
-							}
-							//处理工单延期
-							await _orderApplication.DelayOrderExpiredTimeAsync(order.Id, delay.DelayNum,
-								delay.DelayUnit, delay.IsProDelay, cancellationToken);
-							//发送短信
-							var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
-							var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
-							if (steps.Any())
-							{
-								foreach (var step in steps)
-								{
-									var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
-									var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
-									if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
-									{
-										roleIds.Add(step.RoleId);
-									}
-									var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
-									foreach (var user in userList)
-									{
-										if (!string.IsNullOrEmpty(user.PhoneNo))
-										{
-											//发送短信
-											var messageDto = new Share.Dtos.Push.MessageDto
-											{
-												PushBusiness = EPushBusiness.AutomaticDelay,
-												ExternalId = order.Id,
-												OrderId = order.Id,
-												PushPlatform = EPushPlatform.Sms,
-												Remark = order.Title,
-												Name = user.Name,
-												TemplateCode = "1015",
-												Params = new List<string>() { order.No },
-												TelNumber = user.PhoneNo,
-											};
-											await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
-										}
-									}
-								}
-							}
-						}
-					}
-					order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-					_capPublisher.PublishDelay(order.ExpiredTime.Value - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay, new PublishAutomaticDelayDto() { OrderId = order.Id });
-					var orderDto = _mapper.Map<OrderDto>(order);
-					await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
-						cancellationToken: cancellationToken);
-				}
-			}
-		
-		}
+                                if (delay.BeforeDelay != null)
+                                {
+                                    delay.AfterDelay = (await _expireTime
+                                        .CalcEndTime(delay.BeforeDelay.Value, startTime, delay.DelayUnit, delay.DelayNum, order.AcceptTypeCode))?.EndTime; //todo
+                                }
+                                await _orderDelayRepository.AddAsync(delay, false, cancellationToken);
+                            }
+                            //处理工单延期
+                            await _orderApplication.DelayOrderExpiredTimeAsync(order.Id, delay.DelayNum, delay.DelayUnit, delay.IsProDelay, cancellationToken);
+
+                            // 自贡任务 320调整“延期催办短信”发送的时间,将短信发送时间提前2个小时,所以拆分出去
+                            ////发送短信
+                            //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
+                            //var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
+                            //if (steps.Any())
+                            //{
+                            //	foreach (var step in steps)
+                            //	{
+                            //		var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
+                            //		var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
+                            //		if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
+                            //		{
+                            //			roleIds.Add(step.RoleId);
+                            //		}
+                            //		var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
+                            //		foreach (var user in userList)
+                            //		{
+                            //			if (!string.IsNullOrEmpty(user.PhoneNo))
+                            //			{
+                            //				//发送短信
+                            //				var messageDto = new Share.Dtos.Push.MessageDto
+                            //				{
+                            //					PushBusiness = EPushBusiness.AutomaticDelay,
+                            //					ExternalId = order.Id,
+                            //					OrderId = order.Id,
+                            //					PushPlatform = EPushPlatform.Sms,
+                            //					Remark = order.Title,
+                            //					Name = user.Name,
+                            //					TemplateCode = "1015",
+                            //					Params = new List<string>() { order.No },
+                            //					TelNumber = user.PhoneNo,
+                            //				};
+                            //				await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                            //			}
+                            //		}
+                            //	}
+                            //}
+                        }
+                    }
+                    order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
+                    _capPublisher.PublishDelay(order.ExpiredTime.Value - DateTime.Now.AddHours(1), EventNames.HotlineOrderAutomaticDelay, new PublishAutomaticDelayDto() { OrderId = order.Id });
+                    var orderDto = _mapper.Map<OrderDto>(order);
+                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
+                        cancellationToken: cancellationToken);
+                }
+            }
+
+        }
+
+        /// <summary>
+        /// 延期催办短信(延迟消息,自动延期前2小时发送)
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        [CapSubscribe(EventNames.HotlineOrderAutomaticSendSmsDelay)]
+        public async Task AutomaticDelaySendSms(PublishAutomaticDelayDto dto, CancellationToken cancellationToken)
+        {
+            var enabled = _systemSettingCacheManager.GetSetting(SettingConstants.EnabledAutomaticDelay)?.SettingValue[0];
+            if (bool.Parse(enabled))
+            {
+                var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
+                var expiredTime = DateTime.Now.AddHours(2);
+                if (order != null && order.Status < EOrderStatus.Filed && order.ExpiredTime >= DateTime.Now)
+                {
+                    if (order.ExpiredTime <= expiredTime)
+                    {
+                        var delayAny = await _orderDelayRepository.Queryable().Where(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining).AnyAsync();
+                        if (!delayAny)
+                        {
+                            //发送短信
+                            var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: cancellationToken);
+                            var steps = workflow.Steps.Where(x => x.Status == EWorkflowStepStatus.WaitForAccept || x.Status == EWorkflowStepStatus.WaitForHandle).ToList();
+                            if (steps.Any())
+                            {
+                                foreach (var step in steps)
+                                {
+                                    var setting = step.HandlerOrgId == OrgSeedData.CenterId ? SettingConstants.AutomaticDelayCenterRoles : SettingConstants.AutomaticDelayDepartmentRoles;
+                                    var roleIds = _systemSettingCacheManager.GetSetting(setting)?.SettingValue;
+                                    if (step.HandlerOrgId == OrgSeedData.CenterId && string.IsNullOrEmpty(step.RoleId))
+                                    {
+                                        roleIds.Add(step.RoleId);
+                                    }
+                                    var userList = await _userRepository.Queryable().Where(x => x.OrgId == step.HandlerOrgId && x.Roles.Any(r => roleIds.Contains(r.Name))).ToListAsync(cancellationToken);
+                                    foreach (var user in userList)
+                                    {
+                                        if (!string.IsNullOrEmpty(user.PhoneNo))
+                                        {
+                                            //发送短信
+                                            var messageDto = new Share.Dtos.Push.MessageDto
+                                            {
+                                                PushBusiness = EPushBusiness.AutomaticDelay,
+                                                ExternalId = order.Id,
+                                                OrderId = order.Id,
+                                                PushPlatform = EPushPlatform.Sms,
+                                                Remark = order.Title,
+                                                Name = user.Name,
+                                                TemplateCode = "1015",
+                                                Params = new List<string>() { order.No },
+                                                TelNumber = user.PhoneNo,
+                                            };
+                                            await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
         /// <summary>
         /// 批量发送短信

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

@@ -33,7 +33,7 @@ namespace Hotline.Share.Dtos.CallCenter
         /// <summary>
         /// 响应分机号
         /// </summary>
-        public string TelNo { get; set; }
+        public string? TelNo { get; set; }
 
         /// <summary>
         /// 挂断方

+ 10 - 0
src/Hotline.Share/Dtos/CallCenter/QueryCallsFixedDto.cs

@@ -66,5 +66,15 @@ namespace Hotline.Share.Dtos.CallCenter
         /// 3: 未接
         /// </summary>
         public int Type { get; set; }
+
+        /// <summary>
+        /// 排序字段
+        /// </summary>
+        public string? SortField { get; set; }
+
+        /// <summary>
+        /// 排序方式 0 升序 1 降序
+        /// </summary>
+        public int? SortRule { get; set; }
     }
 }

+ 140 - 0
src/Hotline.Share/Dtos/CallCenter/TelRestApplyAddDto.cs

@@ -0,0 +1,140 @@
+using Hotline.Share.Enums.CallCenter;
+using Hotline.Share.Requests;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Share.Dtos.CallCenter
+{
+    /// <summary>
+    /// 申请
+    /// </summary>
+    public class TelRestApplyAddDto
+    {
+        /// <summary>
+        /// 分机号(冗余)
+        /// </summary>
+        public string TelNo { get; set; }
+
+        /// <summary>
+        /// 小休原因
+        /// </summary>
+        public Kv Reason { get; set; }
+    }
+
+    /// <summary>
+    /// 审批
+    /// </summary>
+    public class TelRestApplyAuditDto
+    {
+        /// <summary>
+        /// 数据Id
+        /// </summary>
+        public List<string> Ids{ get; set; }
+
+        /// <summary>
+        /// 审批原因
+        /// </summary>
+        public string AuditOpinion { get; set; }
+
+        /// <summary>
+        /// 是否通过
+        /// </summary>
+        public bool IsPass { get; set; }
+    }
+
+    public record TelRestApplyRequestDto : PagedKeywordRequest
+    {
+        /// <summary>
+        /// 0:待审批  1:已审批
+        /// </summary>
+        public int Type { get; set; }
+
+        /// <summary>
+        /// 申请人
+        /// </summary>
+        public string ApplyUserName { get; set; }
+
+        /// <summary>
+        /// 申请时间
+        /// </summary>
+        public DateTime? ApplyStartTime { get; set; }
+        public DateTime? ApplyEndTime { get; set; }
+
+        /// <summary>
+        /// 小休原因
+        /// </summary>
+        public string ReasonId { get; set; }
+
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public ETelRestAuditStatus? AuditStatus { get; set; }
+
+        /// <summary>
+        /// 审核人
+        /// </summary>
+        public string? AuditUserName { get; set; }
+
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? AuditStartTime { get; set; }
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? AuditEndTime { get; set; }
+    }
+
+    /// <summary>
+    /// 列表数据
+    /// </summary>
+    public class TelRestApplyListDto
+    {
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 申请人
+        /// </summary>
+        public string ApplyUserName { get; set; }
+
+        /// <summary>
+        /// 申请时间
+        /// </summary>
+        public DateTime? ApplyTime { get; set; }
+
+        public string Reason { get; set; }
+
+        public string ReasonId { get; set; }
+
+        /// <summary>
+        /// 审核人
+        /// </summary>
+        public string? AuditUserName { get; set; }
+        public string? AuditUserId { get; set; }
+
+        /// <summary>
+        /// 审核部门
+        /// </summary>
+        public string? AuditOrgName { get; set; }
+        public string? AuditOrgId { get; set; }
+
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? AuditTime { get; set; }
+
+        /// <summary>
+        /// 审核意见
+        /// </summary>
+        public string? AuditOpinion { get; set; }
+
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public ETelRestAuditStatus AuditStatus { get; set; }
+
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public string AuditStatusText => AuditStatus.GetDescription();
+    }
+}

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

@@ -38,6 +38,8 @@ namespace Hotline.Share.Dtos.Order
 		/// 启禁用
 		/// </summary>
 		public int IsEnable { get; set; }
+
+		public string IsEnableText => IsEnable == 1 ? "启用" : "禁用";
 	}
 
 	public class OrderWordAddDto

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

@@ -161,6 +161,10 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool? IsProvinceOrder { get; set; }
 
+        /// <summary>
+        /// 是否省综合查询
+        /// </summary>
+        public bool? ProvinceSearch { get; set; }
 
         /// <summary>
         /// 是否敏感词

+ 13 - 0
src/Hotline.Share/Dtos/WebPortal/ArticleDetailsDto.cs

@@ -365,4 +365,17 @@ namespace Hotline.Share.Dtos.WebPortal
         /// </summary>
         public IReadOnlyList<FullTextSearchListDto> data { get; set; }
     }
+
+    public class DateDto
+    {
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public DateTime StartTime { get; set; }
+
+        /// <summary>
+        /// /结束时间
+        /// </summary>
+        public DateTime EndTime { get; set; }
+    }
 }

+ 98 - 0
src/Hotline.Share/Dtos/WebPortal/GetOrderCodePwd.cs

@@ -535,4 +535,102 @@ namespace Hotline.Share.Dtos.WebPortal
         public string? path { get; set; }
     }
 
+    /// <summary>
+    /// 工单信息
+    /// </summary>
+    public class OrderResultDto
+    {
+        /// <summary>
+        /// 工单唯一标识
+        /// </summary>
+        public string? Id { get; set; }
+
+        /// <summary>
+        /// 办件编号
+        /// </summary>
+        public string? No { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 工单内容
+        /// </summary>
+        public string? Content { get; set; }
+
+        /// <summary>
+        /// 受理部门(实际办理部门)
+        /// </summary>
+        public string? ActualHandleOrgName { get; set; }
+
+        /// <summary>
+        /// 工单提交(申报)时间(受理时间)
+        /// </summary>
+        public DateTime? CreationTime { get; set; }
+
+        /// <summary>
+        /// 提交人姓名(来电人姓名)
+        /// </summary>
+        public string? FromName { get; set; }
+
+        /// <summary>
+        /// 手机号(来电号码 FromPhone 联系电话 Contact)
+        /// </summary>
+        public string? FromPhone { get; set; }
+    }
+
+    /// <summary>
+    /// 评价信息
+    /// </summary>
+    public class VisitResultDto
+    {
+        /// <summary>
+        /// 工单唯一标识
+        /// </summary>
+        public string? OrderID { get; set; }
+
+        /// <summary>
+        /// 评价满意度(评分)
+        /// </summary>
+        public Kv? NowEvaluate { get; set; }
+
+        /// <summary>
+        /// 评价描述
+        /// </summary>
+        public string? VisitContent { get; set; }
+
+        /// <summary>
+        /// 评价时间
+        /// </summary>
+        public string? VisitTime { get; set; }
+
+        /// <summary>
+        /// 评价人
+        /// </summary>
+        public string? VisitName { get; set; }
+
+        /// <summary>
+        /// 是否公开
+        /// </summary>
+        public bool PublishState { get; set; } = false;
+    }
+
+    /// <summary>
+    /// 账号信息
+    /// </summary>
+    public class UserResultDto
+    {
+        /// <summary>
+        /// 账号信息:uuid(用户唯一标识)
+        /// </summary>
+        public string? UUID { get; set; }
+
+        /// <summary>
+        /// 用户名
+        /// </summary>
+        public string? Name { get; set; }
+    }
+
 }

+ 28 - 0
src/Hotline.Share/Enums/CallCenter/ETelRestAuditStatus.cs

@@ -0,0 +1,28 @@
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.CallCenter
+{
+    public enum ETelRestAuditStatus
+    {
+        /// <summary>
+        /// 待审核
+        /// </summary>
+        [Description("待审核")]
+        NoAudit = 0,
+        /// <summary>
+        /// 审核通过
+        /// </summary>
+        [Description("审核通过")]
+        Pass = 1,
+        /// <summary>
+        /// 审核不通过
+        /// </summary>
+        [Description("审核不通过")]
+        NoPass = 2,
+        /// <summary>
+        /// 撤销
+        /// </summary>
+        [Description("撤销")]
+        Revoke = 3,
+    }
+}

+ 3 - 0
src/Hotline.Share/Enums/Push/EPushBusiness.cs

@@ -90,4 +90,7 @@ public enum EPushBusiness
 
     [Description("甄别完成")]
     ScreenEnd=14,
+
+    [Description("不满意甄别短信")]
+    DissatisfiedScreen = 15,
 }

+ 10 - 5
src/Hotline.Share/Mq/EventNames.Order.cs

@@ -133,10 +133,15 @@ namespace Hotline.Share.Mq
         /// </summary>
         public const string HotlineBatchSmsTask = "hotline.order.batchsmstask";
 
-		/// <summary>
-		/// 自动延期(延迟消息)
-		/// </summary>
-		public const string HotlineOrderAutomaticDelay = "hotline.order.automatic.Delay";
+        /// <summary>
+        /// 自动延期(延迟消息)
+        /// </summary>
+        public const string HotlineOrderAutomaticDelay = "hotline.order.automatic.Delay";
+
+        /// <summary>
+        /// 延期催办短信(延迟消息,自动延期前2小时发送)
+        /// </summary>
+        public const string HotlineOrderAutomaticSendSmsDelay = "hotline.order.automatic.send.sms.Delay";
 
         /// <summary>
         /// 领导通知短信
@@ -146,5 +151,5 @@ namespace Hotline.Share.Mq
         #endregion
 
 
-	}
+    }
 }

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

@@ -110,5 +110,7 @@ namespace Hotline.Caching.Interfaces
         /// 是否不推送呼出的无文件的通话记录
         /// </summary>
         bool IsNoPushCallNativeOutNoFile { get; }
+
+        bool IsSendDissatisfiedScreenSms { get; }
     }
 }

+ 4 - 2
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -41,7 +41,7 @@ namespace Hotline.Caching.Services
             _cacheSystemSetting.Remove(code);
         }
 
-        public T GetOrDefault<T>(string? id, string code, string name, T defaultValue, string remark) 
+        public T GetOrDefault<T>(string? id, string code, string name, T defaultValue, string remark)
         {
             var value = defaultValue.ToString();
             try
@@ -109,7 +109,7 @@ namespace Hotline.Caching.Services
         /// 保存回访详情时发送延迟消息同步通话记录
         /// 如果回访通话记录有多条, 需要关联通话时长最长的那条
         /// </summary>
-        public int VisitCallDelaySecond => 
+        public int VisitCallDelaySecond =>
             GetOrDefault(null, SettingConstants.VisitCallDelaySecond, "回访通话记录同步延时时间(秒)", 60, "保存回访详情时发送延迟消息同步通话记录,如果回访通话记录有多条, 需要关联通话时长最长的那条");
 
         public bool AutomaticPublishOrder =>
@@ -209,5 +209,7 @@ namespace Hotline.Caching.Services
         /// 是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)
         /// </summary>
         public bool IsNoPushCallNativeOutNoFile => GetOrDefault("08dd23d1-5c5b-4262-8c99-8c83710723ea", SettingConstants.IsNoPushCallNativeOutNoFile, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)", true, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)");
+
+        public bool IsSendDissatisfiedScreenSms => GetOrDefault("08db29ad-9b54-44ca-8d4d-35c032748040", SettingConstants.IsSendDissatisfiedScreenSms, "回访不满意是否发送甄别短信", true, "true:发送;false:不发送");
     }
 }

+ 49 - 6
src/Hotline/CallCenter/Tels/TelRestApply.cs

@@ -1,13 +1,56 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Hotline.Share.Enums.CallCenter;
+using SqlSugar;
 using XF.Domain.Repository;
 
 namespace Hotline.CallCenter.Tels
 {
-    public class TelRestApply: PositionWorkflowEntity
+    public class TelRestApply : CreationEntity
     {
+        /// <summary>
+        /// 分机id
+        /// </summary>
+        public string? TelId { get; set; }
+
+        /// <summary>
+        /// 分机号(冗余)
+        /// </summary>
+        public string TelNo { get; set; }
+
+        public string Reason { get; set; }
+
+        public string ReasonId { get; set; }
+
+        /// <summary>
+        /// 审核人
+        /// </summary>
+        public string? AuditUserName { get; set; }
+        public string? AuditUserId { get; set; }
+
+        /// <summary>
+        /// 审核部门
+        /// </summary>
+        public string? AuditOrgName { get; set; }
+        public string? AuditOrgId { get; set; }
+
+        /// <summary>
+        /// 审核时间
+        /// </summary>
+        public DateTime? AuditTime { get; set; }
+
+        /// <summary>
+        /// 审核意见
+        /// </summary>
+        [SugarColumn(ColumnDescription = "审核意见", ColumnDataType = "varchar(2000)")]
+        public string? AuditOpinion { get; set; }
+
+        /// <summary>
+        /// 审核状态
+        /// </summary>
+        public ETelRestAuditStatus AuditStatus { get; set; }
+
+        /// <summary>
+        /// 工号(冗余)
+        /// </summary>
+        public string? StaffNo { get; set; }
     }
 }

+ 12 - 10
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -981,12 +981,6 @@ namespace Hotline.FlowEngine.Workflows
             //        prevStep.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Org;
             //}
 
-            //甄别退回到最开始节点到部门 todo 重构放在调用处判断
-            if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
-            {
-                prevStep.FlowAssignType = prevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
-            }
-
             // dto.ReverseFlowStepAssignInfo ??= new ReverseFlowStepAssignInfo(EReverseFlowStepCreationPolicy.OriginStepUser);
             // //todo
             // var stepAssignInfo = GetStepAssignInfo(dto.ReverseFlowStepAssignInfo, prevStep, prevStepDefine);
@@ -995,8 +989,14 @@ namespace Hotline.FlowEngine.Workflows
             //复制上一个节点为待接办
             var newPrevStep = DuplicateStep(workflow, prevStepDefine, prevStep, EWorkflowTraceType.Previous, dto.ExpiredTime);
             newPrevStep.Assign(prevStep, EFlowAssignType.User);
-            //退给派单组节点,需按照平均分配原则派给一个派单员 禅道299 TODO
-            if (dto.Handler != null) //todo 改为按策略判断
+
+			//甄别退回到最开始节点到部门 todo 重构放在调用处判断  
+			if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
+			{
+				newPrevStep.FlowAssignType = newPrevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
+			}
+			//退给派单组节点,需按照平均分配原则派给一个派单员 禅道299 TODO
+			if (dto.Handler != null) //todo 改为按策略判断
             {
                 var handle = dto.Handler;
                 newPrevStep.Assign(handle.UserId, handle.Username, handle.OrgId, handle.OrgName, handle.RoleId, handle.RoleName);
@@ -1728,7 +1728,8 @@ namespace Hotline.FlowEngine.Workflows
                 //     stepAssignInfo, traceType, expiredTime, stepConfig, cancellationToken);
 
                 targetStepNew = CreateStartStep(workflow, targetStepDefine, dto, assigner, stepAssignInfo, expiredTime);
-                await Task.Run(() => newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew), cancellationToken);
+                //await Task.Run(() => newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew), cancellationToken);
+                newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew);
                 await _workflowStepRepository.AddAsync(targetStepNew, cancellationToken);
                 workflow.Steps.Add(targetStepNew);
                 await CreateTraceAsync(workflow, targetStepNew, traceType, cancellationToken);
@@ -1742,7 +1743,8 @@ namespace Hotline.FlowEngine.Workflows
                 targetStepNew = CreateStep(workflow, targetStepDefine, targetPrevStep, stepAssignInfo, assigner,
                     dto.NextStepCode, null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, expiredTime,
                     dto.NextStepName, true, true, null, dto.BusinessType, dto.FlowDirection);
-                await Task.Run(() => newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew), cancellationToken);
+                //await Task.Run(() => newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew), cancellationToken);
+                newStepConfig?.Invoke(workflow, currentStep, targetStepDefine, targetStep, targetStepNew);
                 await _workflowStepRepository.AddAsync(targetStepNew, cancellationToken);
                 workflow.Steps.Add(targetStepNew);
                 await CreateTraceAsync(workflow, targetStepNew, traceType, cancellationToken);

+ 12 - 2
src/Hotline/Orders/OrderVisitDomainService.cs

@@ -17,6 +17,10 @@ using Microsoft.Extensions.Options;
 using Hotline.Settings;
 using System.Text.RegularExpressions;
 using System.Threading;
+using Hotline.Caching.Services;
+using Hotline.Push.Notifies;
+using Hotline.Share.Enums.Push;
+using MediatR;
 
 namespace Hotline.Orders;
 public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependency
@@ -32,6 +36,8 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
     private readonly ISettingOrderVisitSmsReplyRuleRepository _settingOrderVisitSmsReplyRuleRepository;
     private readonly ISystemLogRepository _logRepository;
     private readonly IRepository<OrderVisitRecord> _orderVisitRecordRepository;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+    private readonly IMediator _mediator;
 
     public OrderVisitDomainService(IRepository<OrderVisitDetail> orderVisitDetailRepository,
         ILogger<OrderVisitDomainService> logger,
@@ -42,7 +48,9 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
         IOptionsSnapshot<AppConfiguration> appOptions,
         ISettingOrderVisitSmsReplyRuleRepository settingOrderVisitSmsReplyRuleRepository,
         ISystemLogRepository logRepository,
-        IRepository<OrderVisitRecord> orderVisitRecordRepository)
+        IRepository<OrderVisitRecord> orderVisitRecordRepository,
+        ISystemSettingCacheManager systemSettingCacheManager,
+        IMediator mediator)
     {
         _orderVisitDetailRepository = orderVisitDetailRepository;
         _logger = logger;
@@ -55,6 +63,8 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
         _settingOrderVisitSmsReplyRuleRepository = settingOrderVisitSmsReplyRuleRepository;
         _logRepository = logRepository;
         _orderVisitRecordRepository = orderVisitRecordRepository;
+        _systemSettingCacheManager = systemSettingCacheManager;
+        _mediator = mediator;
     }
 
     /// <summary>
@@ -214,9 +224,9 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
                     ClientGuid = ""
                 }, cancellationToken: CancellationToken.None);
 
-            //回访成功后,写入回访记录信息
             if (_appOptions.Value.IsZiGong == true)
             {
+                //回访成功后,写入回访记录信息
                 await _orderVisitRecordRepository.AddAsync(new()
                 {
                     No = orderVisit.No,

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

@@ -738,5 +738,10 @@ namespace Hotline.Settings
         /// 是否开启特殊号码功能
         /// </summary>
         public const string IsOpenSpecialPhone = "IsOpenSpecialPhone";
+
+        /// <summary>
+        /// 回访不满意是否发送甄别短信
+        /// </summary>
+        public const string IsSendDissatisfiedScreenSms = "IsSendDissatisfiedScreenSms";
     }
 }

+ 5 - 5
src/Hotline/Snapshot/ThirdAccount.cs

@@ -77,11 +77,11 @@ public class ThirdAccount : CreationSoftDeleteEntity
     [SugarColumn(ColumnDescription = "用户昵称")]
     public string? UserName { get; set; }
 
-    /// <summary>
-    /// 应用类型
-    /// </summary>
-    [SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
-    public EAppType AppType { get; set; }
+    ///// <summary>
+    ///// 应用类型
+    ///// </summary>
+    //[SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
+    //public EAppType AppType { get; set; }
 }
 
 public enum EAppType

+ 29 - 6
src/Hotline/dataview.md

@@ -581,7 +581,10 @@ SELECT  to_char("CreatedTime",'yyyy-MM-dd') AS "Date" ,
 
 
  ### 更新部门名称后执行
- --更新回访明细
+select * from system_organize WHERE "Name" like '%珙县%'
+--001023 珙县智慧信息服务中心
+
+--更新回访明细
 select * from order_visit_detail WHERE "VisitOrgCode"='001023';
 --update order_visit_detail set "VisitOrgName"='珙县智慧信息服务中心' where  "VisitOrgCode"='001023';
 
@@ -671,7 +674,7 @@ select * from order_special where "OrgId"='001023';
 
 --更新特提创建部门
 select * from order_special where "CreatorOrgId"='001023';
---update order_special SET "CreatorOrgName"='珙县智慧信息服务中心'  WHERE "OrgId"='001023';
+--update order_special SET "CreatorOrgName"='珙县智慧信息服务中心'  WHERE "CreatorOrgId"='001023';
 
 --更新特提明细申请部门
 select * from order_special_detail where "OrgId"='001023';
@@ -682,9 +685,29 @@ select * from order_special_detail WHERE "CreatorOrgId"='001023';
 --update order_special_detail SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
 
 --更新知识库创建部门
-select * from knowledge limit 10 where "CreatorOrgId"='001023'
---update knowledge SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023'
+select * from knowledge limit 10 where "CreatorOrgId"='001023';
+--update knowledge SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
 
 --更新知识库关联部门
-select * from knowledge_type_org where "OrgId"='001023'
---update knowledge_type_org set "OrgName"='珙县智慧信息服务中心' WHERE "OrgId"='001023'
+select * from knowledge_type_org where "OrgId"='001023';
+--update knowledge_type_org set "OrgName"='珙县智慧信息服务中心' WHERE "OrgId"='001023';
+
+--更新二次办理申请申请部门
+select * from order_secondary_handling  where "ApplyOrgId"='001023';
+--update order_secondary_handling SET "ApplyOrgName"='珙县智慧信息服务中心' where "ApplyOrgId"='001023';
+
+--更新二次办理申请创建部门
+select * from order_secondary_handling WHERE "CreatorOrgId"='001023';
+--update order_secondary_handling SET "CreatorOrgName"='珙县智慧信息服务中心' WHERE "CreatorOrgId"='001023';
+
+--更新退回申请申请部门
+select * from order_send_back_audit  where "ApplyOrgId"='001023';
+--update order_send_back_audit SET "ApplyOrgName"='珙县智慧信息服务中心' where "ApplyOrgId"='001023';
+
+--更新退回申请退回部门
+select * from order_send_back_audit WHERE "SendBackOrgId"='001023';
+--update order_send_back_audit SET "SendBackOrgName"='珙县智慧信息服务中心' where "SendBackOrgId"='001023';
+
+--更新退回申请创建部门
+select * from order_send_back_audit WHERE "CreatorOrgId"='001023';
+--update order_send_back_audit SET "CreatorOrgName"='珙县智慧信息服务中心' WHERE "CreatorOrgId"='001023';

+ 1 - 1
src/XingTang.Sdk/XingtangSatisfaction.cs

@@ -22,7 +22,7 @@ namespace XingTang.Sdk
         /// <summary>
         /// 评价结果
         /// </summary>
-        public string Result { get; set; }
+        public int Result { get; set; }
 
 
         #region 自建

+ 12 - 1
test/Hotline.Tests/Application/XingTangCallsSyncJobTest.cs

@@ -11,12 +11,14 @@ public class XingTangCallsSyncJobTest
     private readonly XingTangCallsSyncJob xingTangCallsSyncJob;
     private readonly ISqlSugarClient _db;
     private readonly IFixture _fixture;
+    private readonly XingTangCallSatisfactionSyncJob _xingTangCallSatisfactionSyncJob;
 
-    public XingTangCallsSyncJobTest(XingTangCallsSyncJob xingTangCallsSyncJob, ISugarUnitOfWork<XingTangDbContext> uow)
+    public XingTangCallsSyncJobTest(XingTangCallsSyncJob xingTangCallsSyncJob, ISugarUnitOfWork<XingTangDbContext> uow, XingTangCallSatisfactionSyncJob xingTangCallSatisfactionSyncJob)
     {
         this.xingTangCallsSyncJob = xingTangCallsSyncJob;
         _db = uow.Db;
         _fixture = new Fixture();
+        _xingTangCallSatisfactionSyncJob = xingTangCallSatisfactionSyncJob;
     }
 
     [Fact]
@@ -29,6 +31,7 @@ public class XingTangCallsSyncJobTest
         inDto.Tries = 0;
         inDto.CallGuid = DateTime.Now.ToString("yyyyMMddhhmmss") + "FLOW";
         inDto.Ver = string.Empty;
+        inDto.CustomerId = string.Empty;
         inDto.Id = new Random().Next(0, 100000);
 
         var inDto2 = _fixture.Create<XingtangCall>();
@@ -37,12 +40,20 @@ public class XingTangCallsSyncJobTest
         inDto2.IsSync = false;
         inDto2.Tries = 0;
         inDto2.Ver = string.Empty;
+        inDto2.CustomerId = string.Empty;
         inDto2.Id = new Random().Next(0, 100000);
 
         await _db.Insertable(inDto).ExecuteCommandAsync();
         await _db.Insertable(inDto2).ExecuteCommandAsync();
 
         await xingTangCallsSyncJob.Execute(new JobContext());
+        var s1 = _fixture.Create<XingtangSatisfaction>();
+        s1.CallNo = inDto.CallGuid;
+        s1.Result = new Random().Next(1, 5);
+        s1.IsSync = false;
+        s1.Tries = 0;
+        await _db.Insertable(s1).ExecuteCommandAsync();
+        await _xingTangCallSatisfactionSyncJob.Execute(new JobContext());
     }
 }
 

+ 2 - 1
test/Hotline.Tests/Startup.cs

@@ -175,9 +175,10 @@ public class Startup
             services.AddScoped<XingTangCallApplication>();
             services.AddScoped<OrderServiceMock>();
             services.AddScoped<KnowledgeServiceMock>();
+            services.AddXingTangDb(callCenterConfiguration.XingTang);
             services.AddScoped<XingTangCallsSyncJob>();
+            services.AddScoped<XingTangCallSatisfactionSyncJob>();
             services.AddScoped<IFileDomainService, FileDomainService>();
-            services.AddXingTangDb(callCenterConfiguration.XingTang);
             services.AddScoped<IGuiderSystemService, TiqnQueService>();
             services.AddScoped<IWorkflowDomainService, WorkflowDomainService>();