Explorar o código

Merge branch 'test' into lib/test

libin hai 1 mes
pai
achega
6e181015e8

+ 1 - 0
.gitignore

@@ -346,3 +346,4 @@ ASALocalRun/
 healthchecksdb
 /merge.ps1
 /merge_245_test.ps1
+/merge_dev.ps1

+ 35 - 24
src/Hotline.Api/Controllers/OrderController.cs

@@ -2055,12 +2055,14 @@ public class OrderController : BaseController
             }
             else if (_appOptions.Value.IsLuZhou)
             {
-                throw UserFriendlyException.SameMessage("请在期满时间内申请延期!");
+                throw UserFriendlyException.SameMessage("已经超期的工单无法发起延期申请!");
             }
         }
 
-        //验证延期次数
-        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
+		if (_appOptions.Value.IsLuZhou && delaydto.DelayNum > order.TimeLimitCount) throw UserFriendlyException.SameMessage("申请天数需小于等于工单办理时限!");
+
+		//验证延期次数
+		var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum);
         if (int.Parse(setting?.SettingValue[0]) != 0 && !_sessionContext.OrgIsCenter)
         {
             int count = await _orderDelayRepository.CountAsync(x =>
@@ -2099,7 +2101,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;
@@ -3660,13 +3662,13 @@ public class OrderController : BaseController
         }
 
         var (total, items) = await query
-            .Includes(x => x.OrderScreens)
+            .Includes(d => d.OrderScreens)
             .Where(d => d.Contact == dto.PhoneNo)
             .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
-            .Select(m => new OrderHistoryOutDto
+            .Select(d => new OrderHistoryOutDto
             {
-                IsScreen = m.OrderScreens.Any(x => x.Status == EScreenStatus.End),
+                IsScreen = d.OrderScreens.Any(x => x.Status == EScreenStatus.End),
             }, true)
             .OrderByDescending(d => d.CreationTime)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
@@ -4629,7 +4631,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);
                 }
@@ -6388,7 +6390,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
@@ -6398,19 +6399,29 @@ public class OrderController : BaseController
             if (dto.AlterTime)
             {
                 DateTime startTime = DateTime.Now;
-                if (order.CenterToOrgTime.HasValue && order.ProcessType == EProcessType.Jiaoban)
+                DateTime beginTime = DateTime.Now;
+
+				if (order.CenterToOrgTime.HasValue && order.FileOrgIsCenter.HasValue &&  !order.FileOrgIsCenter.Value)
                 {
                     startTime = order.CenterToOrgTime.Value;
                 }
-                else if (order.ProcessType == EProcessType.Zhiban)
+                else if (order.FileOrgIsCenter.HasValue && order.FileOrgIsCenter.Value)
                 {
                     startTime = order.StartTime.Value;
                 }
 
-                //var expiredTime = await _expireTime.CalcEndTime(
-                //    DateTime.Now, startTime, ETimeType.WorkDay,
-                //    dto.TimeLimit.Value, order.AcceptTypeCode);
-                var expiredTime = await _expireTime.CalcEndTime(DateTime.Now, startTime, order.AcceptTypeCode);
+                if (_appOptions.Value.IsLuZhou)
+                {
+                    startTime = order.ExpiredTime.Value;
+                    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(beginTime, startTime, config, order.AcceptTypeCode);
+                }
 
                 //if (expiredTime.EndTime < order.ExpiredTime.Value)
                 //{
@@ -6440,15 +6451,15 @@ public class OrderController : BaseController
                 }
             }
 
-            // if (dto.BusinessType == EBusinessType.Send && recall.NextHandlers.Any())
-            // {
-            //     var flowStepHandler = recall.NextHandlers.FirstOrDefault();
-            //     await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-            //             { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username })
-            //         .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
-            // }
-
-            var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) =
+			// if (dto.BusinessType == EBusinessType.Send && recall.NextHandlers.Any())
+			// {
+			//     var flowStepHandler = recall.NextHandlers.FirstOrDefault();
+			//     await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
+			//             { 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,

