Ver código fonte

Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test

Dun.Jason 1 mês atrás
pai
commit
b8e512d1ab
32 arquivos alterados com 1156 adições e 555 exclusões
  1. 155 0
      src/Hotline.Api/Controllers/EnterpriseLuzhouController.cs
  2. 1 130
      src/Hotline.Api/Controllers/EnterprisesController.cs
  3. 1 3
      src/Hotline.Api/Controllers/IPPbxController.cs
  4. 44 44
      src/Hotline.Api/Controllers/OrderController.cs
  5. 106 0
      src/Hotline.Api/Controllers/SpecialController.cs
  6. 1 1
      src/Hotline.Api/Controllers/WebPortalController.cs
  7. 3 0
      src/Hotline.Api/Controllers/WorkflowController.cs
  8. 1 1
      src/Hotline.Api/config/appsettings.Development.json
  9. 22 7
      src/Hotline.Application/CallCenter/DefaultCallApplication.cs
  10. 2 2
      src/Hotline.Application/Enterprise/EnterpriseApplication.cs
  11. 2 2
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  12. 6 2
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  13. 33 2
      src/Hotline.Application/Orders/Handles/OrderScreenHandler/OrderScreenEndWorkflowHandler.cs
  14. 123 138
      src/Hotline.Application/Orders/OrderApplication.cs
  15. 54 0
      src/Hotline.Application/SpecialNumber/ISpecialNumberApplication.cs
  16. 169 0
      src/Hotline.Application/SpecialNumber/SpecialNumberApplication.cs
  17. 19 1
      src/Hotline.Repository.SqlSugar/File/FileRepository.cs
  18. 1 1
      src/Hotline.Share/Dtos/Article/BulletinDto.cs
  19. 2 0
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  20. 10 0
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  21. 87 0
      src/Hotline.Share/Dtos/Special/SpecialNumberDto.cs
  22. 6 0
      src/Hotline.Share/Enums/FlowEngine/EHandleMode.cs
  23. 3 0
      src/Hotline.Share/Enums/Push/EPushBusiness.cs
  24. 2 2
      src/Hotline.Share/Requests/PagedKeywordRequest.cs
  25. 35 2
      src/Hotline/Article/CircularRecordDomainService.cs
  26. 6 1
      src/Hotline/Article/ICircularRecordDomainService.cs
  27. 3 1
      src/Hotline/File/IFileRepository.cs
  28. 3 1
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  29. 177 172
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  30. 41 33
      src/Hotline/Orders/OrderDomainService.cs
  31. 16 9
      src/Hotline/Orders/OrderVisitDetail.cs
  32. 22 0
      src/Hotline/Special/SpecialNumber.cs

+ 155 - 0
src/Hotline.Api/Controllers/EnterpriseLuzhouController.cs

@@ -0,0 +1,155 @@
+using Hotline.Enterprise;
+using Hotline.Share.Dtos.Enterprise;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Users;
+using Hotline.Share.Dtos;
+using Hotline.Tools;
+using Microsoft.AspNetCore.Mvc;
+using XF.Domain.Authentications;
+using Hotline.Application.Enterprise;
+using Hotline.Configurations;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Extensions;
+using MapsterMapper;
+using Microsoft.Extensions.Options;
+using XF.Domain.Repository;
+
+namespace Hotline.Api.Controllers
+{
+    /// <summary>
+    /// 泸州企业专员工单管理
+    /// </summary>
+    public class EnterpriseLuzhouController : BaseController
+    {
+        private readonly IRepository<EnterpriseSpecialist> _enterpriseSpecialistRepository;
+        private readonly IEnterpriseApplication _enterpriseApplication;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+
+        public EnterpriseLuzhouController(
+            IRepository<EnterpriseSpecialist> enterpriseSpecialistRepository,
+            IEnterpriseApplication enterpriseApplication,
+            IOptionsSnapshot<AppConfiguration> appOptions,
+            ISessionContext sessionContext,
+            IMapper mapper)
+        {
+            _enterpriseSpecialistRepository = enterpriseSpecialistRepository;
+            _enterpriseApplication = enterpriseApplication;
+            _appOptions = appOptions;
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+        }
+
+        
+        [HttpGet("specialist/users")]
+        public async Task<PagedDto<UserDto>> QueryUsers([FromQuery] UserPagedDto request)
+        {
+            var query = _enterpriseApplication.QueryUsersForSpecialist(request);
+            var (total, users) = await query.ToPagedListAsync(request);
+            var userDtos = _mapper.Map<List<UserDto>>(users);
+            return new PagedDto<UserDto>(total, userDtos);
+        }
+
+        /// <summary>
+        /// 批量新增企业专员
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("specialist-batch")]
+        public async Task AddSpecialists([FromBody] List<AddEnterpriseSpecialistDto> dto)
+        {
+            var specialists = _mapper.Map<List<EnterpriseSpecialist>>(dto);
+            await _enterpriseSpecialistRepository.AddRangeAsync(specialists, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 批量删除企业专员
+        /// </summary>
+        [HttpDelete("specialist-batch")]
+        public async Task RemoveSpecialists([FromBody] List<string> ids)
+        {
+            var specialists = await _enterpriseSpecialistRepository.Queryable()
+                .Where(d => ids.Contains(d.Id) || ids.Contains(d.ParentId))
+                .ToListAsync(HttpContext.RequestAborted);
+            await _enterpriseSpecialistRepository.RemoveRangeAsync(specialists, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 查询企业专员
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("specialists-tree")]
+        public Task<List<EnterpriseSpecialistDto>> QuerySpecialists()
+        {
+            return _enterpriseSpecialistRepository.Queryable()
+                .Includes(d => d.User, s => s.Account)
+                .OrderBy(d => d.Id)
+                .Select(d => new EnterpriseSpecialistDto
+                {
+                    Id = d.Id,
+                    ParentId = d.ParentId,
+                    Name = d.User.Name,
+                    UserName = d.User.Account.UserName,
+                    PhoneNo = d.User.PhoneNo,
+                })
+                .ToTreeAsync(d => d.Children, it => it.ParentId, null);
+        }
+
+        /// <summary>
+        /// 查询企业专员工单
+        /// </summary>
+        [HttpGet("specialist/orders")]
+        public async Task<IReadOnlyList<OrderDto>> QueryEnterpriseSpecialistOrders([FromQuery] QueryOrderDto dto)
+        {
+            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto, HttpContext.RequestAborted);
+            var orders = await query.ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
+            return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
+        }
+
+        /// <summary>
+        /// 查询总数
+        /// </summary>
+        [HttpGet("specialist/orders/count")]
+        public async Task<int> CountEnterpriseSpecialistOrders([FromQuery] QueryOrderDto dto)
+        {
+            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto, HttpContext.RequestAborted);
+            return await query.CountAsync(HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 导出企业专员工单
+        /// </summary>
+        [HttpPost("specialist/orders/export")]
+        public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
+        {
+            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto.QueryDto, HttpContext.RequestAborted);
+            List<Order> orders;
+            if (dto.IsExportAll)
+            {
+                orders = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                orders = items;
+            }
+
+            var orderDtos = _mapper.Map<ICollection<OrderDto>>(orders);
+
+            if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter)
+                orderDtos = orderDtos.Select(p => p.DataMask()).ToList();
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = orderDtos
+                .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "企业专员工单数据");
+        }
+
+    }
+}

+ 1 - 130
src/Hotline.Api/Controllers/EnterprisesController.cs

@@ -21,26 +21,10 @@ namespace Hotline.Api.Controllers
     public class EnterprisesController : BaseController
     {
         private readonly IEnterpriseService _enterpriseService;
-        private readonly IRepository<EnterpriseSpecialist> _enterpriseSpecialistRepository;
-        private readonly IEnterpriseApplication _enterpriseApplication;
-        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
-        private readonly ISessionContext _sessionContext;
-        private readonly IMapper _mapper;
 
-        public EnterprisesController(
-            IEnterpriseService enterpriseService,
-            IRepository<EnterpriseSpecialist> enterpriseSpecialistRepository,
-            IEnterpriseApplication enterpriseApplication,
-            IOptionsSnapshot<AppConfiguration> appOptions,
-            ISessionContext sessionContext,
-            IMapper mapper)
+        public EnterprisesController(IEnterpriseService enterpriseService)
         {
             _enterpriseService = enterpriseService;
-            _enterpriseSpecialistRepository = enterpriseSpecialistRepository;
-            _enterpriseApplication = enterpriseApplication;
-            _appOptions = appOptions;
-            _sessionContext = sessionContext;
-            _mapper = mapper;
         }
 
         #region (宜宾)获取企业信息
@@ -58,118 +42,5 @@ namespace Hotline.Api.Controllers
         }
 
         #endregion
-
-        #region 泸州
-
-        [HttpGet("specialist/users")]
-        public async Task<PagedDto<UserDto>> QueryUsers([FromQuery] UserPagedDto request)
-        {
-            var query = _enterpriseApplication.QueryUsersForSpecialist(request);
-            var (total, users) = await query.ToPagedListAsync(request);
-            var userDtos = _mapper.Map<List<UserDto>>(users);
-            return new PagedDto<UserDto>(total, userDtos);
-        }
-
-        /// <summary>
-        /// 批量新增企业专员
-        /// </summary>
-        /// <returns></returns>
-        [HttpPost("specialist-batch")]
-        public async Task AddSpecialists([FromBody] List<AddEnterpriseSpecialistDto> dto)
-        {
-            var specialists = _mapper.Map<List<EnterpriseSpecialist>>(dto);
-            await _enterpriseSpecialistRepository.AddRangeAsync(specialists, HttpContext.RequestAborted);
-        }
-
-        /// <summary>
-        /// 批量删除企业专员
-        /// </summary>
-        [HttpDelete("specialist-batch")]
-        public async Task RemoveSpecialists([FromBody] List<string> ids)
-        {
-            var specialists = await _enterpriseSpecialistRepository.Queryable()
-                .Where(d => ids.Contains(d.Id) || ids.Contains(d.ParentId))
-                .ToListAsync(HttpContext.RequestAborted);
-            await _enterpriseSpecialistRepository.RemoveRangeAsync(specialists, HttpContext.RequestAborted);
-        }
-
-        /// <summary>
-        /// 查询企业专员
-        /// </summary>
-        /// <returns></returns>
-        [HttpGet("specialists-tree")]
-        public Task<List<EnterpriseSpecialistDto>> QuerySpecialists()
-        {
-            return _enterpriseSpecialistRepository.Queryable()
-                .Includes(d => d.User, s => s.Account)
-                .OrderBy(d => d.Id)
-                .Select(d=>new EnterpriseSpecialistDto
-                {
-                    Id = d.Id,
-                    ParentId = d.ParentId,
-                    Name = d.User.Name,
-                    UserName = d.User.Account.UserName,
-                    PhoneNo = d.User.PhoneNo,
-                })
-                .ToTreeAsync(d => d.Children, it => it.ParentId, null);
-        }
-
-        /// <summary>
-        /// 查询企业专员工单
-        /// </summary>
-        [HttpGet("specialist/orders")]
-        public async Task<IReadOnlyList<OrderDto>> QueryEnterpriseSpecialistOrders([FromQuery] QueryOrderDto dto)
-        {
-            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto, HttpContext.RequestAborted);
-            var orders = await query.ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted);
-            return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
-        }
-
-        /// <summary>
-        /// 查询总数
-        /// </summary>
-        [HttpGet("specialist/orders/count")]
-        public async Task<int> CountEnterpriseSpecialistOrders([FromQuery] QueryOrderDto dto)
-        {
-            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto, HttpContext.RequestAborted);
-            return await query.CountAsync(HttpContext.RequestAborted);
-        }
-
-        /// <summary>
-        /// 导出企业专员工单
-        /// </summary>
-        [HttpPost("specialist/orders/export")]
-        public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
-        {
-            var query = await _enterpriseApplication.QueryEnterpriseSpecialistOrdersAsync(dto.QueryDto, HttpContext.RequestAborted);
-            List<Order> orders;
-            if (dto.IsExportAll)
-            {
-                orders = await query.ToListAsync(HttpContext.RequestAborted);
-            }
-            else
-            {
-                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
-                orders = items;
-            }
-
-            var orderDtos = _mapper.Map<ICollection<OrderDto>>(orders);
-
-            if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter)
-                orderDtos = orderDtos.Select(p => p.DataMask()).ToList();
-
-            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
-
-            var dtos = orderDtos
-                .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass))
-                .Cast<object>()
-                .ToList();
-
-            var stream = ExcelHelper.CreateStream(dtos);
-
-            return ExcelStreamResult(stream, "企业专员工单数据");
-        }
-
-        #endregion
     }
 }

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

@@ -66,7 +66,6 @@ namespace Hotline.Api.Controllers
         private readonly IRepository<User> _userRepository;
         private readonly ITelApplication _telApplication;
         private readonly IRepository<Quality.Quality> _qualiteyRepository;
-        private readonly IAiQualityService _aiQualityService;
         private readonly IRepository<QualityTemplate> _qualityTemplate;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
         private readonly IRepository<TelActionRecord> _telActionRecordRepository;
@@ -87,7 +86,7 @@ namespace Hotline.Api.Controllers
             IUserCacheManager userCacheManager, ICapPublisher capPublisher,
             ITelRestRepository telRestRepository, IRepository<User> userRepository,
             ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