+ 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);
         }
 

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

@@ -0,0 +1,166 @@
+using Hotline.Application.CallCenter;
+using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.Tels;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Settings;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.CallCenter;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.CallCenter;
+using Hotline.Tools;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+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;
+
+        public TelRestController(ISystemDicDataCacheManager systemDicDataCacheManager,
+             IRepository<TelRestApply> telRestApplyRepository,
+              IPbxApplication pbxApplication,
+              ISessionContext sessionContext,
+              ITelDomainService telDomainService,
+              IMapper mapper)
+        {
+            _systemDicDataCacheManager = systemDicDataCacheManager;
+            _telRestApplyRepository = telRestApplyRepository;
+            _pbxApplication = pbxApplication;
+            _sessionContext = sessionContext;
+            _telDomainService = telDomainService;
+            _mapper = mapper;
+        }
+
+        #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 AddTelRest([FromBody] TelRestApplyAddDto dto)
+        {
+            if (string.IsNullOrEmpty(dto.TelNo))
+                throw new UserFriendlyException("分机号不能为空!");
+            if (dto.Reason == null)
+                throw new UserFriendlyException("小休原因不能为空!");
+
+            var data = await _telRestApplyRepository.GetAsync(p => p.TelNo == dto.TelNo && p.CreatorId == _sessionContext.RequiredUserId &&
+            p.AuditStatus == ETelRestAuditStatus.NoAudit, HttpContext.RequestAborted);
+            if (data != null)
+                throw new UserFriendlyException("小休申请审批中,暂时无法操作!");
+
+            TelRestApply telRestApply = new()
+            {
+                TelNo = dto.TelNo,
+                Reason = dto.Reason.Value,
+                ReasonId = dto.Reason.Key,
+                StaffNo = _sessionContext.StaffNo,
+                AuditStatus = ETelRestAuditStatus.NoAudit
+            };
+            await _telRestApplyRepository.AddAsync(telRestApply, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 小休审批
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        /// <exception cref="UserFriendlyException"></exception>
+        [HttpPost("telrest_apply_audit")]
+        public async Task TelRestApplyAudit([FromBody] TelRestApplyAuditDto dto)
+        {
+            if (dto.IsPass == false && string.IsNullOrEmpty(dto.AuditOpinion))
+                throw new UserFriendlyException("审批原因不能为空!");
+            var data = await _telRestApplyRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+            if (data == null)
+                throw new UserFriendlyException("审批数据查询失败!");
+            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);
+            if (dto.IsPass)
+            {
+                //审批通过发送通知给前端
+                await _telDomainService.TelRestApplyPassAsync(data.CreatorId, HttpContext.RequestAborted);
+            }
+        }
+
+        /// <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
+    }
+}

+ 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);
+    }
+}

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

@@ -0,0 +1,59 @@
+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)
+                .Select(p => new TelRestApplyListDto
+                {
+                    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;
+        }
+    }
+}

+ 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

+ 16 - 4
src/Hotline.Application/Orders/OrderApplication.cs

@@ -1184,6 +1184,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,
@@ -1217,6 +1221,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 });
             }
@@ -1236,6 +1244,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 });
                 }
@@ -1599,8 +1611,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)
@@ -1621,8 +1634,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) //工单编号降序

+ 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>
         /// 批量发送短信

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

@@ -0,0 +1,138 @@
+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 string Id { 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
+    {
+        /// <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();
+    }
+}

+ 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>
         /// 是否敏感词

+ 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,
+    }
+}

+ 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
 
 
-	}
+    }
 }

+ 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; }
     }
 }

+ 2 - 2
src/Hotline/FlowEngine/Definitions/StepDefine.cs