-            IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate,
+            IRepository<QualityTemplate> qualityTemplate,
             ISystemSettingCacheManager systemSettingCacheManager, IRepository<TelActionRecord> telActionRecordRepository,
             ISystemMobilAreaApplication systemMobilAreaApplication, IRepository<Work> workRepository, Publisher publisher, ITrCallRecordRepository callRecordRepository, ITypedCache<Work> cacheWork, IIPPbxApplication iPPbxApplication, ICallTelClient callTelClient, IRepository<TelOperation> telOperationRepository)
         {
@@ -107,7 +106,6 @@ namespace Hotline.Api.Controllers
             _userRepository = userRepository;
             _telApplication = telApplication;
             _qualiteyRepository = qualiteyRepository;
-            _aiQualityService = aiQualityService;
             _qualityTemplate = qualityTemplate;
             _systemSettingCacheManager = systemSettingCacheManager;
             _telActionRecordRepository = telActionRecordRepository;

+ 44 - 44
src/Hotline.Api/Controllers/OrderController.cs

@@ -70,6 +70,7 @@ using MiniExcelLibs;
 using SqlSugar;
 using System.Text;
 using System.Text.Json;
+using System.Threading;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Exceptions;
@@ -2098,6 +2099,7 @@ public class OrderController : BaseController
     /// </summary>
     [HttpPost("delay/batch_audit")]
     [LogFilter("批量审批延期")]
+    [LogFilterAlpha("延期审核")]
     public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
     {
         var result = new StringBuilder();
@@ -2489,6 +2491,15 @@ public class OrderController : BaseController
 
         var (total, items) = await _orderApplication.MayScreenList(dto)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        var data = _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items);
+        var isAdmin = _orderDomainService.IsCheckAdmin();
+        foreach (var item in data)
+        {
+            if (isAdmin == true)
+                item.IsShowOperate = true;
+            else
+                item.IsShowOperate = item.VisitOrgCode == _sessionContext.OrgId ? true : false;
+        }
         return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
     }
 
@@ -3945,33 +3956,6 @@ public class OrderController : BaseController
         return _sessionContext.OrgIsCenter ? dto : dto.DataMask();
     }
 
-
-    /// <summary>
-    /// 上传附件
-    /// </summary>
-    /// <param name="dto"></param>
-    /// <returns></returns>
-    //[HttpPost]
-    //[LogFilterAlpha("上传附件")]
-    //public async Task UploadFiles(OrderUploadFiles dto) { 
-
-    //       var fileJson = await _fileRepository.AddFileAsync(dto.Files, dto.Id, "", HttpContext.RequestAborted);
-
-    //       if (fileJson.Any())
-    //       {
-    //		var order = await _orderRepository.GetAsync(dto.Id);
-    //           if (order.FileJson != null && order.FileJson.Any())
-    //           {
-    //               order.FileJson.AddRange(fileJson);
-    //           }
-    //           else {
-    //               order.FileJson = fileJson;
-    //		}
-    //           await _orderRepository.Updateable().SetColumns(x => new Order { FileJson = order.FileJson }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
-    //	}
-    //}
-
-
     /// <summary>
     /// 新增工单
     /// </summary>
@@ -4721,8 +4705,10 @@ public class OrderController : BaseController
                     // }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 }
 
-                var (_, currentStep, _, _) = await _workflowDomainService.NextAsync(_sessionContext, nextDto, order.ExpiredTime,
-                    isAutoFillSummaryOpinion, cancellationToken: cancellationToken);
+                var (_, currentStep, _, _) = await _workflowDomainService.NextAsync(_sessionContext, nextDto,
+                    expiredTime: order.ExpiredTime,
+                    isAutoFillSummaryOpinion: isAutoFillSummaryOpinion,
+                    cancellationToken: cancellationToken);
                 if (currentStep.BusinessType is EBusinessType.Send)
                 {
                     await _orderRepository.Updateable().SetColumns(o => new Order()
@@ -4761,7 +4747,8 @@ public class OrderController : BaseController
                             OrgId = unhandleStep.HandlerOrgId,
                             OrgName = unhandleStep.HandlerOrgName,
                         };
-                        var (_, _, _, nextSteps) = await _workflowDomainService.NextAsync(operater, nextflowDto, order.ExpiredTime,
+                        var (_, _, _, nextSteps) = await _workflowDomainService.NextAsync(operater, nextflowDto,
+                            EHandleMode.CrossLevel, order.ExpiredTime,
                             isAutoFillSummaryOpinion, cancellationToken: cancellationToken);
                         tempSteps.AddRange(nextSteps);
                     }
@@ -4817,8 +4804,10 @@ public class OrderController : BaseController
         NextWorkflowDto? flowDto, DateTime? expiredTime, bool isAutoFillSummaryOpinion, CancellationToken cancellation)
     {
         if (flowDto is null || !flowDto.NextHandlers.Any()) return;
-        var (_, _, _, currentSteps) = await _workflowDomainService.NextAsync(current, flowDto, expiredTime,
-            isAutoFillSummaryOpinion, cancellationToken: cancellation);
+        var (_, _, _, currentSteps) = await _workflowDomainService.NextAsync(current, flowDto,
+            expiredTime: expiredTime,
+            isAutoFillSummaryOpinion: isAutoFillSummaryOpinion,
+            cancellationToken: cancellation);
 
         foreach (var currentStep in currentSteps)
         {
@@ -5536,7 +5525,7 @@ public class OrderController : BaseController
             if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行退回!");
 
             var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-               dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted);
+               dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, dto.AssignStepId, HttpContext.RequestAborted);
 
             if (oneSendBack && isOrgToCenter && _appOptions.Value.IsZiGong)
             {
@@ -5567,7 +5556,7 @@ public class OrderController : BaseController
 
                 audit.WorkflowStepSendBackCrTime = currentStep.CreationTime;
                 audit.TraceId = currentStep.Id;
-                await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
+                //await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
             }
             else
             {
@@ -5583,8 +5572,8 @@ public class OrderController : BaseController
             audit.AuditUser = "默认通过";
             audit.AuditTime = DateTime.Now;
             await _orderApplication.OrderPrevious(audit, order, HttpContext.RequestAborted);
-
         }
+        await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted);
     }
 
     /// <summary>
@@ -5593,6 +5582,7 @@ public class OrderController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPost("order_previous_audit")]
+    [LogFilterAlpha("退回审批")]
     public async Task Audit([FromBody] AuditSendBackDto dto)
     {
         if (dto.State == ESendBackAuditState.Refuse && string.IsNullOrEmpty(dto.AuditContent))
@@ -5616,7 +5606,7 @@ public class OrderController : BaseController
             if (_appOptions.Value.IsZiGong)
             {
                 var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-                    order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
+                    order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), sendBack.AssignStepId,
                     HttpContext.RequestAborted);
 
                 if (prevStep.BusinessType == EBusinessType.Send)
@@ -5637,8 +5627,9 @@ public class OrderController : BaseController
         {
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value })
                 .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
-            await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
+
         }
+        await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
     }
 
     /// <summary>
@@ -5646,6 +5637,7 @@ public class OrderController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpPost("order_previous_audit_batch")]
+    [LogFilterAlpha("退回审批批量")]
     public async Task AuditBatch([FromBody] BatchAuditSendBackDto dto)
     {
         foreach (string id in dto.Ids)
@@ -5671,7 +5663,7 @@ public class OrderController : BaseController
                 if (_appOptions.Value.IsZiGong)
                 {
                     var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-                        order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
+                        order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), sendBack.AssignStepId,
                         HttpContext.RequestAborted);
                     if (prevStep.BusinessType == EBusinessType.Send)
                     {
@@ -5692,10 +5684,8 @@ public class OrderController : BaseController
             {
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value })
                     .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
-                await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
             }
-
-
+            await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
         }
     }
 
@@ -5795,7 +5785,7 @@ public class OrderController : BaseController
             throw UserFriendlyException.SameMessage("该工单未开启流程");
 
         var (currentStep, prevStep, steps, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-            order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted);
+            order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, string.Empty, HttpContext.RequestAborted);
         ///查询上一节点是否是领导节点
         ///ture 流程排除领导节点 排除当前节点 prevStep.BusinessType == EBusinessType.DepartmentLeader
         if (_appOptions.Value.IsYiBin && prevStep.Name.Contains("领导"))
@@ -6011,6 +6001,7 @@ public class OrderController : BaseController
     /// <returns></returns>
     [HttpPost("special")]
     [LogFilter("新增工单特提")]
+    [LogFilterAlpha("特提审核")]
     public async Task Add([FromBody] OrderSpecialAddDto dto)
     {
         var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0)
@@ -6113,6 +6104,11 @@ public class OrderController : BaseController
                 },
                 HttpContext.RequestAborted);
 
+            //         if (order.ActualHandleOrgCode != OrgSeedData.CenterId && order.Status < EOrderStatus.Filed)
+            //         {
+            //             await _circularRecordDomainService.OrderSpecialCircularMessage(special, order, HttpContext.RequestAborted);
+            //}
+
             if (string.IsNullOrEmpty(currentStep?.HandlerOrgId))
             {
                 special.OrgId = currentStep.HandlerOrgId;
@@ -6226,6 +6222,7 @@ public class OrderController : BaseController
         special.SpecialType = dto.SpecialType;
         special.LastFileOpinion = order.FileOpinion;
         special.FirstFileOpinion = order.FileOpinion;
+        special.Status = order.Status;
         var firstSpecial = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId).FirstAsync();
         if (firstSpecial is not null)
             special.FirstFileOpinion = firstSpecial.FirstFileOpinion;
@@ -6507,6 +6504,7 @@ public class OrderController : BaseController
     /// <returns></returns>
     [HttpPut("special_batch")]
     [LogFilter("批量审批工单特提")]
+    [LogFilterAlpha("特提审核批量")]
     public async Task UpdateBatch([FromBody] BatchAuditOrderSpecialDto dto)
     {
         var specials = await _orderSpecialRepository.Queryable()
@@ -6886,9 +6884,9 @@ public class OrderController : BaseController
         if (_appOptions.Value.IsZiGong)
         {
             step.Steps = step.Steps.Where(x => x.Key.ToLower() != "start").ToList();
-            if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any())
+            if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.StepType == EStepType.Normal && x.OrgLevel == 1).Any())
             {
-                var stepdDefault = step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1)
+                var stepdDefault = step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.StepType == EStepType.Normal && x.OrgLevel == 1)
                     .FirstOrDefault();
                 defaultStepKey = stepdDefault.Key;
             }
@@ -8136,6 +8134,7 @@ public class OrderController : BaseController
     /// <returns></returns>
     [HttpPut("secondary_handling/audit")]
     [LogFilter("二次办理审批")]
+    [LogFilterAlpha("二次办理审核")]
     public async Task OrderSecondaryHandlingAudit([FromBody] AuditOrderSecondaryHandlingDto dto)
     {
         var model = await _orderSecondaryHandlingApplication.Entity(dto.Id, HttpContext.RequestAborted);
@@ -8151,6 +8150,7 @@ public class OrderController : BaseController
     /// <returns></returns>
     [HttpPut("secondary_handling/batch_audit")]
     [LogFilter("二次办理批量审批")]
+    [LogFilterAlpha("二次办理审核批量")]
     public async Task OrderSecondaryHandlingBatchAudit([FromBody] AuditOrderSecondaryHandlingDto dto)
     {
         foreach (var item in dto.Ids)

+ 106 - 0
src/Hotline.Api/Controllers/SpecialController.cs

@@ -0,0 +1,106 @@
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using XF.Domain.Authentications;
+using Hotline.Share.Dtos;
+using Hotline.Share.Tools;
+using Hotline.Application.SpecialNumber;
+using Hotline.Share.Dtos.Special;
+
+namespace Hotline.Api.Controllers
+{
+    /// <summary>
+    /// 特殊号码
+    /// </summary>
+    public class SpecialController : BaseController
+    {
+        #region 注入
+
+        private readonly IMapper _mapper;
+        private readonly ISessionContext _sessionContext;
+        private readonly ISpecialNumberApplication _specialNumberApplication;
+
+
+        public SpecialController(
+           IMapper mapper,
+           ISessionContext sessionContext,
+           ISpecialNumberApplication specialNumberApplication)
+        {
+            _mapper = mapper;
+            _sessionContext = sessionContext;
+            _specialNumberApplication = specialNumberApplication;
+        }
+
+        #endregion
+
+        #region 特殊号码
+
+        /// <summary>
+        /// 特殊号码列表
+        /// </summary>
+        /// <param name="pagedDto"></param>
+        /// <returns></returns>
+        [HttpGet("number/list")]
+        public async Task<PagedDto<SpecialNumberInfoDto>> QueryAllSpecialNumberListAsync([FromQuery] SpecialNumberDto pagedDto)
+        {
+            return (await _specialNumberApplication.QueryAllSpecialNumberListAsync(pagedDto, HttpContext.RequestAborted)).ToPaged();
+        }
+
+        /// <summary>
+        /// 特殊号码新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("number/add")]
+        public async Task<string> AddSpecialNumberAsync([FromBody] AddSpecialNumberDto dto)
+        {
+            return await _specialNumberApplication.AddSpecialNumberAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 特殊号码编辑
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("number/update")]
+        public async Task UpdateSpecialNumberAsync([FromBody] UpdateSpecialNumberDto dto)
+        {
+            await _specialNumberApplication.UpdateSpecialNumberAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 特殊号码删除
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpDelete("number/remove")]
+        public async Task RemoveSpecialNumberAsync([FromBody] DelSpecialNumberDto dto)
+        {
+            await _specialNumberApplication.RemoveSpecialNumberAsync(dto, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 特殊号码详情根据id查询
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <returns></returns>
+        [HttpGet("number/info")]
+        public async Task<SpecialNumberInfoDto> GetSpecialNumberAsync(string Id)
+        {
+            return await _specialNumberApplication.GetSpecialNumberAsync(Id, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 特殊号码详情根据号码查询
+        /// </summary>
+        /// <param name="PhoneNumber"></param>
+        /// <returns></returns>
+        [HttpGet("number/info/num")]
+        public async Task<SpecialNumberInfoDto> GetSpecialNumberByAsync(string PhoneNumber)
+        {
+            return await _specialNumberApplication.GetSpecialNumberByAsync(PhoneNumber, HttpContext.RequestAborted);
+        }
+
+        #endregion
+    }
+}
+

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

@@ -1977,7 +1977,7 @@ namespace Hotline.Api.Controllers
                 {
                     orderDetail.VisitType = orderVisit.VisitState switch
                     {
-                        EVisitState.WaitForVisit => "1",
+                        EVisitState.WaitForVisit or EVisitState.SMSVisiting or EVisitState.SMSUnsatisfied => "1",
                         EVisitState.Visited => "2",
                         EVisitState.Visiting or EVisitState.NoSatisfiedWaitForVisit or EVisitState.None => "0",
                         _ => "0",

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

@@ -28,6 +28,7 @@ using Hotline.Settings.TimeLimits;
 using Hotline.SeedData;
 using Hotline.Tools;
 using Hotline.Share.Enums.Order;
+using Hotline.Api.Filter;
 
 namespace Hotline.Api.Controllers;
 
@@ -343,6 +344,7 @@ public class WorkflowController : BaseController
     /// </summary>
     [HttpPost("next")]
     [Obsolete("即将弃用")]
+    [LogFilterAlpha("审核开始")]
     public async Task Next([FromBody] NextWorkflowDto dto)
     {
         await _workflowDomainService.NextAsync(_sessionContext, dto, cancellationToken: HttpContext.RequestAborted);
@@ -352,6 +354,7 @@ public class WorkflowController : BaseController
     /// 退回(返回前一节点)
     /// </summary>
     [HttpPost("previous")]
+    [LogFilterAlpha("审核退回")]
     public async Task Previous([FromBody] PreviousWorkflowDto dto)
     {
         await _workflowApplication.PreviousAsync(dto, cancellationToken: HttpContext.RequestAborted);

+ 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

+ 22 - 7
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -19,6 +19,7 @@ using Hotline.Share.Enums.Order;
 using Hotline.Share.Mq;
 using Hotline.Share.Tools;
 using Hotline.Users;
+using JiebaNet.Segmenter.Common;
 using Mapster;
 using MapsterMapper;
 using Microsoft.Extensions.Logging;
@@ -295,6 +296,20 @@ public abstract class DefaultCallApplication : ICallApplication
                 IsOrder = !SqlFunc.IsNullOrEmpty(o.Id),
             }, true);
         }
+        if (dto.Type == 3)
+        {
+            return query.Select((d, o, v) => new CallNativeDto
+            {
+                OrderId = o.Id,
+                OrderNo = o.No,
+                CallState = d.CallState,
+                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"),
+            }, true);
+        }
         return query.Select((d, o, v) => new CallNativeDto
         {
             OrderId = o.Id,
@@ -486,7 +501,7 @@ public abstract class DefaultCallApplication : ICallApplication
                 dto.CallId = callRemark.CallId;
             }
             catch (Exception e)
-            { 
+            {
                 _logger.LogError($"PublishVisitRelevanceCallIdAsync: {e.ToJson()}");
             }
         }
@@ -566,13 +581,13 @@ public abstract class DefaultCallApplication : ICallApplication
             .Where((o, c) => o.Id == orderId)
             .Select((o, c) => new { o.CallId, c.CallNo })
             .FirstAsync(cancellationToken);
-//#if DEBUG
-//        var order = await _orderRepository.GetAsync(orderId);
-//        var oldName = _sessionContext.UserName;
-//        _sessionContext.ChangeSession("08dcfe32-c260-40b4-839a-aeca1f76244c");
-//        var newName = _sessionContext.UserName;
+        //#if DEBUG
+        //        var order = await _orderRepository.GetAsync(orderId);
+        //        var oldName = _sessionContext.UserName;
+        //        _sessionContext.ChangeSession("08dcfe32-c260-40b4-839a-aeca1f76244c");
+        //        var newName = _sessionContext.UserName;
 
-//#endif
+        //#endif
         if (orderCall is null || orderCall.CallNo.IsNullOrEmpty())
         {
             string message = $"延迟更新工单通话, 工单: {orderId} 根据 order.id left join call_native 信息为空; 消息队列无须重试";

+ 2 - 2
src/Hotline.Application/Enterprise/EnterpriseApplication.cs

@@ -49,8 +49,8 @@ public class EnterpriseApplication : IEnterpriseApplication, IScopeDependency
             .ToListAsync(cancellationToken);
         return _orderRepository.Queryable()
                 .Where(d => memberIds.Contains(d.CreatorId))
-                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Title.Contains(dto.No!))
-                .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!))
+                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
                 .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
                 .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
                 .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席

+ 2 - 2
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -118,8 +118,8 @@ namespace Hotline.Application.FlowEngine
         /// 检查退回节点信息
         /// </summary>
         Task<(WorkflowStep currentStep, WorkflowStep prevStep,List<WorkflowStep> steps, bool isOrgToCenter, bool isSecondToFirstOrgLevel)>
-            GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles,
-                CancellationToken cancellationToken);
+            GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles, string? assignStepId,
+				CancellationToken cancellationToken);
 
         /// <summary>
         /// 更新省平台办理结果节点附件

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

@@ -1870,12 +1870,16 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// 检查退回节点信息
     /// </summary>
     public async Task<(WorkflowStep currentStep, WorkflowStep prevStep, List<WorkflowStep> steps, bool isOrgToCenter, bool isSecondToFirstOrgLevel)>
-        GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles,
-            CancellationToken cancellationToken)
+        GetPreviousInformationAsync(string workflowId, string operatorId, string operatorOrgId, string[] roles,string? assignStepId,
+			CancellationToken cancellationToken)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true,
             withCountersigns: true, cancellationToken: cancellationToken);
         var (currentStep, prevStep, _) = _workflowDomainService.GetPreviousStep(workflow, operatorId, operatorOrgId, roles);
+        if (!string.IsNullOrEmpty(assignStepId))
+        {
+			prevStep = workflow.Steps.FirstOrDefault(d => d.Id == assignStepId);
+		}
         var isOrgToCenter = currentStep.BusinessType is EBusinessType.Department &&
                             prevStep.BusinessType is EBusinessType.Seat or EBusinessType.Send;
         var isSecondToFirstOrgLevel = currentStep.HandlerType is EHandlerType.OrgLevel &&

+ 33 - 2
src/Hotline.Application/Orders/Handles/OrderScreenHandler/OrderScreenEndWorkflowHandler.cs

@@ -3,9 +3,12 @@ using Hotline.Configurations;
 using Hotline.FlowEngine.Notifications;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Orders;
+using Hotline.Push.Notifies;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Push;
+using Hotline.Users;
 using MapsterMapper;
 using MediatR;
 using Microsoft.Extensions.Options;
@@ -24,6 +27,8 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
     private readonly ISessionContext _sessionContext;
     private readonly IRepository<OrderScreenDetail> _orderScreenDetailRepository;
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+    private readonly IMediator _mediator;
+    private readonly IRepository<User> _userRepository;
 
     public OrderScreenEndWorkflowHandler(
         IOrderRepository orderRepository,
@@ -34,7 +39,9 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
         IRepository<OrderVisit> orderVisitRepository,
         ISessionContext sessionContext,
         IRepository<OrderScreenDetail> orderScreenDetailRepository,
-         IOptionsSnapshot<AppConfiguration> appOptions)
+        IOptionsSnapshot<AppConfiguration> appOptions,
+        IMediator mediator,
+        IRepository<User> userRepository)
     {
         _orderRepository = orderRepository;
         _capPublisher = capPublisher;
@@ -45,7 +52,8 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
         _sessionContext = sessionContext;
         _orderScreenDetailRepository = orderScreenDetailRepository;
         _appOptions = appOptions;
-
+        _mediator = mediator;
+        _userRepository = userRepository;
     }
 
     /// <summary>Handles a notification</summary>
@@ -142,6 +150,29 @@ public class OrderScreenEndWorkflowHandler : INotificationHandler<EndWorkflowNot
                 };
                 detail.Audit(_sessionContext.UserId, _sessionContext.UserName, _sessionContext.OrgId, _sessionContext.OrgName, 1);
                 await _orderScreenDetailRepository.AddAsync(detail, cancellationToken);
+
+                //这里处理甄别完成后发送短信
+                if (_appOptions.Value.IsZiGong)
+                {
+                    var user = await _userRepository.GetAsync(p => p.Id == screen.CreatorId, cancellationToken);
+                    if (user != null)
+                    {
+                        var isReviewPassText = isReviewPass == true ? "审批通过" : "审批拒绝";
+                        var messageDto = new Share.Dtos.Push.MessageDto
+                        {
+                            PushBusiness = EPushBusiness.ScreenEnd,
+                            ExternalId = screen.Id,
+                            OrderId = screen.Id,
+                            PushPlatform = EPushPlatform.Sms,
+                            Remark = screen.No + isReviewPassText,
+                            Name = screen.CreatorName,
+                            TemplateCode = "1019",
+                            Params = new List<string>() { screen.No, isReviewPassText },
+                            TelNumber = user.PhoneNo,
+                        };
+                        await _mediator.Publish(new PushMessageNotify(messageDto), cancellationToken);
+                    }
+                }
             }
         }
     }

+ 123 - 138
src/Hotline.Application/Orders/OrderApplication.cs

@@ -60,6 +60,8 @@ using Hotline.Repository.SqlSugar.Orders;
 using Quartz.Simpl;
 using J2N.Text;
 using Hotline.Application.FlowEngine;
+using Hotline.Article;
+using Hotline.Share.Dtos.CallCenter;
 
 namespace Hotline.Application.Orders;
 
@@ -110,6 +112,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<KnowledgeQuote> _knowledgeQuoteRepository;
     private readonly IRepository<OrderSpecial> _orderSpecialRepository;
     private readonly IWorkflowApplication _workflowApplication;
+    private readonly ICircularRecordDomainService _circularRecordDomainService;
 
     public OrderApplication(
         IOrderDomainService orderDomainService,
@@ -155,7 +158,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IRepository<OrderTsDetails> orderTsDetailsRepository,
         IRepository<KnowledgeQuote> knowledgeQuoteRepository,
         IRepository<OrderSpecial> orderSpecialRepository,
-        IWorkflowApplication workflowApplication)
+        IWorkflowApplication workflowApplication,
+        ICircularRecordDomainService circularRecordDomainService)
     {
         _orderDomainService = orderDomainService;
         _workflowDomainService = workflowDomainService;
@@ -201,7 +205,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _knowledgeQuoteRepository = knowledgeQuoteRepository;
         _orderSpecialRepository = orderSpecialRepository;
         _workflowApplication = workflowApplication;
-
+        _circularRecordDomainService = circularRecordDomainService;
     }
 
     /// <summary>
@@ -738,9 +742,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 
         var order = await _orderRepository.Queryable()
             .FirstAsync(d => d.Id == dto.Id || d.No == dto.OrderNo, cancellationToken);
+
         if (order != null && dto.Files != null && dto.Files.Any())
         {
-            order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", cancellationToken);
+            List<FileJson> file = order.FileJson;
+            List<FileJson> fileNew = await _fileRepository.AddFileAsync(dto.Files, order.Id, cancellationToken);
+            file.AddRange(fileNew);
+            order.FileJson = file;
             await _orderRepository.UpdateAsync(order, cancellationToken);
         }
     }
@@ -1273,6 +1281,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         {
             visit.EmployeeId = _sessionContextProvider.SessionContext.UserId;
         }
+
         visit.CallId = dto.CallId;
         if (first != null)
         {
@@ -1549,7 +1558,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .WhereIF(dto.FiledType is FiledType.OrgFiled, d => d.FileOrgIsCenter == false) //d => d.ProcessType == EProcessType.Jiaoban
                                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTagCode == dto.OrderTagCode)// 工单标签
                 .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode)) //工单标签
-                .WhereIF(!string.IsNullOrEmpty(dto.FocusOnEvents), d => d.FocusOnEvents.Contains(dto.FocusOnEvents))//!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
+                .WhereIF(!string.IsNullOrEmpty(dto.FocusOnEvents),
+                    d => d.FocusOnEvents.Contains(dto
+                        .FocusOnEvents)) //!string.IsNullOrEmpty(d.FocusOnEvents) && SqlFunc.SplitIn(d.FocusOnEvents, dto.FocusOnEvents))
                 .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) //默认排序时间为创建时间
                 .OrderByIF(dto is { SortField: "no", SortRule: 0 }, d => d.No, OrderByType.Asc) //工单编号升序
                 .OrderByIF(dto is { SortField: "no", SortRule: 1 }, d => d.No, OrderByType.Desc) //工单编号降序
@@ -3072,6 +3083,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Where(x => x.HandlerName != null && x.HandlerName != "")
             .WhereIF(dto.AuditType is 1, x => x.Name == "班长审批")
             .WhereIF(dto.AuditType is 2, x => x.Name == "中心领导")