@@ -11,9 +11,9 @@ public class StepDefine : StepDefineBasic
 {
     #region method
 
-    public bool IsCenter() => BusinessType is EBusinessType.Seat or EBusinessType.Send;
+    public bool IsCenter() => BusinessType is EBusinessType.Seat or EBusinessType.Send or EBusinessType.CenterLeader or EBusinessType.CenterMonitor;
 
-    public bool IsOrg() => BusinessType is EBusinessType.Department;
+    public bool IsOrg() => BusinessType is EBusinessType.Department or EBusinessType.DepartmentLeader;
 
     #endregion
 }

+ 14 - 0
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -322,6 +322,20 @@ namespace Hotline.FlowEngine.Workflows
             }
             else
             {
+                //if dto.NextStepCode is empty, find nextCode, but if not only one throw it
+                if (string.IsNullOrEmpty(dto.NextStepCode))
+                {
+                    if (currentStepDefine?.NextSteps?.Count == 0)
+                        throw new UserFriendlyException(
+                            $"未选择下一办理节点且未配置下一节点, workflowId: {workflow.Id}, stepDefineName: {currentStepDefine.Name}",
+                            "未选择下一办理节点");
+                    if (currentStepDefine?.NextSteps?.Count > 1)
+                        throw new UserFriendlyException(
+                            $"未选择下一办理节点且配置有多个节点, workflowId: {workflow.Id}, stepDefineName: {currentStepDefine.Name}",
+                            "未选择下一办理节点且配置有多个节点");
+                    dto.NextStepCode = currentStepDefine.NextSteps.First().Code;
+                }
+
                 //下一步配置为下一步节点配置
                 nextStepDefine = GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
             }

+ 2 - 2
src/Hotline/Orders/DatabaseEventHandler/OrderVisitDetailEventHandler.cs

@@ -54,7 +54,7 @@ public class OrderVisitDetailEventHandler : IUpdateDatabaseEvent<OrderVisitDetai
            
             _orderRepository.Updateable()
                 .SetColumns(m => m.OrgProcessingResults == visit.OrgProcessingResults)
-                .Where(m => m.Id == orderId.OrderId && m.Status == EOrderStatus.Visited)
+                .Where(m => m.Id == orderId.OrderId && m.Status >= EOrderStatus.Published)
                 .ExecuteCommand();
             _systemLogRepository.Add(name, $"OrgProcessingResults: {visit.OrgProcessingResults.ToJson()}", orderId.No, orderId.No, 1);
         }
@@ -70,7 +70,7 @@ public class OrderVisitDetailEventHandler : IUpdateDatabaseEvent<OrderVisitDetai
            
             _orderRepository.Updateable()
                 .SetColumns(m => m.SeatEvaluate == visit.SeatEvaluate)
-                .Where(m => m.Id == orderId.OrderId && m.Status == EOrderStatus.Visited)
+                .Where(m => m.Id == orderId.OrderId && m.Status >= EOrderStatus.Published)
                 .ExecuteCommand();
             _systemLogRepository.Add(name, $"SeatEvaluate: {visit.SeatEvaluate}",orderId.No, orderId.No, 1);
         }

+ 24 - 0
src/Hotline/Snapshot/ThirdAccount.cs

@@ -76,4 +76,28 @@ public class ThirdAccount : CreationSoftDeleteEntity
     /// </summary>
     [SugarColumn(ColumnDescription = "用户昵称")]
     public string? UserName { get; set; }
+
+    /// <summary>
+    /// 应用类型
+    /// </summary>
+    [SugarColumn(ColumnDescription = "应用类型", DefaultValue = "1")]
+    public EAppType AppType { get; set; }
+}
+
+public enum EAppType
+{
+    /// <summary>
+    /// 随手拍
+    /// </summary>
+    Snapshot = 1,
+
+    /// <summary>
+    /// 部门办件app
+    /// </summary>
+    Department = 2,
+
+    /// <summary>
+    /// 市民办件app
+    /// </summary>
+    Citizen = 3
 }

+ 135 - 1
src/Hotline/dataview.md