+             .WhereIF(_appOptions.Value.IsZiGong && dto.AuditType is 3, x => x.Name == "中心初审")
             .GroupBy(x => new { x.HandlerName })
             .Select(x => new OrderScreenAuditVo
             {
@@ -3263,33 +3275,30 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             //    x => SqlFunc.JsonListObjectAny(x.OrgHandledAttitude, "Key", dto.OrgHandledAttitude))
             //.WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason),
             //    x => SqlFunc.JsonField(x.OrgNoSatisfiedReason, "Key") == dto.OrgNoSatisfiedReason)
-            .Where(x => x.OrderVisit.VisitState == EVisitState.Visited && x.OrderVisit.IsCanHandle);
+            .Where(x => x.OrderVisit.VisitState == EVisitState.Visited && x.OrderVisit.IsCanHandle)
+            .WhereIF(dto.DataScope is 1, x => x.VisitOrgCode == _sessionContext.OrgId);
         if (_sessionContext.OrgId != null && !_sessionContext.OrgIsCenter)
         {
-            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-                    x => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
-                         x.OrderVisit.Order.No.Contains(dto.Keyword!))
-                .Where(x => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode == _sessionContext.OrgId && (
+            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.Title.Contains(dto.Keyword!) || x.OrderVisit.Order.No.Contains(dto.Keyword!))
+                .Where(x => x.VisitTarget == EVisitTarget.Org && (
                     SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
                     SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
-                ));
+                ))
+                .WhereIF(dto.DataScope is 0, x => x.VisitOrgCode.StartsWith(_sessionContext.OrgId))
+                ;
         }
         else
         {
-            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-                    x => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
-                         x.OrderVisit.Order.No.Contains(dto.Keyword!))
+            query.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.Title.Contains(dto.Keyword!) || x.OrderVisit.Order.No.Contains(dto.Keyword!))
                 .WhereIF(dto.ScreenType == EOrderScreenType.Org, x => x.VisitTarget == EVisitTarget.Org && (
                     SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
                     SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
                 ))
-                .WhereIF(dto.ScreenType == EOrderScreenType.Seat,
-                    x => x.VisitTarget == EVisitTarget.Seat &&
-                         (x.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied || x.SeatEvaluate == ESeatEvaluate.NoSatisfied))
+                .WhereIF(dto.ScreenType == EOrderScreenType.Seat, x => x.VisitTarget == EVisitTarget.Seat && (x.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied || x.SeatEvaluate == ESeatEvaluate.NoSatisfied))
                 ;
         }
 
@@ -3301,7 +3310,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .OrderByIF(dto is { SortRule: 1, SortField: "order.filedTime" }, x => x.OrderVisit.Order.FiledTime, OrderByType.Desc)
             .OrderByIF(dto is { SortRule: 0, SortField: "orderVisit.visitTime" }, x => x.OrderVisit.VisitTime, OrderByType.Asc)
             .OrderByIF(dto is { SortRule: 1, SortField: "orderVisit.visitTime" }, x => x.OrderVisit.VisitTime, OrderByType.Desc)
-            .OrderByIF(dto is { SortRule: 0, SortField: "screenByEndTime" }, x => x.ScreenByEndTime, OrderByType.Asc)
+            .OrderByIF(dto is { SortRule: 0, SortField: "screenByEndTime" }, x => x.ScreenByEndTime, OrderByType.Asc)//截止申请日期排序
             .OrderByIF(dto is { SortRule: 1, SortField: "screenByEndTime" }, x => x.ScreenByEndTime, OrderByType.Desc)
             .OrderByIF(dto.SortRule is null, x => x.CreationTime, OrderByType.Desc);
     }
@@ -3462,7 +3471,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.IsAiVisit.HasValue && dto.IsAiVisit == true, d => d.AiVisitCount <= 0) //(未建立过)
             .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.Order.SourceChannelCode == dto.Channel)
             .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode),
-            d => SqlFunc.Subqueryable<OrderRelationTag>().InnerJoin<SystemDicData>((s, p) => s.TagId == p.Id).Where((s, p) => p.DicDataValue == dto.OrderTagCode && d.OrderId == s.OrderId).Any())//工单标签
+                d => SqlFunc.Subqueryable<OrderRelationTag>().InnerJoin<SystemDicData>((s, p) => s.TagId == p.Id)
+                    .Where((s, p) => p.DicDataValue == dto.OrderTagCode && d.OrderId == s.OrderId).Any()) //工单标签
             .OrderByIF(dto.VisitStateQuery != EVisitStateQuery.Visited, d => d.Order.IsUrgent, OrderByType.Desc)
             .OrderByDescending(d => d.PublishTime);
         return query;
@@ -3630,7 +3640,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _sessionContext.ChangeSession(startStep.HandlerId);
         var isAutoFillSummaryOpinion = _systemSettingCacheManager.IsAutoFillSummaryOpinion;
 
-        await _workflowDomainService.NextAsync(operater, nextDto, order.ExpiredTime, isAutoFillSummaryOpinion,
+        await _workflowDomainService.NextAsync(operater, nextDto,
+            expiredTime: order.ExpiredTime,
+            isAutoFillSummaryOpinion: isAutoFillSummaryOpinion,
             cancellationToken: cancellationToken);
     }
 
@@ -4099,6 +4111,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 },
                 cancellation);
 
+
+        //if (order.ActualHandleOrgCode != OrgSeedData.CenterId && order.Status < EOrderStatus.Filed)
+        //{
+        //	await _circularRecordDomainService.OrderSpecialCircularMessage(special, order, cancellation);
+        //}
+
         if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
         {
             special.NextHandlers = new List<StepAssignInfo> { newStep.GetWorkflowStepHandler() };
@@ -4785,8 +4803,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
             .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status) //工单状态
             .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.CurrentStepCode == dto.CurrentStepCode) //当前办理节点
-            .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode))//工单标签
-                                                                                                                              //.OrderByDescending(d => d.IsUrgent)
+            .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTagCode)) //工单标签
+                                                                                                                               //.OrderByDescending(d => d.IsUrgent)
             .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.IsUrgent, OrderByType.Desc)
             .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.StartTime, OrderByType.Desc)
             .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.CreationTime, OrderByType.Asc) //创建时间升序
@@ -5004,17 +5022,15 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-
     public ISugarQueryable<ExtendedSendBackVo> ExtendedSendBackStatistics(PagedKeywordRequest dto)
     {
-
         var query = _orderSendBackAuditRepository.Queryable()
-            .Where(x => x.ApplyOrgId.Length == 6)
+            .Where(x => x.ApplyOrgId.Length == 6 && x.CreationTime > x.OrderExpiredTime)
+            .WhereIF(!_sessionContext.OrgIsCenter, x => x.ApplyOrgId == _sessionContext.OrgId)
             .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
             .GroupBy(x => new { x.ApplyOrgId, x.ApplyOrgName })
             .Select(x => new ExtendedSendBackVo()
             {
-
                 OrgId = x.ApplyOrgId,
                 OrgName = x.ApplyOrgName,
                 TotalNum = SqlFunc.AggregateSum(1),
@@ -5034,37 +5050,38 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     public ISugarQueryable<OrderSendBackAudit> ExtendedSendBackDetail(ExtendedSendBackRequest dto)
     {
         var query = _orderSendBackAuditRepository.Queryable()
-            .Includes(x => x.Order)
-            .Where(x => x.ApplyOrgId.Length == 6)
-            .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
-            .WhereIF(!_sessionContext.OrgIsCenter, x => x.ApplyOrgId == _sessionContext.RequiredOrgId)
-            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!))
-            .WhereIF(!string.IsNullOrEmpty(dto.Titel), x => x.Order.Title.Contains(dto.Titel!))
-            .WhereIF(!string.IsNullOrEmpty(dto.OrgId), x => x.ApplyOrgId == dto.OrgId)
-            .WhereIF(dto.Type is ExtendedSendBackType.PassNum, x => x.State == ESendBackAuditState.End)
-            .WhereIF(dto.Type is ExtendedSendBackType.NoPassNum, x => x.State == ESendBackAuditState.Refuse)
-            .WhereIF(dto.Type is ExtendedSendBackType.AuditNum, x => x.State == ESendBackAuditState.Apply)
-            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.Order.AcceptTypeCode == dto.AcceptType) //受理类型
-            .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel) //来源渠道
-            .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot))//热点分类
-            .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart) //受理时间开始
-            .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd) //受理时间结束
-            .WhereIF(!string.IsNullOrEmpty(dto.ApplyOrgName), x => x.ApplyOrgName == dto.ApplyOrgName!) //申请部门
-            .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), x => x.CreatorName == dto.ApplyUserName!) //申请人
-            .WhereIF(dto.State.HasValue, x => x.State == dto.State) //退回审批状态
-            .WhereIF(!string.IsNullOrEmpty(dto.AuditUser), x => x.AuditUser == dto.AuditUser!) //审批人
-            .WhereIF(dto.AuditTimeStart.HasValue && dto.AuditTimeEnd.HasValue, x => x.AuditTime >= dto.AuditTimeStart && x.AuditTime <= dto.AuditTimeEnd)// 审批时间
-            .WhereIF(!string.IsNullOrEmpty(dto.AuditContent), x => x.AuditContent.Contains(dto.AuditContent!))//审批意见
-            .OrderByIF(string.IsNullOrEmpty(dto.SortField), x => x.CreationTime, OrderByType.Desc)
-            .OrderByIF(dto is { SortField: "order.startTime", SortRule: 0 }, x => x.Order.StartTime, OrderByType.Asc)
-            .OrderByIF(dto is { SortField: "order.startTime", SortRule: 1 }, x => x.Order.StartTime, OrderByType.Desc)
-            .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, x => x.CreationTime, OrderByType.Asc)
-            .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, x => x.CreationTime, OrderByType.Desc)
-            .OrderByIF(dto is { SortField: "auditTime", SortRule: 0 }, x => x.AuditTime, OrderByType.Asc)
-            .OrderByIF(dto is { SortField: "auditTime", SortRule: 1 }, x => x.AuditTime, OrderByType.Desc)
+                .Includes(x => x.Order)
+                .Where(x => x.ApplyOrgId.Length == 6 && x.CreationTime > x.OrderExpiredTime)
+                .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, x => x.CreationTime >= dto.StartTime && x.CreationTime <= dto.EndTime)
+                .WhereIF(!_sessionContext.OrgIsCenter, x => x.ApplyOrgId == _sessionContext.RequiredOrgId)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!))
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgId), x => x.ApplyOrgId == dto.OrgId)
+                .WhereIF(dto.Type is ExtendedSendBackType.PassNum, x => x.State == ESendBackAuditState.End)
+                .WhereIF(dto.Type is ExtendedSendBackType.NoPassNum, x => x.State == ESendBackAuditState.Refuse)
+                .WhereIF(dto.Type is ExtendedSendBackType.AuditNum, x => x.State == ESendBackAuditState.Apply)
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.Order.AcceptTypeCode == dto.AcceptType) //受理类型
+                .WhereIF(!string.IsNullOrEmpty(dto.Channel), x => x.Order.SourceChannelCode == dto.Channel) //来源渠道
+                .WhereIF(!string.IsNullOrEmpty(dto.Hotspot),
+                    x => x.Order.HotspotSpliceName != null && x.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点分类
+                .WhereIF(dto.CreationTimeStart.HasValue, x => x.Order.CreationTime >= dto.CreationTimeStart) //受理时间开始
+                .WhereIF(dto.CreationTimeEnd.HasValue, x => x.Order.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+                .WhereIF(!string.IsNullOrEmpty(dto.ApplyOrgName), x => x.ApplyOrgName == dto.ApplyOrgName!) //申请部门
+                .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), x => x.CreatorName == dto.ApplyUserName!) //申请人
+                .WhereIF(dto.State.HasValue, x => x.State == dto.State) //退回审批状态
+                .WhereIF(!string.IsNullOrEmpty(dto.AuditUser), x => x.AuditUser == dto.AuditUser!) //审批人
+                .WhereIF(dto.AuditTimeStart.HasValue && dto.AuditTimeEnd.HasValue,
+                    x => x.AuditTime >= dto.AuditTimeStart && x.AuditTime <= dto.AuditTimeEnd) // 审批时间
+                .WhereIF(!string.IsNullOrEmpty(dto.AuditContent), x => x.AuditContent.Contains(dto.AuditContent!)) //审批意见
+                .OrderByIF(string.IsNullOrEmpty(dto.SortField), x => x.CreationTime, OrderByType.Desc)
+                .OrderByIF(dto is { SortField: "order.startTime", SortRule: 0 }, x => x.Order.StartTime, OrderByType.Asc)
+                .OrderByIF(dto is { SortField: "order.startTime", SortRule: 1 }, x => x.Order.StartTime, OrderByType.Desc)
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, x => x.CreationTime, OrderByType.Asc)
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, x => x.CreationTime, OrderByType.Desc)
+                .OrderByIF(dto is { SortField: "auditTime", SortRule: 0 }, x => x.AuditTime, OrderByType.Asc)
+                .OrderByIF(dto is { SortField: "auditTime", SortRule: 1 }, x => x.AuditTime, OrderByType.Desc)
             ;
         return query;
-
     }
 
 
@@ -5098,33 +5115,32 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         }
 
         return query
-            .Includes(d => d.Order)
-            .Includes(d => d.Workflow)
-            //如果查询全部
-            //1.1、热线中心用户看系统中所有已申请延期的工单(需排除取消延期的工单)和自动延期的工单
-            //1.2、部门用户看部门及其下级部门已申请延期的工单(需排除取消延期的工单)和部门办理中时自动延期的工单
-            .WhereIF(dto.DataScope is 0, d => (d.AutomaticDelayNum == 0 || d.AutomaticDelayNum == null) && d.DelayState != EDelayState.Withdraw)
-            .WhereIF(dto.DataScope is 0 && !_sessionContext.OrgIsCenter, d => d.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId))
-            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
-            .WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
-            .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
-            .WhereIF(dto.DelayState != null, d => d.DelayState == dto.DelayState)
-            //延期列表页面数据范围快捷查询条件选中“我的“时需排除取消延期的工单
-            .WhereIF(dto.DataScope is 1, d => d.CreatorId == _sessionContext.RequiredUserId && d.DelayState != EDelayState.Withdraw)
-            .WhereIF(dto.QueryDelayState is EQueryDelayState.Examining, d => d.DelayState == EDelayState.Examining)
-            .WhereIF(dto.QueryDelayState is EQueryDelayState.Pass, d => d.DelayState == EDelayState.Pass)
-            .WhereIF(dto.QueryDelayState is EQueryDelayState.NoPass, d => d.DelayState == EDelayState.NoPass)
-            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName),
-                d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandleStepName == dto.CurrentStepName) //当前节点
-            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName),
-                d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandlerName == dto.ActualHandlerName) // 审批人
-            .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.Order.OrgLevelOneName == dto.OrgLevelOneName) //一级部门
-            .WhereIF(dto.StartCreationTime.HasValue && dto.EndCreationTime.HasValue,
-                d => d.CreationTime >= dto.StartCreationTime && d.CreationTime <= dto.EndCreationTime) // 申请时间
-            .OrderByDescending(d => d.ApplyDelayTime)
-           ;
-
+                .Includes(d => d.Order)
+                .Includes(d => d.Workflow)
+                //如果查询全部
+                //1.1、热线中心用户看系统中所有已申请延期的工单(需排除取消延期的工单)和自动延期的工单
+                //1.2、部门用户看部门及其下级部门已申请延期的工单(需排除取消延期的工单)和部门办理中时自动延期的工单
+                .WhereIF(dto.DataScope is 0, d => (d.AutomaticDelayNum == 0 || d.AutomaticDelayNum == null) && d.DelayState != EDelayState.Withdraw)
+                .WhereIF(dto.DataScope is 0 && !_sessionContext.OrgIsCenter, d => d.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId))
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                    d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
+                .WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
+                .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
+                .WhereIF(dto.DelayState != null, d => d.DelayState == dto.DelayState)
+                //延期列表页面数据范围快捷查询条件选中“我的“时需排除取消延期的工单
+                .WhereIF(dto.DataScope is 1, d => d.CreatorId == _sessionContext.RequiredUserId && d.DelayState != EDelayState.Withdraw)
+                .WhereIF(dto.QueryDelayState is EQueryDelayState.Examining, d => d.DelayState == EDelayState.Examining)
+                .WhereIF(dto.QueryDelayState is EQueryDelayState.Pass, d => d.DelayState == EDelayState.Pass)
+                .WhereIF(dto.QueryDelayState is EQueryDelayState.NoPass, d => d.DelayState == EDelayState.NoPass)
+                .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName),
+                    d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandleStepName == dto.CurrentStepName) //当前节点
+                .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName),
+                    d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandlerName == dto.ActualHandlerName) // 审批人
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.Order.OrgLevelOneName == dto.OrgLevelOneName) //一级部门
+                .WhereIF(dto.StartCreationTime.HasValue && dto.EndCreationTime.HasValue,
+                    d => d.CreationTime >= dto.StartCreationTime && d.CreationTime <= dto.EndCreationTime) // 申请时间
+                .OrderByDescending(d => d.ApplyDelayTime)
+            ;
     }
 
     /// <summary>
@@ -5136,17 +5152,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var isAdmin = _orderDomainService.IsCheckAdmin();
         var isHandled = dto.IsApply.HasValue && dto.IsApply.Value;
         var query = _orderDelayRepository
-            .Queryable(hasHandled: isHandled, isAdmin: isAdmin)
-            .Includes(d => d.Order)
-            .Includes(d => d.Workflow)
-            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-                d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
-            //.WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
-            .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
-            //.WhereIF(dto.DelayState != null, x => x.DelayState == dto.DelayState)
-            //.Where(x=>x.DelayState == EDelayState.Examining)
-            .OrderByDescending(d => d.ApplyDelayTime)
-           ;
+                .Queryable(hasHandled: isHandled, isAdmin: isAdmin)
+                .Includes(d => d.Order)
+                .Includes(d => d.Workflow)
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                    d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
+                //.WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining)
+                .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
+                //.WhereIF(dto.DelayState != null, x => x.DelayState == dto.DelayState)
+                //.Where(x=>x.DelayState == EDelayState.Examining)
+                .OrderByDescending(d => d.ApplyDelayTime)
+            ;
 
         return query;
     }
@@ -5155,47 +5171,12 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 
     public async Task OrderPrevious(OrderSendBackAudit sendBack, Order order, CancellationToken cancellationToken)
     {
-
-        //var (workflow, currentStep, prevDefine, prevStep, newStep, flowDirection) =
-        //       await _workflowApplication.PreviousAsync(sendBack.SendBackData,
-        //           async (workflow1, currentStep1, prevStepDefine, prevStep1, newStep) =>
-        //           {
-        //               var stepAssignInfo =
-        //                   await GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, cancellationToken);
-        //               if (stepAssignInfo is null) return;
-        //               var validator = new StepAssignInfoValidator();
-        //               await validator.ValidateAndThrowAsync(stepAssignInfo);
-        //               newStep.Assign(stepAssignInfo);
-        //               if (sendBack.AssignStepId != prevStep1.Id) prevStep1.HandleMode = EHandleMode.PreviousNoDisplay;
-        //           },
-        //           cancellationToken);
-
-        //if (sendBack.IsAssign.Value)
-        //{
-        //    while (sendBack.AssignStepId != prevStep.Id)
-        //    {
-        //        (workflow, currentStep, prevDefine, prevStep, newStep, flowDirection) =
-        //       await _workflowApplication.PreviousAsync(sendBack.SendBackData,
-        //           async (workflow1, currentStep1, prevStepDefine, prevStep1, newStep) =>
-        //           {
-        //               var stepAssignInfo =
-        //                   await GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, cancellationToken);
-        //               if (stepAssignInfo is null) return;
-        //               var validator = new StepAssignInfoValidator();
-        //               await validator.ValidateAndThrowAsync(stepAssignInfo);
-        //               newStep.Assign(stepAssignInfo);
-        //               if (sendBack.AssignStepId != prevStep.Id) prevStep1.HandleMode = EHandleMode.PreviousNoDisplay;
-        //           },
-        //           cancellationToken);
-        //    }
-        //}
-
         var handleMode = EHandleMode.Previous;
         WorkflowStep? currentStep, prevStep, newStep, startStep = null;
         EFlowDirection flowDirection;
-        var userId = _sessionContextProvider.SessionContext.RequiredUserId;
-        var orgId = _sessionContextProvider.SessionContext.RequiredOrgId;
-        var roles = _sessionContextProvider.SessionContext.Roles;
+        var userId = sendBack.WorkflowUserId;
+        var orgId = sendBack.WorkflowOrgId;
+        var roles = sendBack.WorkflowRoleIds.ToArray();
         do
         {
             (_, currentStep, _, prevStep, newStep, flowDirection) =
@@ -5209,16 +5190,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                         var validator = new StepAssignInfoValidator();
                         await validator.ValidateAndThrowAsync(stepAssignInfo);
                         newStep.Assign(stepAssignInfo);
-
-                        if (sendBack.AssignStepId != prevStep1.Id) handleMode = EHandleMode.PreviousNoDisplay;
                     },
                     cancellationToken);
 
+            if (sendBack.AssignStepId != prevStep.Id) handleMode = EHandleMode.PreviousNoDisplay;
             startStep ??= currentStep;
             userId = prevStep.HandlerId;
             orgId = prevStep.HandlerOrgId;
             roles = [prevStep.RoleId];
-        } while (sendBack.AssignStepId != prevStep.Id && prevStep.StepType is not EStepType.Start && !prevStep.IsOrigin);
+        } while (!string.IsNullOrEmpty(sendBack.AssignStepId) &&
+                 sendBack.AssignStepId != prevStep.Id &&
+                 prevStep.StepType is not EStepType.Start);
 
         sendBack.ApplyOrgId = currentStep.AcceptorOrgId;
         sendBack.ApplyOrgName = currentStep!.AcceptorOrgName;
@@ -5240,17 +5222,20 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         if (prevStep.BusinessType == EBusinessType.Send)
         {
             await _orderRepository.Updateable().SetColumns(o => new Order()
-            { CenterToOrgHandlerId = newStep.HandlerId, CenterToOrgHandlerName = newStep.HandlerName, ProcessType = processType, SendBackNum = order.SendBackNum })
+            {
+                CenterToOrgHandlerId = newStep.HandlerId,
+                CenterToOrgHandlerName = newStep.HandlerName,
+                ProcessType = processType,
+                SendBackNum = order.SendBackNum
+            })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
         }
         else
         {
             await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType, SendBackNum = order.SendBackNum })
-            .Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
+                .Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
         }
-
-
-        await _orderSendBackAuditRepository.AddAsync(sendBack, cancellationToken);
     }
+
     #endregion
 }

+ 54 - 0
src/Hotline.Application/SpecialNumber/ISpecialNumberApplication.cs

@@ -0,0 +1,54 @@
+using Hotline.Share.Dtos.Special;
+
+namespace Hotline.Application.SpecialNumber
+{
+    public interface ISpecialNumberApplication
+    {
+        #region 特殊号码
+
+        /// <summary>
+        /// 特殊号码 - 列表
+        /// </summary>
+        /// <param name="pagedDto"></param>
+        /// <returns></returns>
+        Task<(int, IList<SpecialNumberInfoDto>)> QueryAllSpecialNumberListAsync(SpecialNumberDto pagedDto, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 特殊号码 - 新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        Task<string> AddSpecialNumberAsync(AddSpecialNumberDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///特殊号码 - 编辑
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task UpdateSpecialNumberAsync(UpdateSpecialNumberDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///特殊号码 - 删除
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task RemoveSpecialNumberAsync(DelSpecialNumberDto dto, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///特殊号码 - 详情
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <returns></returns>
+        Task<SpecialNumberInfoDto> GetSpecialNumberAsync(string Id, CancellationToken cancellationToken);
+
+        /// <summary>
+        ///特殊号码 - 详情
+        /// </summary>
+        /// <param name="PhoneNumber"></param>
+        /// <returns></returns>
+        Task<SpecialNumberInfoDto> GetSpecialNumberByAsync(string PhoneNumber, CancellationToken cancellationToken);
+
+        #endregion
+    }
+}

+ 169 - 0
src/Hotline.Application/SpecialNumber/SpecialNumberApplication.cs

@@ -0,0 +1,169 @@
+using MapsterMapper;
+using SqlSugar;
+using XF.Domain.Authentications;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+using Hotline.Repository.SqlSugar.Extensions;
+using Hotline.Share.Dtos.Special;
+
+namespace Hotline.Application.SpecialNumber
+{
+    public class SpecialNumberApplication : ISpecialNumberApplication, IScopeDependency
+    {
+        #region 注册
+
+        private readonly IRepository<Hotline.Special.SpecialNumber> _specialNumberRepository;
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+
+        public SpecialNumberApplication(
+            IRepository<Hotline.Special.SpecialNumber> specialNumberRepository,
+            ISessionContext sessionContext,
+            IMapper mapper)
+        {
+            _specialNumberRepository = specialNumberRepository;
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+        }
+
+        #endregion
+
+        #region 特殊号码
+
+        #region 特殊号码 - 列表
+
+        /// <summary>
+        /// 特殊号码 - 列表
+        /// </summary>
+        /// <param name="pagedDto"></param>
+        /// <returns></returns>
+        public async Task<(int, IList<SpecialNumberInfoDto>)> QueryAllSpecialNumberListAsync(SpecialNumberDto dto, CancellationToken cancellationToken)
+        {
+            var typeSpliceName = string.Empty;
+
+            //单表分页
+            var (total, temp) = await _specialNumberRepository.Queryable()
+
+                .WhereIF(!string.IsNullOrEmpty(dto.PhoneNumber), x => x.PhoneNumber.Contains(dto.PhoneNumber))
+                .WhereIF(!string.IsNullOrEmpty(dto.Notes), x => x.Notes.Contains(dto.Notes))
+                .WhereIF(dto.CreationTimeStart.HasValue, x => x.CreationTime >= dto.CreationTimeStart)
+                .WhereIF(dto.CreationTimeEnd.HasValue, x => x.CreationTime <= dto.CreationTimeEnd)
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, x => x.CreationTime, OrderByType.Asc)  //创建时间升序
+                .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, x => x.CreationTime, OrderByType.Desc) //创建时间降序
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, cancellationToken);
+            return (total, _mapper.Map<IList<SpecialNumberInfoDto>>(temp));
+            //return (total, temp);
+        }
+
+        #endregion
+
+        #region 特殊号码 - 新增
+
+        /// <summary>
+        /// 新增
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task<string> AddSpecialNumberAsync(AddSpecialNumberDto dto, CancellationToken cancellationToken)
+        {
+            var data = _mapper.Map<Hotline.Special.SpecialNumber>(dto);
+
+            var any = await _specialNumberRepository.Queryable().Where(x => x.PhoneNumber == dto.PhoneNumber).AnyAsync();
+            if (any)
+                throw UserFriendlyException.SameMessage("特殊号码已存在!");
+
+            data.InitId();
+
+            return await _specialNumberRepository.AddAsync(data, cancellationToken);
+        }
+
+        #endregion
+
+        #region 特殊号码 - 修改
+
+        /// <summary>
+        /// 修改
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task UpdateSpecialNumberAsync(UpdateSpecialNumberDto dto, CancellationToken cancellationToken)
+        {
+            var data = await _specialNumberRepository.GetAsync(dto.Id);
+
+            if (data == null)
+                throw UserFriendlyException.SameMessage("特殊号码查询失败");
+
+            var any = await _specialNumberRepository.Queryable().Where(x => x.PhoneNumber == dto.PhoneNumber && x.Id != dto.Id).AnyAsync();
+            if (any)
+                throw UserFriendlyException.SameMessage("特殊号码已存在!");
+
+            data.PhoneNumber = dto.PhoneNumber;
+            data.Notes = dto.Notes;
+
+            await _specialNumberRepository.UpdateAsync(data, cancellationToken);
+        }
+
+        #endregion
+
+        #region 特殊号码 - 删除
+
+        /// <summary>
+        /// 删除
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task RemoveSpecialNumberAsync(DelSpecialNumberDto dto, CancellationToken cancellationToken)
+        {
+            var data = await _specialNumberRepository.GetAsync(dto.Id);
+
+            if (data == null)
+                throw UserFriendlyException.SameMessage("特殊号码查询失败");
+
+            await _specialNumberRepository.RemoveAsync(data, false, cancellationToken);
+        }
+
+        #endregion
+
+        #region 特殊号码 - 详情
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <returns></returns>
+        public async Task<SpecialNumberInfoDto> GetSpecialNumberAsync(string Id, CancellationToken cancellationToken)
+        {
+            var data = await _specialNumberRepository.Queryable()
+                .Where(x => x.Id == Id).FirstAsync();
+            if (data == null)
+                throw UserFriendlyException.SameMessage("特殊号码查询失败");
+            return _mapper.Map<SpecialNumberInfoDto>(data);
+        }
+
+        #endregion
+
+        #region 特殊号码 - 详情
+
+        /// <summary>
+        /// 详情
+        /// </summary>
+        /// <param name="PhoneNumber"></param>
+        /// <returns></returns>
+        public async Task<SpecialNumberInfoDto> GetSpecialNumberByAsync(string PhoneNumber, CancellationToken cancellationToken)
+        {
+            var data = await _specialNumberRepository.Queryable()
+                .Where(x => x.PhoneNumber == PhoneNumber).FirstAsync();
+            if (data == null)
+                throw UserFriendlyException.SameMessage("特殊号码查询失败");
+            return _mapper.Map<SpecialNumberInfoDto>(data);
+        }
+
+        #endregion
+
+        #endregion
+    }
+}

+ 19 - 1
src/Hotline.Repository.SqlSugar/File/FileRepository.cs

@@ -45,7 +45,25 @@ namespace Hotline.Repository.SqlSugar.File
             return entities.Select(x => new FileJson { Id = x.Id, FileId = x.Additions, Path = x.Path, FileName = x.Name, FileType = x.Type }).ToList();
         }
 