@@ -576,4 +576,138 @@ SELECT  to_char("CreatedTime",'yyyy-MM-dd') AS "Date" ,
  SUM(( CASE  WHEN (SUBSTRING("IvrDtmf",1 + (LENGTH("IvrDtmf")- 1 ),1) = N'2' )  AND ( "OnState" = 2 ) THEN 1  ELSE 0 END )) AS "EnterpriseRingOffCount" , 
  SUM(( CASE  WHEN (SUBSTRING("IvrDtmf",1 + (LENGth("IvrDtmf")- 1 ),1) = N'3' ) and "Gateway"<>'82826886' AND ( "OnState" = 2 ) THEN 1 ELSE 0 END)) as "高效挂断",
  SUM(( CASE  WHEN (((( "BeginIvrTime" IS NOT NULL ) AND NOT( "BeginQueueTime" IS NOT NULL )) AND NOT( "BeginRingTime" IS NOT NULL )) AND ( "OnState" = 2 )) THEN 1  ELSE 0 END )) AS "IvrRingOffCount"  FROM "tr_call_record" 
- WHERE (((( "CreatedTime" >= '2024-07-01 00:00:00.000' ) AND ( "CreatedTime" <= '2024-12-31 23:59:59.000' )) AND (LENGTH("Gateway") > 4 )) AND ( "CallDirection" = 0 ))GROUP BY to_char("CreatedTime",'yyyy-MM-dd') ORDER BY "Date"))
+ WHERE (((( "CreatedTime" >= '2024-07-01 00:00:00.000' ) AND ( "CreatedTime" <= '2024-12-31 23:59:59.000' )) AND (LENGTH("Gateway") > 4 )) AND ( "CallDirection" = 0 ))GROUP BY to_char("CreatedTime",'yyyy-MM-dd') ORDER BY "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';
+
+--处理工单 一级部门
+select * from "order" where "OrgLevelOneCode"='001023';
+--update "order" set "OrgLevelOneName"='珙县智慧信息服务中心' where  "OrgLevelOneCode"='001023';
+
+--处理工单 实际办理部门
+select * from "order" WHERE "ActualHandleOrgCode"='001023';
+--update "order" SET "ActualHandlerName"='珙县智慧信息服务中心' WHERE "ActualHandleOrgCode"='001023';
+
+--处理工单 归档部门
+select * from  "order" WHERE "FileUserOrgId" = '001023';
+--update "order" SET "FileUserOrgName"='珙县智慧信息服务中心'  WHERE "FileUserOrgId" = '001023';
+
+--处理工单接办部门
+select * from "order" WHERE "CurrentHandleOrgId"='001023';
+--update "order" SET "CurrentHandleOrgName"='珙县智慧信息服务中心' where "CurrentHandleOrgId"='001023';
+
+--更新延期申请部门
+select * from order_delay where "ApplyOrgCode"='001023';
+--update order_delay SET "ApplyOrgName"='珙县智慧信息服务中心' where "ApplyOrgCode"='001023';
+
+--更新延期创建部门
+select * from order_delay WHERE "CreatorOrgId"='001023';
+--update order_delay SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
+
+--更新甄别创建部门
+select * from order_screen WHERE "CreatorOrgId"='001023';
+--update order_screen SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
+
+--更新流程实际办理部门
+select * from workflow where "ActualHandleOrgCode" ='001023';
+--update workflow SET "ActualHandleOrgName"= '珙县智慧信息服务中心' where "ActualHandleOrgCode" ='001023';
+
+--更新流程一级部门
+select * from workflow WHERE "OrgLevelOneCode"='001023';
+--update workflow set "OrgLevelOneName"='珙县智慧信息服务中心' where "OrgLevelOneCode"='001023';
+
+--更新流程受理部门
+select * from workflow where "AcceptorOrgId"='001023';
+--update  workflow set "AcceptorOrgName"='珙县智慧信息服务中心' where "AcceptorOrgId"='001023';
+
+--更新流程创建部门
+select * from workflow where "CreatorOrgId"='001023';
+--update workflow SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
+
+--更新流程实际接办部门
+select * from workflow WHERE "CurrentHandleOrgId"='001023';
+--update workflow SET "CurrentHandleOrgName"='珙县智慧信息服务中心' where"CurrentHandleOrgId"='001023';
+
+--更新流程明细受理部门
+select * from workflow_step where "AcceptorOrgId"='001023';
+--update workflow_step SET "AcceptorOrgName"='珙县智慧信息服务中心' where "AcceptorOrgId"='001023';
+
+--更新流程明细办理部门
+select * from workflow_step WHERE "HandlerOrgId"='001023';
+--update workflow_step SET "HandlerOrgName"='珙县智慧信息服务中心' where "HandlerOrgId"='001023'
+
+--更新流程明细创建部门
+select * from workflow_step WHERE "CreatorOrgId"='001023';
+--update workflow_step SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
+
+--更新流程明细签收部门
+select * from workflow_step WHERE "AssignerOrgId"='001023';
+--update workflow_step SET "AssignerName"='珙县智慧信息服务中心' where "AssignerOrgId"='001023';
+
+--更新流程快照受理部门
+select * from workflow_trace where "AcceptorOrgId"='001023';
+--update workflow_trace SET "AcceptorOrgName"='珙县智慧信息服务中心' where "AcceptorOrgId"='001023';
+
+--更新流程快照办理部门
+select * from workflow_trace WHERE "HandlerOrgId"='001023';
+--update workflow_trace SET "HandlerOrgName"='珙县智慧信息服务中心' where "HandlerOrgId"='001023';
+
+--更新流程快照创建部门
+select * from workflow_trace WHERE "CreatorOrgId"='001023';
+--update workflow_trace SET "CreatorOrgName"='珙县智慧信息服务中心' where "CreatorOrgId"='001023';
+
+--更新流程快照签收部门
+select * from workflow_trace WHERE "AssignerOrgId"='001023';
+--update workflow_trace SET "AssignerName"='珙县智慧信息服务中心' where "AssignerOrgId"='001023';
+
+--更新特提申请部门
+select * from order_special where "OrgId"='001023';
+--update order_special SET "OrgName"='珙县智慧信息服务中心' WHERE "OrgId"='001023';
+
+--更新特提创建部门
+select * from order_special where "CreatorOrgId"='001023';
+--update order_special SET "CreatorOrgName"='珙县智慧信息服务中心'  WHERE "CreatorOrgId"='001023';
+
+--更新特提明细申请部门
+select * from order_special_detail where "OrgId"='001023';
+--update order_special_detail SET "OrgName"='珙县智慧信息服务中心' where "OrgId"='001023';
+
+--更新特提明细创建部门
+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_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';

+ 3 - 1
test/Hotline.Tests/Controller/OrderControllerTest.cs

@@ -195,10 +195,10 @@ public class OrderControllerTest : TestBase
             .FirstAsync();
         var visitDetaila = await _orderVisitDetailRepository.Queryable().Where(m => m.VisitId == visit.Id).ToListAsync();
         var visitDetail = visitDetaila.Adapt<List<VisitDetailDto>>();
+        var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt("0");
         visitDetail.ForEach(m =>
         {
             m.SeatEvaluate = ESeatEvaluate.DefaultSatisfied;
-            var smsReply = _orderVisitDomainService.GetVisitEvaluateByReplyTxt("0");
             m.OrgProcessingResults = smsReply.GetOrgProcessingResults(_systemDicDataCacheManager.VisitSatisfaction);
             m.OrgHandledAttitude = smsReply.GetOrgHandledAttitude(_systemDicDataCacheManager.VisitSatisfaction);
         });
@@ -221,6 +221,8 @@ public class OrderControllerTest : TestBase
         };
 
         await _orderController.Visit(visitDto);
+        var orderEntity = await _orderRepository.GetAsync(order.Id);
+        orderEntity.OrgProcessingResults.ShouldNotBeNull();
     }
 
     /// <summary>