-        public async Task<List<FileJson>> AddFileAsync(List<FileDto> files, string id, string flowId = "", CancellationToken cancellationToken = default) 
+		public async Task<List<FileJson>> AddFileAsync(IList<FileDto> files, string id, CancellationToken requestAborted)
+		{
+			var entities = files.Adapt<List<Hotline.File.File>>();
+			foreach (var file in entities)
+			{
+				var names = file.FileName.Split(".");
+				file.Name = names[0];
+				file.Type = names[1];
+				file.Key = id;
+				file.OrgName = _sessionContext.OrgName;
+				file.OrgId = _sessionContext.OrgId;
+				file.UserId = _sessionContext.UserId;
+				file.UserName = _sessionContext.UserName;
+			}
+			await AddRangeAsync(entities, requestAborted);
+			return entities.Select(x => new FileJson { Id = x.Id, FileId = x.Additions, Path = x.Path, FileName = x.Name, FileType = x.Type }).ToList();
+		}
+
+		public async Task<List<FileJson>> AddFileAsync(List<FileDto> files, string id, string flowId = "", CancellationToken cancellationToken = default) 
 		{
 			List<Hotline.File.File> newFiles =  new List<Hotline.File.File>();
 			var classify = files[0].Classify;

+ 1 - 1
src/Hotline.Share/Dtos/Article/BulletinDto.cs

@@ -296,7 +296,7 @@ namespace Hotline.Share.Dtos.Article
         public List<CircularReadGroupDto> CircularReadGroups { get; set; }
     }
 
-    public record UpdateCircularDto : AddCircularDto
+	public record UpdateCircularDto : AddCircularDto
     {
         public string Id { get; set; }
     }

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

@@ -982,6 +982,8 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public DateTime? ScreenByEndTime { get; set; }
 
+        public bool? IsShowOperate { get; set; }
+
     }
 
     /// <summary>

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

@@ -19,6 +19,11 @@ namespace Hotline.Share.Dtos.Order
         /// 本地编号(√)
         /// </summary>
         public string No { get; set; }
+        
+        /// <summary>
+        /// 标题
+        /// </summary>
+        public string? Title { get; set; }
 
         /// <summary>
         /// 诉求内容
@@ -850,6 +855,11 @@ namespace Hotline.Share.Dtos.Order
         /// 受理坐席名字或工号(×)
         /// </summary>
         public string? NameOrNo { get; set; }
+
+        /// <summary>
+        /// 0 全部  1 我的(本部门)
+        /// </summary>
+        public int? DataScope { get; set; }
     }
 
     public record UrgeListDto : PagedKeywordRequest

+ 87 - 0
src/Hotline.Share/Dtos/Special/SpecialNumberDto.cs

@@ -0,0 +1,87 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.Special
+{
+    public record AddSpecialNumberDto
+    {
+        /// <summary>
+        /// 电话号码
+        /// </summary>
+        public string PhoneNumber { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string? Notes { get; set; }
+    }
+
+    public record UpdateSpecialNumberDto : AddSpecialNumberDto
+    {
+        /// <summary>
+        /// 案例库ID
+        /// </summary>
+        public string Id { get; set; }
+    }
+
+    public record DelSpecialNumberDto
+    {
+        public string Id { get; set; }
+    }
+
+    public record SpecialNumberDto : PagedRequest
+    {
+        /// <summary>
+        /// 电话号码
+        /// </summary>
+        public string PhoneNumber { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+
+        public string? Notes { get; set; }
+
+        /// <summary>
+        /// 创建开始时间
+        /// </summary>
+        public DateTime? CreationTimeStart { get; set; }
+
+        /// <summary>
+        /// 创建结束时间
+        /// </summary>
+        public DateTime? CreationTimeEnd { get; set; }
+
+        /// <summary>
+        /// 排序字段
+        /// </summary>
+        public string? SortField { get; set; } = "creationTime";
+
+        /// <summary>
+        /// 排序方式 // 0 升序 1 降序
+        /// </summary>
+        public int? SortRule { get; set; } = 0;
+    }
+
+    public record SpecialNumberInfoDto
+    {
+        /// <summary>
+        /// 特殊电话ID
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 电话号码
+        /// </summary>
+        public string PhoneNumber { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        public string? Notes { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime? CreationTime { get; set; }
+    }
+}

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

@@ -13,6 +13,12 @@ public enum EHandleMode
     [Description("正常")]
     Normal = 0,
 
+    /// <summary>
+    /// 跨级派单
+    /// </summary>
+    [Description("跨级派单")]
+    CrossLevel = 1,
+
     /// <summary>
     /// 审核通过(审批流程特有)
     /// </summary>

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

@@ -87,4 +87,7 @@ public enum EPushBusiness
 
     [Description("随手拍短信")]
     Snapshot = 13,
+
+    [Description("甄别完成")]
+    ScreenEnd=14,
 }

+ 2 - 2
src/Hotline.Share/Requests/PagedKeywordRequest.cs

@@ -1008,7 +1008,7 @@ public record OrderScreenAuditPagedRequest : PagedKeywordRequest
     public string AuditUserName { get; set; }
 
     /// <summary>
-    ///  1 中心班长   2 中心领导
+    ///  1 中心班长   2 中心领导 3中心初审
     /// </summary>
     public int? AuditType { get; set; }
 
@@ -1543,7 +1543,7 @@ public record ExtendedSendBackRequest : PagedKeywordRequest
 {
     public string? No { get; set; }
 
-    public string? Titel { get; set; }
+    public string? Title { get; set; }
 
     public string? OrgId { get; set; }
 

+ 35 - 2
src/Hotline/Article/CircularRecordDomainService.cs

@@ -1,4 +1,5 @@
-using Hotline.Realtimes;
+using Hotline.Orders;
+using Hotline.Realtimes;
 using Hotline.Share.Dtos.Article;
 using Hotline.Share.Enums.Article;
 using MapsterMapper;
@@ -169,5 +170,37 @@ namespace Hotline.Article
                 }
             }
         }
-    }
+
+
+
+        /// <summary>
+        /// 特提处理通知公告
+        /// </summary>
+        /// <param name="special"></param>
+        /// <param name="order"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public async Task OrderSpecialCircularMessage(OrderSpecial special,Order order,CancellationToken cancellationToken = default) {
+
+			var cMessage = new AddCircularDto
+			{
+				Title = "信件特提信息",
+				Content = $"编号为{order.No}的工单已被特提。",
+				CircularTypeId = "1",
+				CircularTypeName = "公告通知",
+				CircularType = ECircularType.Org,
+				IsMustRead = false,
+				SourceOrgId = _sessionContext.RequiredOrgId,
+				SourceOrgName = _sessionContext.OrgName
+			};
+			var groups = new CircularReadGroupDto
+			{
+				OrgId = order.ActualHandleOrgCode,
+				OrgName = order.ActualHandleOrgName
+			};
+			cMessage.CircularReadGroups = new List<CircularReadGroupDto> { groups };
+
+		}
+
+	}
 }

+ 6 - 1
src/Hotline/Article/ICircularRecordDomainService.cs

@@ -1,4 +1,5 @@
 
+using Hotline.Orders;
 using Hotline.Share.Dtos.Article;
 
 namespace Hotline.Article
@@ -16,5 +17,9 @@ namespace Hotline.Article
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
         Task AddCircularMessage(AddCircularDto dto, CancellationToken cancellationToken = default);
-    }
+
+
+        Task OrderSpecialCircularMessage(OrderSpecial special, Order order, CancellationToken cancellationToken = default);
+
+	}
 }

+ 3 - 1
src/Hotline/File/IFileRepository.cs

@@ -18,5 +18,7 @@ namespace Hotline.File
 		Task<List<WorkflowTraceDto>> WorkflowTraceRecursion(List<WorkflowTraceDto> dto, CancellationToken cancellationToken);
 		Task<List<Hotline.File.File>> GetByKeyAsync(string key, CancellationToken cancellationToken);
         Task<List<FileJson>> AddFileAsync(IList<SnapshotFileInDto> files, string id, CancellationToken requestAborted);
-    }
+		Task<List<FileJson>> AddFileAsync(IList<FileDto> files, string id, CancellationToken requestAborted);
+
+	}
 }

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

@@ -38,7 +38,9 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// new
         /// </summary>
-        Task<(Workflow, WorkflowStep, StepDefine, List<WorkflowStep>)> NextAsync(ISessionContext current, NextWorkflowDto dto,
+        Task<(Workflow, WorkflowStep, StepDefine, List<WorkflowStep>)> NextAsync(
+            ISessionContext current, NextWorkflowDto dto,
+            EHandleMode handleMode = EHandleMode.Normal,
             DateTime? expiredTime = null, bool isAutoFillSummaryOpinion = false,
             Action<Workflow, WorkflowStep, StepDefine>? currentStepConfig = null,
             Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,

+ 177 - 172
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -284,7 +284,8 @@ namespace Hotline.FlowEngine.Workflows
         /// workflow, currentStep, nextStepDefine, nextSteps
         /// </summary>
         public async Task<(Workflow, WorkflowStep, StepDefine, List<WorkflowStep>)> NextAsync(
-            ISessionContext current, NextWorkflowDto dto,
+            ISessionContext current, NextWorkflowDto dto, 
+            EHandleMode handleMode = EHandleMode.Normal,
             DateTime? expiredTime = null, bool isAutoFillSummaryOpinion = false,
             Action<Workflow, WorkflowStep, StepDefine>? currentStepConfig = null,
             Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,
@@ -434,7 +435,7 @@ namespace Hotline.FlowEngine.Workflows
                 }
             }
 
-            await HandleStepAsync(currentStep, workflow, dto, counterSignType, expiredTime, EHandleMode.Normal, cancellationToken);
+            await HandleStepAsync(currentStep, workflow, dto, counterSignType, expiredTime, handleMode, cancellationToken);
 
             currentStep.IsActualHandled = CheckIsActualHandle(workflow, currentStep, nextStepDefine, dto);
 
@@ -608,7 +609,9 @@ namespace Hotline.FlowEngine.Workflows
             nextDto.WorkflowId = workflow.Id;
             nextDto.StepId = startStep.Id;
             var (_, _, _, nextSteps) =
-                await NextAsync(_sessionContextProvider.SessionContext, nextDto, expiredTime, true,
+                await NextAsync(_sessionContextProvider.SessionContext, nextDto, 
+                    expiredTime: expiredTime, 
+                    isAutoFillSummaryOpinion: true,
                     newStepConfig: newStepConfig, cancellationToken: cancellationToken);
             return nextSteps;
         }
@@ -731,164 +734,164 @@ namespace Hotline.FlowEngine.Workflows
             return workflow.ActualHandleStepAcceptTime;
         }
 
-        /// <summary>
-        /// 退回(返回前一节点)
-        /// </summary>
-        /// <returns></returns>
-        public async Task<EFlowDirection> PreviousAsync(Workflow workflow, PreviousWorkflowDto dto,
-            string applicantId, string applicantName,
-            string applicantOrgId, string applicantOrgName,
-            string applicantOrgAreaCode, string applicantOrgAreaName,
-            bool applicantIsCenter, string[] applicantRoleIds,
-            CancellationToken cancellationToken)
-        {
-            //ValidatePermission(workflow, operater.OrgId, operater.Id);
-
-            var (currentStep, prevStep, countersignStartStep) =
-                GetPreviousStep(workflow, applicantId, applicantOrgId, applicantRoleIds);
-
-            //保存附件
-            if (dto.Files.Any())
-                currentStep.FileJson = await _fileRepository.AddFileAsync(
-                    dto.Files, workflow.ExternalId, currentStep.Id, cancellationToken);
+        ///// <summary>
+        ///// 退回(返回前一节点)
+        ///// </summary>
+        ///// <returns></returns>
+        //public async Task<EFlowDirection> PreviousAsync(Workflow workflow, PreviousWorkflowDto dto,
+        //    string applicantId, string applicantName,
+        //    string applicantOrgId, string applicantOrgName,
+        //    string applicantOrgAreaCode, string applicantOrgAreaName,
+        //    bool applicantIsCenter, string[] applicantRoleIds,
+        //    CancellationToken cancellationToken)
+        //{
+        //    //ValidatePermission(workflow, operater.OrgId, operater.Id);
 
-            // add prev current to remove list
-            var removeSteps = new List<WorkflowStep> { currentStep, prevStep };
+        //    var (currentStep, prevStep, countersignStartStep) =
+        //        GetPreviousStep(workflow, applicantId, applicantOrgId, applicantRoleIds);
 
-            if (countersignStartStep is not null)
-            {
-                //add cs steps to remove list
-                SearchCountersignSteps(countersignStartStep, workflow.Steps, ref removeSteps);
+        //    //保存附件
+        //    if (dto.Files.Any())
+        //        currentStep.FileJson = await _fileRepository.AddFileAsync(
+        //            dto.Files, workflow.ExternalId, currentStep.Id, cancellationToken);
 
-                //end cs
-                var currentCountersign =
-                    workflow.Countersigns.FirstOrDefault(d => d.Id == countersignStartStep.StartCountersignId);
-                if (currentCountersign is null)
-                    throw new UserFriendlyException(
-                        $"未查询到对应会签信息,workflowId:{workflow.Id}, countersignId:{currentStep.CountersignId}",
-                        "无效会签编号");
+        //    // add prev current to remove list
+        //    var removeSteps = new List<WorkflowStep> { currentStep, prevStep };
 
-                //结束step会签信息
-                countersignStartStep.CountersignEnd();
-                await _workflowStepRepository.UpdateAsync(countersignStartStep, cancellationToken);
-                //updateSteps.Add(countersignStartStep);
-
-                //结束会签
-                //currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
-                //    current.RequiredUserId, current.UserName,
-                //    current.RequiredOrgId, current.OrgName,
-                //    current.OrgAreaCode, current.OrgAreaName);
-                currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
-                    applicantId, applicantName,
-                    applicantOrgId, applicantOrgName,
-                    applicantOrgAreaCode, applicantOrgAreaName);
-
-                await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
-
-                //update workflow cs status
-                if (workflow.CheckIfCountersignOver())
-                    workflow.EndCountersign();
-            }
+        //    if (countersignStartStep is not null)
+        //    {
+        //        //add cs steps to remove list
+        //        SearchCountersignSteps(countersignStartStep, workflow.Steps, ref removeSteps);
+
+        //        //end cs
+        //        var currentCountersign =
+        //            workflow.Countersigns.FirstOrDefault(d => d.Id == countersignStartStep.StartCountersignId);
+        //        if (currentCountersign is null)
+        //            throw new UserFriendlyException(
+        //                $"未查询到对应会签信息,workflowId:{workflow.Id}, countersignId:{currentStep.CountersignId}",
+        //                "无效会签编号");
+
+        //        //结束step会签信息
+        //        countersignStartStep.CountersignEnd();
+        //        await _workflowStepRepository.UpdateAsync(countersignStartStep, cancellationToken);
+        //        //updateSteps.Add(countersignStartStep);
+
+        //        //结束会签
+        //        //currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
+        //        //    current.RequiredUserId, current.UserName,
+        //        //    current.RequiredOrgId, current.OrgName,
+        //        //    current.OrgAreaCode, current.OrgAreaName);
+        //        currentCountersign.End(currentStep.Id, currentStep.Code, currentStep.BusinessType,
+        //            applicantId, applicantName,
+        //            applicantOrgId, applicantOrgName,
+        //            applicantOrgAreaCode, applicantOrgAreaName);
+
+        //        await _workflowCountersignRepository.UpdateAsync(currentCountersign, cancellationToken);
+
+        //        //update workflow cs status
+        //        if (workflow.CheckIfCountersignOver())
+        //            workflow.EndCountersign();
+        //    }
 
-            //update trace
-            //var trace = await PreviousTraceAsync(workflow.Id, dto, currentStep,
-            //    applicantId, applicantName,
-            //    applicantOrgId, applicantOrgName,
-            //    applicantOrgAreaCode, applicantOrgAreaName,
-            //    applicantIsCenter, cancellationToken);
-            var trace = workflow.Traces.First(t => t.StepId == currentStep.Id);
-            // _mapper.Map(dto, trace);
-            trace.FileJson = currentStep.FileJson;
-            trace.IsSms = dto.AcceptSms;
-            trace.Opinion = dto.Opinion;
+        //    //update trace
+        //    //var trace = await PreviousTraceAsync(workflow.Id, dto, currentStep,
+        //    //    applicantId, applicantName,
+        //    //    applicantOrgId, applicantOrgName,
+        //    //    applicantOrgAreaCode, applicantOrgAreaName,
+        //    //    applicantIsCenter, cancellationToken);
+        //    var trace = workflow.Traces.First(t => t.StepId == currentStep.Id);
+        //    // _mapper.Map(dto, trace);
+        //    trace.FileJson = currentStep.FileJson;
+        //    trace.IsSms = dto.AcceptSms;
+        //    trace.Opinion = dto.Opinion;
 
-            //HandleTrace(trace, dto.Opinion, current);
+        //    //HandleTrace(trace, dto.Opinion, current);
 
-            trace.Handle(applicantId, applicantName,
-                applicantOrgId, applicantOrgName,
-                applicantOrgAreaCode, applicantOrgAreaName,
-                applicantIsCenter, EHandleMode.Previous, dto.Opinion);
+        //    trace.Handle(applicantId, applicantName,
+        //        applicantOrgId, applicantOrgName,
+        //        applicantOrgAreaCode, applicantOrgAreaName,
+        //        applicantIsCenter, EHandleMode.Previous, dto.Opinion);
 
-            //await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
+        //    //await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
 
-            //如果有传入期满时间 新节点为传入的期满时间
-            if (dto.ExpiredTime.HasValue)
-                prevStep.StepExpiredTime = dto.ExpiredTime;
+        //    //如果有传入期满时间 新节点为传入的期满时间
+        //    if (dto.ExpiredTime.HasValue)
+        //        prevStep.StepExpiredTime = dto.ExpiredTime;
 
-            if (workflow.FlowType == EFlowType.Handle)
-            {
-                prevStep.FlowAssignType = prevStep.BusinessType is EBusinessType.Seat ? EFlowAssignType.Role :
-                    prevStep.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Org;
-            }
+        //    if (workflow.FlowType == EFlowType.Handle)
+        //    {
+        //        prevStep.FlowAssignType = prevStep.BusinessType is EBusinessType.Seat ? EFlowAssignType.Role :
+        //            prevStep.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Org;
+        //    }
 
-            //甄别退回到最开始节点到部门
-            if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
-            {
-                prevStep.FlowAssignType = prevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
-            }
+        //    //甄别退回到最开始节点到部门
+        //    if (workflow.FlowType == EFlowType.Review && workflow.ModuleCode == WorkflowModuleConsts.OrderScreen)
+        //    {
+        //        prevStep.FlowAssignType = prevStep.StepType == EStepType.Start ? EFlowAssignType.Org : prevStep.FlowAssignType;
+        //    }
 
 
-            //复制上一个节点为待接办
-            // var newPrevStep =
-            //     await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
-            var newPrevStep = DuplicateStep(prevStep, EWorkflowTraceType.Previous, dto.ExpiredTime);
-            //退给派单组节点,需按照平均分配原则派给一个派单员 禅道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);
-            }
+        //    //复制上一个节点为待接办
+        //    // var newPrevStep =
+        //    //     await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
+        //    var newPrevStep = DuplicateStep(prevStep, EWorkflowTraceType.Previous, dto.ExpiredTime);
+        //    //退给派单组节点,需按照平均分配原则派给一个派单员 禅道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);
+        //    }
 
-            await _workflowStepRepository.AddAsync(newPrevStep, cancellationToken);
-            await CreateTraceAsync(workflow, newPrevStep, EWorkflowTraceType.Previous, cancellationToken);
+        //    await _workflowStepRepository.AddAsync(newPrevStep, cancellationToken);
+        //    await CreateTraceAsync(workflow, newPrevStep, EWorkflowTraceType.Previous, cancellationToken);
 
-            //remove workflow.steps
-            await _workflowStepRepository.RemoveRangeAsync(removeSteps, cancellationToken);
+        //    //remove workflow.steps
+        //    await _workflowStepRepository.RemoveRangeAsync(removeSteps, cancellationToken);
 
-            var stepIds = removeSteps.Select(d => d.Id).ToList();
-            var updateTraces = workflow.Traces.Where(d => stepIds.Contains(d.StepId)).ToList();
-            await UpdateTracesStateAsync(updateTraces, EWorkflowTraceState.StepRemoveByPrevious, cancellationToken);
+        //    var stepIds = removeSteps.Select(d => d.Id).ToList();
+        //    var updateTraces = workflow.Traces.Where(d => stepIds.Contains(d.StepId)).ToList();
+        //    await UpdateTracesStateAsync(updateTraces, EWorkflowTraceState.StepRemoveByPrevious, cancellationToken);
 
-            if (workflow.Status is EWorkflowStatus.Completed)
-                workflow.SetStatusRunnable();
+        //    if (workflow.Status is EWorkflowStatus.Completed)
+        //        workflow.SetStatusRunnable();
 
-            //更新实际办理节点信息
-            workflow.UpdateActualStepWhenAssign(newPrevStep, new FlowStepHandler
-            {
-                UserId = newPrevStep.HandlerId,
-                Username = newPrevStep.HandlerName,
-                OrgId = newPrevStep.HandlerOrgId,
-                OrgName = newPrevStep.HandlerOrgName,
-            });
+        //    //更新实际办理节点信息
+        //    workflow.UpdateActualStepWhenAssign(newPrevStep, new FlowStepHandler
+        //    {
+        //        UserId = newPrevStep.HandlerId,
+        //        Username = newPrevStep.HandlerName,
+        //        OrgId = newPrevStep.HandlerOrgId,
+        //        OrgName = newPrevStep.HandlerOrgName,
+        //    });
 
-            workflow.UpdateCurrentStepWhenAssign(newPrevStep, new FlowStepHandler
-            {
-                UserId = newPrevStep.HandlerId,
-                Username = newPrevStep.HandlerName,
-                OrgId = newPrevStep.HandlerOrgId,
-                OrgName = newPrevStep.HandlerOrgName,
-            });
+        //    workflow.UpdateCurrentStepWhenAssign(newPrevStep, new FlowStepHandler
+        //    {
+        //        UserId = newPrevStep.HandlerId,
+        //        Username = newPrevStep.HandlerName,
+        //        OrgId = newPrevStep.HandlerOrgId,
+        //        OrgName = newPrevStep.HandlerOrgName,
+        //    });
 
-            // //更新流程可办理对象
-            // workflow.UpdatePreviousHandlers(applicantId, applicantOrgId, prevStep);
+        //    // //更新流程可办理对象
+        //    // workflow.UpdatePreviousHandlers(applicantId, applicantOrgId, prevStep);
 
-            //orgToCenter会触发重新计算期满时间,1.无需审核按当前时间进行计算 2.需审核按审核通过时间计算
-            var isOrgToCenter = prevStep.BusinessType is EBusinessType.Send && prevStep.IsOrigin;
+        //    //orgToCenter会触发重新计算期满时间,1.无需审核按当前时间进行计算 2.需审核按审核通过时间计算
+        //    var isOrgToCenter = prevStep.BusinessType is EBusinessType.Send && prevStep.IsOrigin;
 
-            await _workflowRepository.UpdateAsync(workflow, cancellationToken);
+        //    await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
-            await _publisher.PublishAsync(new PreviousNotify(workflow, newPrevStep, dto, isOrgToCenter),
-                PublishStrategy.ParallelWhenAll, cancellationToken);
+        //    await _publisher.PublishAsync(new PreviousNotify(workflow, newPrevStep, dto, isOrgToCenter),
+        //        PublishStrategy.ParallelWhenAll, cancellationToken);
 
-            return GetFlowDirection(currentStep.BusinessType, prevStep.BusinessType);
-        }
+        //    return GetFlowDirection(currentStep.BusinessType, prevStep.BusinessType);
+        //}
 
         /// <summary>
         /// 退回(new)
         /// </summary>
         public async Task<(Workflow workflow, WorkflowStep currentStep, StepDefine prevDefine,
                 WorkflowStep prevStep, WorkflowStep newStep, EFlowDirection flowDirection)>
-            PreviousAsync(Workflow workflow, PreviousWorkflowDto dto, OperatorInfo operatorInfo, 
+            PreviousAsync(Workflow workflow, PreviousWorkflowDto dto, OperatorInfo operatorInfo,
                 EHandleMode handleMode = EHandleMode.Previous,
                 Action<Workflow, WorkflowStep, StepDefine, WorkflowStep, WorkflowStep>? newStepConfig = null,
                 CancellationToken cancellationToken = default)
@@ -957,13 +960,13 @@ namespace Hotline.FlowEngine.Workflows
             if (dto.ExpiredTime.HasValue)
                 prevStep.StepExpiredTime = dto.ExpiredTime;
 
-            if (workflow.FlowType == EFlowType.Handle) //该逻辑需放在退回操作前依据业务判断
-            {
-                prevStep.FlowAssignType = prevStep.BusinessType is EBusinessType.Seat ? EFlowAssignType.Role :
-                    prevStep.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Org;
-            }
+            //if (workflow.FlowType == EFlowType.Handle) //该逻辑需放在退回操作前依据业务判断
+            //{
+            //    prevStep.FlowAssignType = prevStep.BusinessType is EBusinessType.Seat ? EFlowAssignType.Role :
+            //        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;
@@ -976,6 +979,7 @@ namespace Hotline.FlowEngine.Workflows
             var prevStepDefine = workflow.WorkflowDefinition.FindStepDefine(prevStep.Code);
             //复制上一个节点为待接办
             var newPrevStep = DuplicateStep(workflow, prevStepDefine, prevStep, EWorkflowTraceType.Previous, dto.ExpiredTime);
+            newPrevStep.Assign(prevStep, EFlowAssignType.User);
             //退给派单组节点,需按照平均分配原则派给一个派单员 禅道299 TODO
             if (dto.Handler != null) //todo 改为按策略判断
             {
@@ -2859,43 +2863,44 @@ namespace Hotline.FlowEngine.Workflows
             return newStep;
         }
 
-        private WorkflowStep DuplicateStep(WorkflowStep step, EWorkflowTraceType traceType, DateTime? expiredTime)
-        {
-            var newStep = _mapper.Map<WorkflowStep>(step);
-            newStep.Reset();
-            newStep.Status = EWorkflowStepStatus.WaitForAccept;
-            newStep.PrevStepId = step.PrevStepId;
-            newStep.IsMain = step.IsMain;
-            newStep.IsOrigin = step.IsOrigin;
-            //newStep.ParentId = step.ParentId;
-            newStep.Handlers = step.Handlers;
-            newStep.StartCountersignId = step.StartCountersignId;
-            newStep.CountersignId = step.CountersignId;
-            newStep.IsStartedCountersignEnd = step.IsStartedCountersignEnd;
-            newStep.StepExpiredTime = expiredTime;
-            newStep.InitId();
-
-            newStep.Assign(step);
-
-            //退回场景:指派给原办理人,其余场景:按照原节点原始指派方式复制 //todo 重构为参数传入办理对象
-            if (traceType is EWorkflowTraceType.Previous)
-            {
-                newStep.FlowAssignType = step.FlowAssignType;
-                //    //newStep.FlowAssignType = EFlowAssignType.User;
-                //    // 是否中心  临时紧急修改 后续在流程模版定义是否原办理人退回类型 来实现流程 禅道200
-                //    //newStep.FlowAssignType = step.BusinessType is EBusinessType.Seat or EBusinessType.Send
-                //    //    ? step.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Role
-                //    //    : EFlowAssignType.Org;
-                //    //if (newStep is { FlowAssignType: EFlowAssignType.Role, BusinessType: EBusinessType.Send })
-                //    //    newStep.FlowAssignType = EFlowAssignType.User;
-
-                newStep.Assign(step.HandlerId, step.HandlerName, step.HandlerOrgId, step.HandlerOrgName, step.RoleId, step.RoleName);
-            }
+        //private WorkflowStep DuplicateStep(WorkflowStep step, EWorkflowTraceType traceType, DateTime? expiredTime)
+        //{
+        //    var newStep = _mapper.Map<WorkflowStep>(step);
+        //    newStep.Reset();
+        //    newStep.Status = EWorkflowStepStatus.WaitForAccept;
+        //    newStep.PrevStepId = step.PrevStepId;
+        //    newStep.IsMain = step.IsMain;
+        //    newStep.IsOrigin = step.IsOrigin;
+        //    //newStep.ParentId = step.ParentId;
+        //    newStep.Handlers = step.Handlers;
+        //    newStep.StartCountersignId = step.StartCountersignId;
+        //    newStep.CountersignId = step.CountersignId;
+        //    newStep.IsStartedCountersignEnd = step.IsStartedCountersignEnd;
+        //    newStep.StepExpiredTime = expiredTime;
+        //    newStep.InitId();
+
+        //    newStep.Assign(step);
+
+        //    //退回场景:指派给原办理人,其余场景:按照原节点原始指派方式复制 //todo 重构为参数传入办理对象
+        //    if (traceType is EWorkflowTraceType.Previous)
+        //    {
+        //        newStep.FlowAssignType = step.FlowAssignType;
+        //        //    //newStep.FlowAssignType = EFlowAssignType.User;
+        //        //    // 是否中心  临时紧急修改 后续在流程模版定义是否原办理人退回类型 来实现流程 禅道200
+        //        //    //newStep.FlowAssignType = step.BusinessType is EBusinessType.Seat or EBusinessType.Send
+        //        //    //    ? step.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Role
+        //        //    //    : EFlowAssignType.Org;
+        //        //    //if (newStep is { FlowAssignType: EFlowAssignType.Role, BusinessType: EBusinessType.Send })
+        //        //    //    newStep.FlowAssignType = EFlowAssignType.User;
+
+        //        newStep.Assign(step.HandlerId, step.HandlerName, step.HandlerOrgId, step.HandlerOrgName, step.RoleId, step.RoleName);
+        //    }
 
-            return newStep;
-        }
+        //    return newStep;
+        //}
 
         //new
+
         private WorkflowStep DuplicateStep(
             Workflow workflow, StepDefine stepDefine, WorkflowStep step,
             EWorkflowTraceType traceType, DateTime? expiredTime)
@@ -2914,7 +2919,7 @@ namespace Hotline.FlowEngine.Workflows
             newStep.StepExpiredTime = expiredTime;
             newStep.InitId();
 
-            newStep.Assign(step, EFlowAssignType.User);
+            newStep.Assign(step);
 
             // //退回场景:指派给原办理人,其余场景:按照原节点原始指派方式复制 //todo 重构为参数传入办理对象
             // if (traceType is EWorkflowTraceType.Previous)

+ 41 - 33
src/Hotline/Orders/OrderDomainService.cs

@@ -70,9 +70,9 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     private readonly IRepository<WorkflowStep> _workflowStepRepository;
     private readonly ISystemLogRepository _systemLogRepository;
     private readonly IOrderSnapshotRepository _orderSnapshotRepository;
-	private readonly ICalcExpireTime _expireTime;
+    private readonly ICalcExpireTime _expireTime;
 
-	public OrderDomainService(
+    public OrderDomainService(
         IOrderRepository orderRepository,
         IRepository<OrderRedo> orderRedoRepository,
         IRepository<OrderPublish> orderPublishRepository,
@@ -98,7 +98,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         ISystemLogRepository systemLogRepository,
         IOptionsSnapshot<AppConfiguration> appOptions,
         IOrderSnapshotRepository orderSnapshotRepository,
-		ICalcExpireTime expireTime)
+        ICalcExpireTime expireTime)
     {
         _orderRepository = orderRepository;
         _orderRedoRepository = orderRedoRepository;
@@ -124,9 +124,9 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         _systemLogRepository = systemLogRepository;
         _appOptions = appOptions;
         _orderSnapshotRepository = orderSnapshotRepository;
-		_expireTime = expireTime;
+        _expireTime = expireTime;
 
-	}
+    }
 
     /// <summary>
     /// 归档后自动发布
@@ -604,16 +604,21 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         if (schedulings > 0)
         {
             var sendNum = steps.Count / schedulings;
-			if (!scheduling.LoginSendOrderNum.HasValue)
-			{
-				scheduling.LoginSendOrderNum = scheduling.LoginSendOrderNum.HasValue && scheduling.LoginSendOrderNum > sendNum ? scheduling.LoginSendOrderNum : sendNum;
-			}
-			sendNum = scheduling.LoginSendOrderNum.Value;
-			if (sendNum <= 0) return;
-			var sendSteps = steps.Take(sendNum).ToList();
-			await _schedulingRepository.Updateable()
-				.SetColumns(s => new Scheduling() { AtWork = scheduling.AtWork, LoginSendOrderNum = scheduling.LoginSendOrderNum })
-				.Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
+            scheduling.SendOrderNum += sendNum;
+            if (!scheduling.LoginSendOrderNum.HasValue)
+            {
+                scheduling.LoginSendOrderNum = scheduling.LoginSendOrderNum.HasValue && scheduling.LoginSendOrderNum > sendNum ? scheduling.LoginSendOrderNum : sendNum;
+                await _schedulingRepository.Updateable()
+                    .SetColumns(s => new Scheduling() { LoginSendOrderNum = scheduling.LoginSendOrderNum })
+                    .Where(s => s.SchedulingTime == scheduling.SchedulingTime).ExecuteCommandAsync(cancellationToken);
+            }
+            sendNum = scheduling.LoginSendOrderNum.Value;
+            await _schedulingRepository.Updateable()
+                .SetColumns(s => new Scheduling() { SendOrderNum = scheduling.SendOrderNum, AtWork = scheduling.AtWork })
+                .Where(s => s.Id == scheduling.Id).ExecuteCommandAsync(cancellationToken);
+
+            if (sendNum <= 0) return;
+            var sendSteps = steps.Take(sendNum).ToList();
             await _orderRepository.Updateable().SetColumns(o => new Order()
             {
                 CenterToOrgHandlerId = user.OrgId,
@@ -697,7 +702,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     {
         var valid = new OrderValidation { Validation = false, Result = "" };
         var hotspot = await _hotspotRepository.GetAsync(dto.HotspotId, cancellationToken);
-        if (hotspot.TrunkNum.Equals(AppDefaults.TrafficTrunkNum))
+        if (hotspot != null && hotspot.TrunkNum.Equals(AppDefaults.TrafficTrunkNum))
         {
             switch (dto.AcceptTypeCode)
             {
@@ -766,7 +771,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         return valid;
     }
     #endregion
-    
+
     #region 即将超期和超期短信
 
     /// <summary>
@@ -825,35 +830,38 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 
     #region  计算甄别申请截至日期
 
-    public async Task<DateTime>  GetScreenByEndTime() {
+    public async Task<DateTime> GetScreenByEndTime()
+    {
 
         var endTime = DateTime.Now;
         var beginTime = DateTime.Now;
         var timeValue = 1;
-		if (_appOptions.Value.IsZiGong)
+        if (_appOptions.Value.IsZiGong)
         {
             timeValue = 2;
-		}
+        }
         else if (_appOptions.Value.IsLuZhou)
         {
-			DateTime firstDayOfMonth = new DateTime(beginTime.Year, beginTime.Month, 1);
-			DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
+            DateTime firstDayOfMonth = new DateTime(beginTime.Year, beginTime.Month, 1);
+            DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
             beginTime = new DateTime(lastDayOfMonth.Year, lastDayOfMonth.Month, lastDayOfMonth.Day, 23, 59, 59);
-		}
-        else {
-			var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyEndTime);
-            if (int.Parse(setting?.SettingValue[0]) > 0) {
+        }
+        else
+        {
+            var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyEndTime);
+            if (int.Parse(setting?.SettingValue[0]) > 0)
+            {
                 timeValue = int.Parse(setting?.SettingValue[0]);
-			}
-		}
-		endTime = (await _expireTime.CalcEndTime(beginTime, beginTime, ETimeType.WorkDay, timeValue, 0, 0)).EndTime;
-		return endTime;
+            }
+        }
+        endTime = (await _expireTime.CalcEndTime(beginTime, beginTime, ETimeType.WorkDay, timeValue, 0, 0)).EndTime;
+        return endTime;
     }
-	#endregion
+    #endregion
 
-	#region private
+    #region private
 
-	private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
+    private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(workflowId))
             throw UserFriendlyException.SameMessage("无效流程编号");

+ 16 - 9
src/Hotline/Orders/OrderVisitDetail.cs

@@ -8,10 +8,10 @@ using XF.Utility.EnumExtensions;
 
 namespace Hotline.Orders
 {
-	[SugarIndex("index_visitDetail_creationtime", nameof(OrderVisitDetail.CreationTime), OrderByType.Desc)]
-	[SugarIndex("index_visitDetail_visitId", nameof(OrderVisitDetail.VisitId), OrderByType.Desc)]
-	[SugarIndex("index_visitDetail_visitOrgCode", nameof(OrderVisitDetail.VisitOrgCode), OrderByType.Desc)]
-	public class OrderVisitDetail : CreationEntity
+    [SugarIndex("index_visitDetail_creationtime", nameof(OrderVisitDetail.CreationTime), OrderByType.Desc)]
+    [SugarIndex("index_visitDetail_visitId", nameof(OrderVisitDetail.VisitId), OrderByType.Desc)]
+    [SugarIndex("index_visitDetail_visitOrgCode", nameof(OrderVisitDetail.VisitOrgCode), OrderByType.Desc)]
+    public class OrderVisitDetail : CreationEntity
     {
 
         /// <summary>
@@ -99,9 +99,16 @@ namespace Hotline.Orders
         /// </summary>
         public EVisitTarget VisitTarget { get; set; }
 
-		/// <summary>
-		/// 截至甄别时间
-		/// </summary>
-		public DateTime? ScreenByEndTime { get; set; }
-	}
+        /// <summary>
+        /// 截至甄别时间
+        /// </summary>
+        public DateTime? ScreenByEndTime { get; set; }
+
+        ///// <summary>
+        ///// 查询数据用
+        ///// </summary>
+        //[SugarColumn(IsIgnore = true)]
+        //public bool? IsShowOperate { get; set; }
+
+    }
 }

+ 22 - 0
src/Hotline/Special/SpecialNumber.cs

@@ -0,0 +1,22 @@
+using SqlSugar;
+using System.ComponentModel;
+using XF.Domain.Repository;
+
+namespace Hotline.Special
+{
+    [Description("特殊号码管理")]
+    public class SpecialNumber : CreationEntity
+    {
+        /// <summary>
+        /// 电话号码
+        /// </summary>
+        [SugarColumn(ColumnDescription = "电话号码")]
+        public string PhoneNumber { get; set; }
+
+        /// <summary>
+        /// 备注
+        /// </summary>
+        [SugarColumn(ColumnDescription = "备注")]
+        public string? Notes { get; set; }
+    }
+}