瀏覽代碼

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

田爽 10 月之前
父節點
當前提交
1c2f54ac4c
共有 73 個文件被更改,包括 2312 次插入856 次删除
  1. 132 1
      src/Hotline.Api/Controllers/AiController.cs
  2. 8 2
      src/Hotline.Api/Controllers/ArticleController.cs
  3. 143 47
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  4. 1 1
      src/Hotline.Api/Controllers/BsController.cs
  5. 30 1
      src/Hotline.Api/Controllers/EnforcementOrderController.cs
  6. 1 0
      src/Hotline.Api/Controllers/HomeController.cs
  7. 10 3
      src/Hotline.Api/Controllers/IPPbxController.cs
  8. 1 0
      src/Hotline.Api/Controllers/KnowledgeController.cs
  9. 317 118
      src/Hotline.Api/Controllers/OrderController.cs
  10. 87 70
      src/Hotline.Api/Controllers/TestController.cs
  11. 3 0
      src/Hotline.Application.Contracts/Validators/FlowEngine/StartWorkflowDtoValidator.cs
  12. 2 1
      src/Hotline.Application/CallCenter/Calls/ITrApplication.cs
  13. 8 6
      src/Hotline.Application/CallCenter/Calls/TrApplication.cs
  14. 144 34
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  15. 11 1
      src/Hotline.Application/Orders/IOrderApplication.cs
  16. 39 10
      src/Hotline.Application/Orders/OrderApplication.cs
  17. 385 381
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  18. 33 1
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  19. 5 5
      src/Hotline.Repository.SqlSugar/BaseRepositoryWorkflow.cs
  20. 15 15
      src/Hotline.Repository.SqlSugar/DataPermissions/DataPermissionFilterBuilder.cs
  21. 2 0
      src/Hotline.Repository.SqlSugar/DataPermissions/IDataPermissionFilterBuilder.cs
  22. 21 2
      src/Hotline.Repository.SqlSugar/Extensions/DataPermissionExtensions.cs
  23. 59 0
      src/Hotline.Share/Dtos/Ai/AiDto.cs
  24. 6 1
      src/Hotline.Share/Dtos/FlowEngine/BasicWorkflowDto.cs
  25. 14 1
      src/Hotline.Share/Dtos/FlowEngine/NextStepOption.cs
  26. 19 2
      src/Hotline.Share/Dtos/FlowEngine/Workflow/WorkflowStepDto.cs
  27. 5 0
      src/Hotline.Share/Dtos/Knowledge/KnowledgePagedDto.cs
  28. 25 0
      src/Hotline.Share/Dtos/Order/ExternalcitizensDto.cs
  29. 9 0
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  30. 53 0
      src/Hotline.Share/Dtos/Order/OrderModifyingRecordsDto.cs
  31. 3 2
      src/Hotline.Share/Dtos/Order/OrderSpecialDto.cs
  32. 8 8
      src/Hotline.Share/Dtos/Order/OrderWaitedDto.cs
  33. 39 0
      src/Hotline.Share/Dtos/Order/UpdateOrderExpiredTimeDto.cs
  34. 22 1
      src/Hotline.Share/Dtos/OrderTranspond/TranspondCityRawDataDto.cs
  35. 8 0
      src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs
  36. 21 0
      src/Hotline.Share/Enums/Ai/EAiCallOutTaskState.cs
  37. 3 0
      src/Hotline.Share/Enums/CallCenter/EActionType.cs
  38. 22 0
      src/Hotline.Share/Enums/FlowEngine/EHandleMode.cs
  39. 6 0
      src/Hotline.Share/Enums/FlowEngine/EWorkflowStepStatus.cs
  40. 18 3
      src/Hotline.Share/Enums/Order/ESource.cs
  41. 16 0
      src/Hotline.Share/Enums/Order/EUpdateType.cs
  42. 1 1
      src/Hotline.Share/Hotline.Share.csproj
  43. 5 0
      src/Hotline.Share/Mq/EventNames.Share.cs
  44. 5 0
      src/Hotline.Share/Requests/DepartmentalProcessingStatisticsDto.cs
  45. 13 0
      src/Hotline.Share/Requests/PagedKeywordRequest.cs
  46. 49 0
      src/Hotline/Ai/CallOut/CallOutTask.cs
  47. 29 0
      src/Hotline/Ai/CallOut/CallOutTaskDetail.cs
  48. 19 0
      src/Hotline/Ai/CallOut/CallOutTemplate.cs
  49. 3 8
      src/Hotline/Authentications/Police110SessionContext.cs
  50. 2 2
      src/Hotline/Authentications/ProvinceSessionContext.cs
  51. 2 0
      src/Hotline/Authentications/SessionContextCreator.cs
  52. 4 9
      src/Hotline/Authentications/YbEnterpriseSessionContext.cs
  53. 51 0
      src/Hotline/Authentications/ZzptSessionContext.cs
  54. 3 3
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  55. 41 2
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  56. 12 4
      src/Hotline/FlowEngine/Workflows/Workflow.cs
  57. 90 84
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  58. 48 0
      src/Hotline/FlowEngine/Workflows/WorkflowStep.cs
  59. 2 2
      src/Hotline/FlowEngine/Workflows/WorkflowStepHandler.cs
  60. 16 0
      src/Hotline/Import/ExternalCitizensExcelContent.cs
  61. 12 0
      src/Hotline/OrderTranspond/TranspondCityRawData.cs
  62. 2 1
      src/Hotline/Orders/IOrderDomainService.cs
  63. 9 1
      src/Hotline/Orders/Order.cs
  64. 25 7
      src/Hotline/Orders/OrderDomainService.cs
  65. 44 0
      src/Hotline/Orders/OrderModifyingRecords.cs
  66. 2 1
      src/Hotline/Orders/OrderSpecial.cs
  67. 1 0
      src/Hotline/README.md
  68. 12 3
      src/Hotline/Settings/TimeLimits/ITimeLimitDomainService.cs
  69. 40 3
      src/Hotline/Settings/TimeLimits/TimeLimitDomainService.cs
  70. 1 1
      src/XF.Domain.Repository/Entity.cs
  71. 3 3
      src/XF.Domain.Repository/IRepositoryWorkflow.cs
  72. 8 0
      src/XF.Domain/Constants/SettingConstants.cs
  73. 4 4
      src/XF.Domain/Entities/IWorkflow.cs

+ 132 - 1
src/Hotline.Api/Controllers/AiController.cs

@@ -1,6 +1,7 @@
 
 using Consul;
 using DotNetCore.CAP;
+using Hotline.Ai.CallOut;
 using Hotline.Ai.Jths;
 using Hotline.Ai.Visit;
 using Hotline.Application.Quality;
@@ -46,8 +47,9 @@ namespace Hotline.Api.Controllers
         private readonly IOrderRepository _orderRepository;
         private readonly IQualityApplication _qualityApplication;
         private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
+        private readonly IRepository<CallOutTemplate> _callOutTemplateRepository;
 
-        public AiController(ISystemSettingCacheManager systemSettingCacheManager,IRepository<AiOrderVisit> aiOrderVisitRepository,IRepository<AiOrderVisitDetail>  aiOrderVisitDetailRepository,IRepository<OrderVisit> orderVisitRepository,IRepository<OrderVisitDetail> orderVisitDetailRepository,IMapper mapper, /*IOptionsSnapshot<AiVisitConfig> options,*/IAiVisitService aiVisitService, ILogger<AiController> logger,ICapPublisher capPublisher,IOrderRepository orderRepository,IQualityApplication qualityApplication, ISystemDicDataCacheManager sysDicDataCacheManager)
+        public AiController(ISystemSettingCacheManager systemSettingCacheManager,IRepository<AiOrderVisit> aiOrderVisitRepository,IRepository<AiOrderVisitDetail>  aiOrderVisitDetailRepository,IRepository<OrderVisit> orderVisitRepository,IRepository<OrderVisitDetail> orderVisitDetailRepository,IMapper mapper, /*IOptionsSnapshot<AiVisitConfig> options,*/IAiVisitService aiVisitService, ILogger<AiController> logger,ICapPublisher capPublisher,IOrderRepository orderRepository,IQualityApplication qualityApplication, ISystemDicDataCacheManager sysDicDataCacheManager,IRepository<CallOutTemplate> callOutTemplateRepository)
         {
            _systemSettingCacheManager = systemSettingCacheManager;
             _aiOrderVisitRepository = aiOrderVisitRepository;
@@ -62,6 +64,7 @@ namespace Hotline.Api.Controllers
             _orderRepository = orderRepository;
             _qualityApplication = qualityApplication;
             _sysDicDataCacheManager = sysDicDataCacheManager;
+            _callOutTemplateRepository = callOutTemplateRepository;
         }
 
 
@@ -100,7 +103,132 @@ namespace Hotline.Api.Controllers
             return IsOk;
         }
 
+        #region 批量外呼
 
+        #region 批量外呼模板
+
+        /// <summary>
+        /// 外呼模板列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("callout-template-list")]
+        public async Task<PagedDto<AiCallOutTemplateQueryRep>> AiCallOutTemplateQuery([FromQuery]AiCallOutTemplateQueryRequest dto)
+        {
+            var (total,items) =await _callOutTemplateRepository.Queryable()
+                .Includes(x=>x.CallOutTasks)
+                .WhereIF(!string.IsNullOrEmpty(dto.TemplateName), x => x.TemplateName.Contains(dto.TemplateName))
+                .WhereIF(dto.StartTime != null, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime != null, x => x.CreationTime <= dto.EndTime)
+                .Select(x => new AiCallOutTemplateQueryRep()
+                {
+                    Id = x.Id,
+                    TemplateName = x.TemplateName,
+                    TemplateContent = x.TemplateContent,
+                    //CallOutTaskCount = x.CallOutTasks != null ? x.CallOutTasks.Count() : 0,
+                    CreationTime = x.CreationTime,
+                    IsEnable = x.IsEnable,
+                    CreatorName = x.CreatorName,
+                    CreatorOrgName = x.CreatorOrgName,
+                })
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<AiCallOutTemplateQueryRep>(total,items);
+        }
+
+        /// <summary>
+        /// 新增外呼模板
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("add-callouttemplate")]
+        public async Task AddCallOutTemplate([FromBody]CallOutTemplateDto dto)
+        {
+            var callOutTemplate = _mapper.Map<CallOutTemplate>(dto);
+            callOutTemplate.IsEnable = true;
+            await _callOutTemplateRepository.AddAsync(callOutTemplate, HttpContext.RequestAborted);
+        }
+        /// <summary>
+        /// 修改外呼模板
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("update-callouttemplate")]
+        public async Task UpdateCallOutTemplate([FromBody] UpdateCallOutTemplateDto dto)
+        {
+            var model = await _callOutTemplateRepository.Queryable().Includes(x=>x.CallOutTasks).FirstAsync(x => x.Id == dto.Id, HttpContext.RequestAborted);
+            if (model == null)
+                throw UserFriendlyException.SameMessage("无效模板");
+            //验证是否有待执行的外呼任务
+            if (model.CallOutTasks.Any(x=>x.AiCallOutTaskState!= EAiCallOutTaskState.Ended))
+            {
+                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务,暂时无法修改!");
+            }
+
+            model.TemplateName = dto.TemplateName;
+            model.TemplateContent = dto.TemplateContent;
+
+            await _callOutTemplateRepository.UpdateAsync(model, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 删除外呼模板
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpDelete("del-callouttemplate")]
+        public async Task DelCallOutTemplate([FromQuery]string id)
+        {
+            var model = await _callOutTemplateRepository.Queryable().Includes(x => x.CallOutTasks).FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
+            if (model == null)
+                throw UserFriendlyException.SameMessage("无效模板");
+
+            //验证是否有待执行的外呼任务
+            if (model.CallOutTasks.Any(x => x.AiCallOutTaskState != EAiCallOutTaskState.Ended))
+            {
+                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务,暂时无法删除!");
+            }
+
+            await _callOutTemplateRepository.RemoveAsync(id, true, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 外呼模板启用禁用
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("callouttemplate-enable-unenable")]
+        public async Task CallOutTemplateEnableAndUnEnable([FromQuery]string id)
+        {
+            var model = await _callOutTemplateRepository.Queryable().Includes(x => x.CallOutTasks).FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
+            if (model == null)
+                throw UserFriendlyException.SameMessage("无效模板");
+
+            //验证是否有待执行的外呼任务
+            if (model.CallOutTasks.Any(x => x.AiCallOutTaskState != EAiCallOutTaskState.Ended))
+            {
+                throw UserFriendlyException.SameMessage("当前模板有待执行的外呼任务,暂时无法操作!");
+            }
+
+            model.IsEnable = !model.IsEnable;
+
+            await _callOutTemplateRepository.UpdateAsync(model, HttpContext.RequestAborted);
+        }
+
+        
+
+
+        #endregion
+
+
+        #region 批量外呼任务
+
+
+
+
+        #endregion
+
+        #endregion
 
         #region 智能回访
 
@@ -570,5 +698,8 @@ namespace Hotline.Api.Controllers
         }
 
         #endregion
+
+
+        
     }
 }

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

@@ -1,4 +1,5 @@
-using Hotline.Application.FlowEngine;
+using DotNetCore.CAP;
+using Hotline.Application.FlowEngine;
 using Hotline.Article;
 using Hotline.Caching.Interfaces;
 using Hotline.Permissions;
@@ -34,8 +35,9 @@ namespace Hotline.Api.Controllers
         private readonly ICircularRecordDomainService _circularRecordDomainService;
         private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
         private readonly IMediator _mediator;
+        private readonly ICapPublisher _capPublisher;
 
-        public ArticleController(IRepository<Bulletin> bulletinRepository, IMapper mapper, ISystemDomainService systemDomainService, ISystemOrganizeRepository organizeRepository, IWorkflowApplication workflowApplication, IRepository<Circular> circularRepository, ISessionContext sessionContext, IRepository<CircularRecord> circularRecordRepository, IRepository<CircularReadGroup> circularReadGroupRepository, IRepository<User> userRepository, ICircularRecordDomainService circularRecordDomainService, ISystemDicDataCacheManager systemDicDataCacheManager, IMediator mediator)
+        public ArticleController(IRepository<Bulletin> bulletinRepository, IMapper mapper, ISystemDomainService systemDomainService, ISystemOrganizeRepository organizeRepository, IWorkflowApplication workflowApplication, IRepository<Circular> circularRepository, ISessionContext sessionContext, IRepository<CircularRecord> circularRecordRepository, IRepository<CircularReadGroup> circularReadGroupRepository, IRepository<User> userRepository, ICircularRecordDomainService circularRecordDomainService, ISystemDicDataCacheManager systemDicDataCacheManager, IMediator mediator, ICapPublisher capPublisher)
         {
             _bulletinRepository = bulletinRepository;
             _mapper = mapper;
@@ -49,6 +51,7 @@ namespace Hotline.Api.Controllers
             _circularRecordDomainService = circularRecordDomainService;
             _systemDicDataCacheManager = systemDicDataCacheManager;
             _mediator = mediator;
+            _capPublisher = capPublisher;
         }
         #region 通知
 
@@ -471,6 +474,9 @@ namespace Hotline.Api.Controllers
                 bulletin.ExaminManId = _sessionContext.RequiredUserId;
                 await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
                 var publishBulletin = _mapper.Map<PublishBulletinDto>(bulletin);
+
+                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlinePushBulletin, publishBulletin, cancellationToken: HttpContext.RequestAborted);
+                
                 //todo await _bulletinService.PushBulletin(publishBulletin, HttpContext.RequestAborted);
             }
             else

+ 143 - 47
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -8,6 +8,7 @@ using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Schedulings;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
+using Hotline.Settings.TimeLimits;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Bi;
 using Hotline.Share.Dtos.Bigscreen;
@@ -52,8 +53,10 @@ namespace Hotline.Api.Controllers.Bi
         private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IRepository<OrderScreen> _orderScreenRepository;
         private readonly IOrderSecondaryHandlingApplication _orderSecondaryHandlingApplication;
+        private readonly IOrderApplication _orderApplication;
+        private readonly ITimeLimitDomainService _timeLimitDomainService;
 
-        public BiOrderController(
+		public BiOrderController(
             IOrderRepository orderRepository,
             IRepository<Hotspot> hotspotTypeRepository,
             ISystemDicDataCacheManager sysDicDataCacheManager,
@@ -73,8 +76,10 @@ namespace Hotline.Api.Controllers.Bi
             IRepository<WorkflowTrace> workflowTraceRepository,
             IRepository<OrderScreen> orderScreenRepository,
             IRepository<WorkflowStepHandler> workflowStepHandleRepository,
-            IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication
-            )
+            IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication,
+            IOrderApplication orderApplication,
+            ITimeLimitDomainService timeLimitDomainService
+			)
         {
             _orderRepository = orderRepository;
             _hotspotTypeRepository = hotspotTypeRepository;
@@ -96,8 +101,9 @@ namespace Hotline.Api.Controllers.Bi
             _orderScreenRepository = orderScreenRepository;
             _workflowStepHandleRepository = workflowStepHandleRepository;
             _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication;
-
-        }
+            _orderApplication = orderApplication;
+            _timeLimitDomainService = timeLimitDomainService;
+		}
 
         /// <summary>
         /// 部门超期统计明细
@@ -1538,9 +1544,10 @@ namespace Hotline.Api.Controllers.Bi
         /// <param name="StartDate"></param>
         /// <param name="EndDate"></param>
         /// <param name="OrgName"></param>
+        /// <param name="IsProvince"></param>
         /// <returns></returns>
         [HttpGet("departmental_processing_statistics")]
-        public async Task<object> DepartmentalProcessingStatistics(DateTime StartDate, DateTime EndDate, string? OrgName)
+        public async Task<object> DepartmentalProcessingStatistics(DateTime StartDate, DateTime EndDate, string? OrgName, bool? IsProvince)
         {
             EndDate = EndDate.AddDays(1).AddSeconds(-1);
             var IsCenter = _sessionContext.OrgIsCenter;
@@ -1549,6 +1556,7 @@ namespace Hotline.Api.Controllers.Bi
             #region 工单
             var queryOrder = _orderRepository.Queryable()
                          .Where(it => it.CreationTime >= StartDate && it.CreationTime <= EndDate && it.Status > EOrderStatus.WaitForAccept)
+                        .WhereIF(IsProvince.HasValue && IsProvince == true, it => it.Source == ESource.ProvinceStraight)
                          .Select(it => new
                          {
                              it.Id,
@@ -1599,12 +1607,13 @@ namespace Hotline.Api.Controllers.Bi
             var queryPublish = _orderPublishRepository.Queryable()
                 .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
                 .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
                 .Select((x, o) => new
                 {
                     o.Id,
                     OrgCode = IsCenter == true ? o.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : o.ActualHandleOrgCode.Substring(0, _sessionContext.RequiredOrgId.Length + 3),
-                    PublishState = x.PublishState,
-                    Status = o.Status
+                    x.PublishState,
+                    o.Status
                 })
                 .MergeTable()
                 .WhereIF(IsCenter == false, it => it.OrgCode.StartsWith(_sessionContext.RequiredOrgId))
@@ -1642,14 +1651,16 @@ namespace Hotline.Api.Controllers.Bi
             //会签(已办超期、待办超期)
             var queryCountersign = _workflowStepHandleRepository.Queryable()
              .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
-             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
-             .Select((x, o) => new
+             .LeftJoin<Order>((x, o, p) => x.WorkflowId == o.WorkflowId)
+             .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
+             .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
+             .Select((x, o, p) => new
              {
                  OrgCode = IsCenter == true ? x.OrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : x.OrgId.Substring(0, _sessionContext.RequiredOrgId.Length + 3),// d.OrgId,
-                 HandleTime = o.HandleTime,
-                 StepExpiredTime = o.StepExpiredTime,
-                 Status = o.Status,
-                 CountersignPosition = o.CountersignPosition
+                 o.HandleTime,
+                 o.StepExpiredTime,
+                 o.Status,
+                 o.CountersignPosition
              })
               .MergeTable()
               .WhereIF(IsCenter == false, it => it.OrgCode.StartsWith(_sessionContext.RequiredOrgId))
@@ -1686,8 +1697,10 @@ namespace Hotline.Api.Controllers.Bi
             #region 延期
             //延期
             var orderDelay = _orderDelayRepository.Queryable()
-                .Where(x => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
-                .Select(x => new
+                .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
+                .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
+                .Select((x, o) => new
                 {
                     OrgCode = IsCenter == true ? x.ApplyOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : x.ApplyOrgCode.Substring(0, _sessionContext.RequiredOrgId.Length + 3),
                     x.DelayState
@@ -1727,13 +1740,15 @@ namespace Hotline.Api.Controllers.Bi
             #region 甄别
             //甄别
             var orderScreen = _orderScreenRepository.Queryable()
-                .Where(x => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
-                .WhereIF(!string.IsNullOrEmpty(OrgName), x => x.CreatorOrgId.Contains(OrgName))
-                .Select(x => new
+                .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
+                .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
+                .WhereIF(!string.IsNullOrEmpty(OrgName), (x, o) => x.CreatorOrgId.Contains(OrgName))
+                .Select((x, o) => new
                 {
                     x.Id,
                     OrgCode = IsCenter == true ? x.CreatorOrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : x.CreatorOrgId.Substring(0, _sessionContext.RequiredOrgId.Length + 3),
-                    Status = x.Status
+                    x.Status
                 })
                 .MergeTable()
                 .WhereIF(IsCenter == false, it => it.OrgCode.StartsWith(_sessionContext.RequiredOrgId))
@@ -1770,8 +1785,11 @@ namespace Hotline.Api.Controllers.Bi
             #region 满意度
             //满意度
             var orderVisit = _orderVisitDetailRepository.Queryable()
-            .Where(x => x.OrderVisit.VisitTime >= StartDate && x.OrderVisit.VisitTime <= EndDate && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
-            .Select(x => new
+                .LeftJoin<OrderVisit>((x, o) => x.VisitId == o.Id)
+                .LeftJoin<Order>((x, o, p) => o.OrderId == p.Id)
+            .Where((x, o, p) => x.OrderVisit.VisitTime >= StartDate && x.OrderVisit.VisitTime <= EndDate && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
+            .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
+            .Select((x, o, p) => new
             {
                 OrgCode = IsCenter == true ? x.VisitOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : x.VisitOrgCode.Substring(0, _sessionContext.RequiredOrgId.Length + 3),
                 x.OrgProcessingResults
@@ -1881,9 +1899,10 @@ namespace Hotline.Api.Controllers.Bi
         /// <param name="EndDate"></param>
         /// <param name="OrgCode"></param>
         /// <param name="OrgName"></param>
+        /// <param name="IsProvince"></param>
         /// <returns></returns>
         [HttpGet("departmental_processing_child_statistics")]
-        public async Task<object> DepartmentalProcessingChildStatistics(DateTime StartDate, DateTime EndDate, string OrgCode, string? OrgName)
+        public async Task<object> DepartmentalProcessingChildStatistics(DateTime StartDate, DateTime EndDate, string OrgCode, string? OrgName, bool? IsProvince)
         {
             EndDate = EndDate.AddDays(1).AddSeconds(-1);
 
@@ -1893,6 +1912,7 @@ namespace Hotline.Api.Controllers.Bi
                       .Where(it => it.CreationTime >= StartDate && it.CreationTime <= EndDate && it.Status > EOrderStatus.WaitForAccept)
                       .WhereIF(OrgCode == "001", it => it.ActualHandleOrgCode == OrgCode)
                       .WhereIF(OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(OrgCode))
+                      .WhereIF(IsProvince.HasValue && IsProvince == true, it => it.Source == ESource.ProvinceStraight)
                       .Select(it => new
                       {
                           it.Id,
@@ -1942,6 +1962,7 @@ namespace Hotline.Api.Controllers.Bi
             var queryPublish = _orderPublishRepository.Queryable()
                 .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
                 .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
                 .WhereIF(OrgCode == "001", (x, o) => o.ActualHandleOrgCode == OrgCode)
                 .WhereIF(OrgCode != "001", (x, o) => o.ActualHandleOrgCode.StartsWith(OrgCode))
                 .Select((x, o) => new
@@ -1986,10 +2007,12 @@ namespace Hotline.Api.Controllers.Bi
             //会签(已办超期、待办超期)
             var queryCountersign = _workflowStepHandleRepository.Queryable()
              .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
-             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
-             .WhereIF(OrgCode == "001", (x, o) => x.OrgId == OrgCode)
-             .WhereIF(OrgCode != "001", (x, o) => x.OrgId.StartsWith(OrgCode))
-             .Select((x, o) => new
+             .LeftJoin<Order>((x, o, p) => x.WorkflowId == o.WorkflowId)
+             .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
+             .WhereIF(OrgCode == "001", (x, o, p) => x.OrgId == OrgCode)
+             .WhereIF(OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(OrgCode))
+              .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
+             .Select((x, o, p) => new
              {
                  OrgCode = x.OrgId.Substring(0, OrgCode.Length + 3),
                  o.HandleTime,
@@ -2031,10 +2054,12 @@ namespace Hotline.Api.Controllers.Bi
             #region 延期
             //延期
             var orderDelay = _orderDelayRepository.Queryable()
-                .Where(x => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
-                .WhereIF(OrgCode == "001", x => x.ApplyOrgCode == OrgCode)
-                .WhereIF(OrgCode != "001", x => x.ApplyOrgCode.StartsWith(OrgCode))
-                .Select(x => new
+                .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
+                .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
+                .WhereIF(OrgCode == "001", (x, o) => x.ApplyOrgCode == OrgCode)
+                .WhereIF(OrgCode != "001", (x, o) => x.ApplyOrgCode.StartsWith(OrgCode))
+                .Select((x, o) => new
                 {
                     OrgCode = x.ApplyOrgCode.Substring(0, OrgCode.Length + 3),
                     x.DelayState
@@ -2073,15 +2098,17 @@ namespace Hotline.Api.Controllers.Bi
             #region 甄别
             //甄别
             var orderScreen = _orderScreenRepository.Queryable()
-                .Where(x => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
-                .WhereIF(!string.IsNullOrEmpty(OrgName), x => x.CreatorOrgId.Contains(OrgName))
-                .WhereIF(OrgCode == "001", x => x.CreatorOrgId == OrgCode)
-                .WhereIF(OrgCode != "001", x => x.CreatorOrgId.StartsWith(OrgCode))
-                .Select(x => new
+                .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
+                .Where((x, o) => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
+                .WhereIF(!string.IsNullOrEmpty(OrgName), (x, o) => x.CreatorOrgId.Contains(OrgName))
+                .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
+                .WhereIF(OrgCode == "001", (x, o) => x.CreatorOrgId == OrgCode)
+                .WhereIF(OrgCode != "001", (x, o) => x.CreatorOrgId.StartsWith(OrgCode))
+                .Select((x, o) => new
                 {
                     x.Id,
                     OrgCode = x.CreatorOrgId.Substring(0, OrgCode.Length + 3),
-                    Status = x.Status
+                    x.Status
                 })
                 .MergeTable()
                 .GroupBy(x => new { x.OrgCode })
@@ -2117,10 +2144,13 @@ namespace Hotline.Api.Controllers.Bi
             #region 满意度
             //满意度
             var orderVisit = _orderVisitDetailRepository.Queryable()
-              .Where(x => x.OrderVisit.VisitTime >= StartDate && x.OrderVisit.VisitTime <= EndDate && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
-              .WhereIF(OrgCode == "001", x => x.VisitOrgCode == OrgCode)
-              .WhereIF(OrgCode != "001", x => x.VisitOrgCode.StartsWith(OrgCode))
-            .Select(x => new
+                .LeftJoin<OrderVisit>((x, o) => x.VisitId == o.Id)
+                .LeftJoin<Order>((x, o, p) => o.OrderId == p.Id)
+                .Where((x, o) => x.OrderVisit.VisitTime >= StartDate && x.OrderVisit.VisitTime <= EndDate && x.VisitTarget == EVisitTarget.Org && x.OrderVisit.VisitState == EVisitState.Visited && !string.IsNullOrEmpty(x.VisitOrgCode))
+                .WhereIF(OrgCode == "001", (x, o) => x.VisitOrgCode == OrgCode)
+                .WhereIF(OrgCode != "001", (x, o) => x.VisitOrgCode.StartsWith(OrgCode))
+               .WhereIF(IsProvince.HasValue && IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
+            .Select((x, o) => new
             {
                 OrgCode = x.VisitOrgCode.Substring(0, OrgCode.Length + 3),
                 x.OrgProcessingResults
@@ -2295,6 +2325,7 @@ namespace Hotline.Api.Controllers.Bi
                                   .WhereIF(dto.OrgCode == "001", it => it.ActualHandleOrgCode == dto.OrgCode)
                                   .WhereIF(dto.OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(dto.OrgCode))
                                  .WhereIF(dto.StatisticsType == EStatisticsType.YBOrderCountNum, it => it.Status >= EOrderStatus.Filed)//已办
+                                 .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, it => it.Source == ESource.ProvinceStraight)
                                  .Select(it => new SelectOrderId { Id = it.Id })
                                  .MergeTable();
 
@@ -2305,7 +2336,8 @@ namespace Hotline.Api.Controllers.Bi
                   .WhereIF(dto.OrgCode == "001", (x, o, p) => x.OrgId == dto.OrgCode)
                   .WhereIF(dto.OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(dto.OrgCode))
                   .WhereIF(dto.StatisticsType == EStatisticsType.YBOrderCountNum, (x, o, p) => o.Status >= EWorkflowStepStatus.Handled && o.CountersignPosition > ECountersignPosition.None)//会签已办
-                   .Select((x, o, p) => new SelectOrderId { Id = p.Id })
+                  .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
+                  .Select((x, o, p) => new SelectOrderId { Id = p.Id })
                   .MergeTable();
 
                 var queryData = await _orderRepository.OrderListUnionAll(ybQuery, hqybquery)
@@ -2329,6 +2361,7 @@ namespace Hotline.Api.Controllers.Bi
                 //工单
                 var (totalOrder, items) = await _orderRepository.Queryable()
                           .Where(it => it.CreationTime >= dto.StartDate && it.CreationTime <= dto.EndDate && it.Status > EOrderStatus.WaitForAccept)
+                         .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, it => it.Source == ESource.ProvinceStraight)
                           .WhereIF(dto.OrgCode == "001", it => it.ActualHandleOrgCode == dto.OrgCode)
                           .WhereIF(dto.OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(dto.OrgCode))
                            .WhereIF(dto.StatisticsType == EStatisticsType.Archived, it => it.Status >= EOrderStatus.Filed)//已归档
@@ -2347,6 +2380,7 @@ namespace Hotline.Api.Controllers.Bi
                 var queryPublish = await _orderPublishRepository.Queryable()
                     .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
                     .Where((x, o) => x.CreationTime >= dto.StartDate && x.CreationTime <= dto.EndDate)
+                    .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
                     .WhereIF(dto.OrgCode == "001", (x, o) => o.ActualHandleOrgCode == dto.OrgCode)
                     .WhereIF(dto.OrgCode != "001", (x, o) => o.ActualHandleOrgCode.StartsWith(dto.OrgCode))
                     .WhereIF(dto.StatisticsType == EStatisticsType.WaitPublished, (x, o) => o.Status == EOrderStatus.Filed)//待发布  --已归档的就是待发布
@@ -2373,6 +2407,7 @@ namespace Hotline.Api.Controllers.Bi
                 var orderDelay = await _orderDelayRepository.Queryable()
                 .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
                 .Where((x, o) => x.CreationTime >= dto.StartDate && x.CreationTime <= dto.EndDate)
+                .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
                 .WhereIF(dto.OrgCode == "001", (x, o) => x.ApplyOrgCode == dto.OrgCode)
                 .WhereIF(dto.OrgCode != "001", (x, o) => x.ApplyOrgCode.StartsWith(dto.OrgCode))
               .WhereIF(dto.StatisticsType == EStatisticsType.OrderDelayCount, (x, o) => x.DelayState == EDelayState.Pass)//延期次数
@@ -2396,7 +2431,8 @@ namespace Hotline.Api.Controllers.Bi
                 var orderScreen = await _orderScreenRepository.Queryable()
                  .LeftJoin<Order>((x, o) => x.OrderId == o.Id)
                 .Where((x, o) => x.CreationTime >= dto.StartDate && x.CreationTime <= dto.EndDate)
-                  .WhereIF(dto.OrgCode == "001", (x, o) => x.CreatorOrgId == dto.OrgCode)
+                .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o) => o.Source == ESource.ProvinceStraight)
+                .WhereIF(dto.OrgCode == "001", (x, o) => x.CreatorOrgId == dto.OrgCode)
                 .WhereIF(dto.OrgCode != "001", (x, o) => x.CreatorOrgId.StartsWith(dto.OrgCode))
                 .WhereIF(dto.StatisticsType == EStatisticsType.ScreenCount, (x, o) => x.Id != null)//申请总量
                 .WhereIF(dto.StatisticsType == EStatisticsType.ScreenApproval, (x, o) => x.Status == EScreenStatus.Approval || x.Status == EScreenStatus.Apply)//待甄别
@@ -2422,8 +2458,8 @@ namespace Hotline.Api.Controllers.Bi
                 var queryCountersign = await _workflowStepHandleRepository.Queryable()
                .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
                .LeftJoin<Order>((x, o, p) => o.WorkflowId == p.WorkflowId)
-                .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle
-             && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
+               .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
+               .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
                .WhereIF(dto.OrgCode == "001", (x, o, p) => x.OrgId == dto.OrgCode)
                .WhereIF(dto.OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(dto.OrgCode))
                .WhereIF(dto.StatisticsType == EStatisticsType.HQYBOverdue, (x, o, p) => o.Status >= EWorkflowStepStatus.Handled && o.HandleTime > o.StepExpiredTime && o.CountersignPosition > ECountersignPosition.None)//会签已办超期
@@ -2455,7 +2491,8 @@ namespace Hotline.Api.Controllers.Bi
                          .Where(it => it.CreationTime >= dto.StartDate && it.CreationTime <= dto.EndDate && it.Status > EOrderStatus.WaitForAccept)
                          .WhereIF(dto.OrgCode == "001", it => it.ActualHandleOrgCode == dto.OrgCode)
                          .WhereIF(dto.OrgCode != "001", it => it.ActualHandleOrgCode.StartsWith(dto.OrgCode))
-                          .WhereIF(dto.StatisticsType == EStatisticsType.SubtotalOverdue, it => (it.Status >= EOrderStatus.Filed && it.ActualHandleTime > it.ExpiredTime))//已办超期
+                         .WhereIF(dto.StatisticsType == EStatisticsType.SubtotalOverdue, it => (it.Status >= EOrderStatus.Filed && it.ActualHandleTime > it.ExpiredTime))//已办超期
+                         .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, it => it.Source == ESource.ProvinceStraight)
                          .Select(it => new SelectOrderId { Id = it.Id })
                          .MergeTable();
 
@@ -2464,6 +2501,7 @@ namespace Hotline.Api.Controllers.Bi
                .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
                .LeftJoin<Order>((x, o, p) => o.WorkflowId == p.WorkflowId)
                .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
+               .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, (x, o, p) => p.Source == ESource.ProvinceStraight)
                .WhereIF(dto.OrgCode == "001", (x, o, p) => x.OrgId == dto.OrgCode)
                .WhereIF(dto.OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(dto.OrgCode))
 
@@ -2493,6 +2531,7 @@ namespace Hotline.Api.Controllers.Bi
             return new PagedDto<OrderDto>(total, new List<OrderDto>());
         }
 
+
         /// <summary>
         /// 高频来电统计
         /// </summary>
@@ -3148,5 +3187,62 @@ namespace Hotline.Api.Controllers.Bi
 
             return ExcelStreamResult(stream, "二次办理满意度列表数据");
         }
-    }
+
+
+
+        /// <summary>
+        /// 未签收统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("unsigned_order_report")]
+        public async Task<PagedDto<UnsignedOrderDto>> UnsignedOrderReport([FromQuery] QueryUnsignedOrdersRequest dto)
+        {
+	        var query = _orderApplication.QueryUnsignedOrders(dto);
+	        var (total, items) = await query.Select((x,ws)=> new UnsignedOrder { Order = x , WorkflowStep = ws }).ToPagedListAsync(dto, HttpContext.RequestAborted);
+            var itemsVo = _mapper.Map<IReadOnlyList<UnsignedOrderDto>>(items);
+            foreach (var item in itemsVo)
+            {
+                item.UnsignedTime = _timeLimitDomainService.CalcWorkTimeToHour(item.WorkflowStep.CreationTime, item.WorkflowStep.Status == EWorkflowStepStatus.WaitForAccept ? DateTime.Now : item.WorkflowStep.AcceptTime!.Value, false);
+            }
+			return new PagedDto<UnsignedOrderDto>(total, itemsVo);
+        }
+		/// <summary>
+		/// 未签收统计导出
+		/// </summary>
+		/// <returns></returns>
+		[HttpPost("unsigned_order_report/_export")]
+        public async Task<FileStreamResult> UnsignedOrdersReportReport([FromBody] ExportExcelDto<QueryUnsignedOrdersRequest> dto)
+        {
+	        var query = _orderApplication.QueryUnsignedOrders(dto.QueryDto).Select((x, ws) => new UnsignedOrder { Order = x, WorkflowStep = ws });
+	        List<UnsignedOrder>  unsignedOrders;
+	        if (dto.IsExportAll)
+	        {
+		        unsignedOrders = await query.ToListAsync(HttpContext.RequestAborted);
+	        }
+	        else
+	        {
+		        var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+		        unsignedOrders = items;
+	        }
+
+	        var unsignedOrderDtos = _mapper.Map<ICollection<UnsignedOrderDto>>(unsignedOrders);
+
+	        foreach (var item in unsignedOrderDtos)
+	        {
+                item.UnsignedTime = _timeLimitDomainService.CalcWorkTimeToHour(item.WorkflowStep.CreationTime, item.WorkflowStep.Status == EWorkflowStepStatus.WaitForAccept ? DateTime.Now : item.WorkflowStep.AcceptTime!.Value, false);
+            }
+
+			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+	        var dtos = unsignedOrderDtos
+				.Select(stu => _mapper.Map(stu, typeof(UnsignedOrderDto), dynamicClass))
+		        .Cast<object>()
+		        .ToList();
+
+	        var stream = ExcelHelper.CreateStream(dtos);
+
+	        return ExcelStreamResult(stream, "未签收统计列表数据");
+        }
+	}
 }

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

@@ -142,7 +142,7 @@ namespace Hotline.Api.Controllers
 
 
             //area7
-            var query7 = await _orderRepository.Queryable(viewFilter: false)
+            var query7 = await _orderRepository.Queryable(canView: false)
                 .GroupBy(d => d.HotspotName)
                 .Select(d => new
                 {

+ 30 - 1
src/Hotline.Api/Controllers/EnforcementOrderController.cs

@@ -32,6 +32,7 @@ namespace Hotline.Api.Controllers
         private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
         private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
         private readonly ISessionContext _sessionContext;
+        private readonly IRepository<SystemArea> _systemAreaRepository;
         private readonly IOrderRepository _orderRepository;
 
         /// <summary>
@@ -45,6 +46,7 @@ namespace Hotline.Api.Controllers
         /// <param name="sysDicDataCacheManager"></param>
         /// <param name="systemOrganizeRepository"></param>
         /// <param name="sessionContext"></param>
+        /// <param name="systemAreaRepository"></param>
         /// <param name="orderRepository"></param>
         public EnforcementOrderController(IRepository<EnforcementOrders> enforcementOrdersRepository,
          IRepository<JudicialComplaintsEventType> judicialComplaintsEventTypeRepository,
@@ -54,7 +56,9 @@ namespace Hotline.Api.Controllers
          ISystemDicDataCacheManager sysDicDataCacheManager,
          IRepository<SystemOrganize> systemOrganizeRepository,
          ISessionContext sessionContext,
-         IOrderRepository orderRepository)
+         IOrderRepository orderRepository,
+		 IRepository<SystemArea> systemAreaRepository
+         )
         {
             _enforcementOrdersRepository = enforcementOrdersRepository;
             _judicialComplaintsEventTypeRepository = judicialComplaintsEventTypeRepository;
@@ -64,6 +68,7 @@ namespace Hotline.Api.Controllers
             _sysDicDataCacheManager = sysDicDataCacheManager;
             _systemOrganizeRepository = systemOrganizeRepository;
             _sessionContext = sessionContext;
+            _systemAreaRepository = systemAreaRepository;
             _orderRepository = orderRepository;
         }
 
@@ -165,6 +170,30 @@ namespace Hotline.Api.Controllers
             return rsp;
         }
 
+        /// <summary>
+        /// 获取省市区树形
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("area/tree")]
+        public async Task<List<SystemArea>> GetAreaTree()
+        {
+            var areaCode = _sessionContext.OrgAreaCode;
+            if (string.IsNullOrEmpty(areaCode))
+                areaCode = "511500";
+            if (areaCode == "511500")
+            {
+                return await _systemAreaRepository.Queryable().OrderBy(x => x.Id).ToTreeAsync(x => x.Children, q => q.ParentId, "510000");
+            }
+            else
+            {
+                string parentId = "510000";
+                var data = await _systemAreaRepository.GetAsync(p => p.Id == areaCode);
+                if (data != null)
+                    parentId = data.ParentId;
+                return await _systemAreaRepository.Queryable().Where(p => p.Id.StartsWith(areaCode)).OrderBy(x => x.Id).ToTreeAsync(x => x.Children, q => q.ParentId, parentId);
+            }
+        }
+
         /// <summary>
         /// 线索核实  
         /// </summary>

+ 1 - 0
src/Hotline.Api/Controllers/HomeController.cs

@@ -184,6 +184,7 @@ public class HomeController : BaseController
 			IsTranspondCity = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TranspondCity).SettingValue[0]),
 			IsAverageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]),
             IsOpenJudicialManagement = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsOpenJudicialManagement).SettingValue[0]),
+            NoSignOrgCode = _systemSettingCacheManager.GetSetting(SettingConstants.NoSignOrgCode).SettingValue,
         };
         return rsp;
     }

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

@@ -101,10 +101,17 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("query-tels")]
-        public async Task<IReadOnlyList<TrTelDto>> TrQueryTels()
+        public async Task<List<TrTelDto>> TrQueryTels()
         {
             var tels = await _trClient.QueryTelsAsync(new QueryTelRequest() { }, HttpContext.RequestAborted);
-            return _mapper.Map<IReadOnlyList<TrTelDto>>(tels);
+            var returnlist = _mapper.Map<List<TrTelDto>>(tels);
+            string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
+            returnlist.ForEach(x =>
+            {
+                x.CallOutQueue = callOutQueueId;
+            });
+
+            return returnlist;
         }
 
         /// <summary>
@@ -173,7 +180,7 @@ namespace Hotline.Api.Controllers
         public async Task<TrOnDutyResponseDto> OnDuty([FromBody] TrOnDutyDto dto)
         {
             //return await _userDomainService.TrOnDutyAsync(_sessionContext.RequiredUserId,dto.TelNo, HttpContext.RequestAborted);
-            return await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo, HttpContext.RequestAborted);
+            return await _trApplication.OnSign(_sessionContext.RequiredUserId, dto.TelNo,(ETelModel)dto.TelModelState, HttpContext.RequestAborted);
         }
 
         /// <summary>

+ 1 - 0
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -503,6 +503,7 @@ namespace Hotline.Api.Controllers
                 .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => SqlFunc.JsonLike(x.KnowledgeType, typeSpliceName))
                 .WhereIF(!string.IsNullOrEmpty(hotspotHotSpotFullName), x => x.HotspotType.HotSpotFullName.EndsWith(hotspotHotSpotFullName!))
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.SourceOrganizeId != null && x.SourceOrganizeId.EndsWith(pagedDto.CreateOrgId!))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.ModuleCode), x => x.Workflow.ModuleCode == pagedDto.ModuleCode)
                 .OrderByDescending(d => d.CreationTime)
                 .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);
             //temp.ForEach(x => x.IsCanHandle = x.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId));

+ 317 - 118
src/Hotline.Api/Controllers/OrderController.cs

@@ -40,13 +40,13 @@ using Hotline.Tools;
 using Hotline.Users;
 using Hotline.YbEnterprise.Sdk;
 using MapsterMapper;
-using MathNet.Numerics.Distributions;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Mvc;
 using MiniExcelLibs;
+using Org.BouncyCastle.Utilities;
 using SqlSugar;
-using System;
+using StackExchange.Redis;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Constants;
@@ -114,8 +114,10 @@ public class OrderController : BaseController
     private readonly IRepository<OrderSpecialDetail> _orderSpecialDetailRepository;
     private readonly IOrderSecondaryHandlingApplication _orderSecondaryHandlingApplication;
     private readonly IRepository<OrderCopy> _orderCopyRepository;
+    private readonly IRepository<ExternalCitizens> _externalCitizensRepository;
+    private readonly IRepository<OrderModifyingRecords> _orderModifyingRecordsRepository;
 
-	public OrderController(
+    public OrderController(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         IWorkflowApplication workflowApplication,
@@ -167,8 +169,10 @@ public class OrderController : BaseController
         IRepository<TranspondCityRawData> transpondCityRawDataRepository,
         IRepository<OrderSpecialDetail> orderSpecialDetailRepository,
         IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication,
-        IRepository<OrderCopy> orderCopyRepository
-		)
+        IRepository<OrderCopy> orderCopyRepository,
+        IRepository<ExternalCitizens> externalCitizensRepository,
+        IRepository<OrderModifyingRecords> orderModifyingRecordsRepository
+        )
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -222,8 +226,9 @@ public class OrderController : BaseController
         _orderSpecialDetailRepository = orderSpecialDetailRepository;
         _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication;
         _orderCopyRepository = orderCopyRepository;
-
-	}
+        _externalCitizensRepository = externalCitizensRepository;
+        _orderModifyingRecordsRepository = orderModifyingRecordsRepository;
+    }
 
     #region 工单发布
 
@@ -1328,7 +1333,7 @@ public class OrderController : BaseController
     [HttpGet("delay")]
     public async Task<PagedDto<OrderDelayDto>> DelayList([FromQuery] DelayListDto dto)
     {
-        var (total, items) = await _orderDelayRepository.Queryable(viewFilter: true)
+        var (total, items) = await _orderDelayRepository.Queryable(canView: true)
             .Includes(x => x.Order)
             .Includes(x => x.Workflow)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
@@ -1352,7 +1357,7 @@ public class OrderController : BaseController
     {
         var isHandled = dto.IsApply.HasValue && dto.IsApply.Value;
         var (total, items) = await _orderDelayRepository
-            .Queryable(viewFilter: true, handlerFilter: !isHandled)
+            .Queryable(canView: true, hasHandled: !isHandled)
             .Includes(x => x.Order)
             .Includes(x => x.Workflow)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
@@ -1519,7 +1524,7 @@ public class OrderController : BaseController
         var view = dto.source == 1;
         var handler = dto.source == 1 && dto.Status is EScreenStatus.Apply;
 
-        var query = _orderScreenRepository.Queryable(viewFilter: view, handlerFilter: handler)
+        var query = _orderScreenRepository.Queryable(canView: view, hasHandled: handler)
             .Includes(x => x.Order)
             .Includes(x => x.VisitDetail)
             .Includes(x => x.Visit, d => d.Order)
@@ -1717,7 +1722,7 @@ public class OrderController : BaseController
     [HttpGet("screen/{id}")]
     public async Task<OrderScreenListDto> ScreenEntity(string id)
     {
-        var model = await _orderScreenRepository.Queryable(viewFilter: false)
+        var model = await _orderScreenRepository.Queryable(canView: false)
             .Includes(x => x.Order)
             .Includes(x => x.Workflow)
             .Includes(x => x.Visit, d => d.Order)
@@ -2179,7 +2184,7 @@ public class OrderController : BaseController
     public async Task<FileStreamResult> ExportOrders([FromBody] ExportExcelDto<QueryOrderDto> dto)
     {
         var query = _orderApplication.QueryOrders(dto.QueryDto);
-        List<Order> orders;
+        List<Orders.Order> orders;
         if (dto.IsExportAll)
         {
             orders = await query.ToListAsync(HttpContext.RequestAborted);
@@ -2255,26 +2260,27 @@ public class OrderController : BaseController
         if (order == null)
             return new();
 
-        string? countersignId = null;
-        var canPrevious = false;
+        var dto = _mapper.Map<OrderDto>(order);
+
         if (!string.IsNullOrEmpty(order.WorkflowId))
         {
             var result = await _workflowDomainService.GetWorkflowHandlePermissionAsync(
-                order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
+                order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
                 cancellationToken: HttpContext.RequestAborted);
-            order.Workflow = result.workflow;
-            countersignId = result.countersignId;
-            canPrevious = result.canPrevious;
+            //order.Workflow = result.Workflow;
+            dto.CountersignId = result.CountersignId;
+            dto.CanHandle = result.CanHandle;
+            dto.CanPrevious = result.CanPrevious;
 
-            await _mediator.Publish(new GetOrderDetailNotify(order.Workflow,
+            await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
         }
 
-        var dto = _mapper.Map<OrderDto>(order!);
-        dto.CountersignId = countersignId;
-        dto.CanHandle = order.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
+        //var dto = _mapper.Map<OrderDto>(order!);
+        //dto.CountersignId = countersignId;
+        //dto.CanHandle = order.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
         dto.IsCanDelay = !order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining);
         if (order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId))
         {
@@ -2310,14 +2316,14 @@ public class OrderController : BaseController
             dto.DelayString = "";
         }
 
-        dto.CanPrevious = canPrevious;
+        //dto.CanPrevious = canPrevious;
 
         if (dto.FileJson != null && dto.FileJson.Any())
         {
             var ids = order.FileJson.Select(x => x.Id).ToList();
             var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
             //x.Classify == "办理上传" &&
-		   dto.Files = files.Where(x =>string.IsNullOrEmpty(x.FlowKey)).ToList();
+            dto.Files = files.Where(x => string.IsNullOrEmpty(x.FlowKey)).ToList();
         }
 
         var call = await _trCallRecordRepository.Queryable().Where(x => x.CallAccept == order.CallId).FirstAsync();
@@ -2359,7 +2365,7 @@ public class OrderController : BaseController
                 throw UserFriendlyException.SameMessage("来电已保存工单");
         }
 
-        var order = _mapper.Map<Order>(dto);
+        var order = _mapper.Map<Orders.Order>(dto);
         order.SignerId = _sessionContext.UserId;
         order.SignerName = _sessionContext.UserName;
         order.InitId();
@@ -2425,11 +2431,11 @@ public class OrderController : BaseController
         var copy = new OrderCopy();
         _mapper.Map(order, copy);
         copy.OrderId = order.Id;
-		copy.AuditTime = DateTime.Now;
-		copy.AuditUserId = _sessionContext.UserId;
-		copy.AuditUserName = _sessionContext.UserName;
-		copy.InitId();
-		await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
+        copy.AuditTime = DateTime.Now;
+        copy.AuditUserId = _sessionContext.UserId;
+        copy.AuditUserName = _sessionContext.UserName;
+        copy.InitId();
+        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
         return order.Id;
     }
 
@@ -2532,16 +2538,16 @@ public class OrderController : BaseController
         await _orderRepository.UpdateNav(order).Include(d => d.OrderExtension).ExecuteCommandAsync();
         //敏感分词
         await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
-		// 副本工单
-		var copy = new OrderCopy();
-		_mapper.Map(order, copy);
-		copy.OrderId = order.Id;
-		copy.AuditTime = DateTime.Now;
+        // 副本工单
+        var copy = new OrderCopy();
+        _mapper.Map(order, copy);
+        copy.OrderId = order.Id;
+        copy.AuditTime = DateTime.Now;
         copy.AuditUserId = _sessionContext.UserId;
         copy.AuditUserName = _sessionContext.UserName;
-		copy.InitId();
-		await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
-	}
+        copy.InitId();
+        await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted);
+    }
 
     /// <summary>
     /// 开始工单办理流程
@@ -2598,7 +2604,8 @@ public class OrderController : BaseController
             var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
             if (dto.Workflow.BusinessType == EBusinessType.Send && averageSendOrder)
             {
-                dto.Workflow.NextHandlers = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                dto.Workflow.NextHandlers = new List<FlowStepHandler> { handler };
             }
             //是否市州互转
             if (dto.Data.Transpond.HasValue && dto.Data.Transpond.Value)
@@ -2704,7 +2711,8 @@ public class OrderController : BaseController
         // 平均派单
         if (dto.BusinessType == EBusinessType.Send && averageSendOrder)
         {
-            dto.NextHandlers = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+            var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+            dto.NextHandlers = new List<FlowStepHandler> { handler };
         }
 
         await _workflowApplication.NextAsync(dto, _sessionContext, order.ExpiredTime, HttpContext.RequestAborted);
@@ -2848,7 +2856,7 @@ public class OrderController : BaseController
     [HttpPost("order_repeatable_event")]
     public async Task<bool> RepeatableEvent(QueryRepeatableEventDto dto)
     {
-        var exp = Expressionable.Create<Order>()
+        var exp = Expressionable.Create<Orders.Order>()
             .OrIF(!string.IsNullOrEmpty(dto.HotspotSpliceName),
                 x => x.HotspotSpliceName.EndsWith(dto.HotspotSpliceName!))
             .OrIF(!string.IsNullOrEmpty(dto.Address), x => x.Address != null && x.Address.EndsWith(dto.Address!));
@@ -2885,7 +2893,7 @@ public class OrderController : BaseController
 	        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
 		var (total, items) = await _orderRepository
-            .Queryable(viewFilter: true, handlerFilter: !isHandled)
+            .Queryable(canView: true, hasHandled: !isHandled)
             .Includes(d => d.OrderSpecials)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword) || d.Title.Contains(dto.Keyword))
@@ -2895,7 +2903,8 @@ public class OrderController : BaseController
             .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
             .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
             .Where(d => d.Status != EOrderStatus.BackToProvince)
-			.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
+            //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
+            .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State == 0) == false)
             .WhereIF(dto.StartTime.HasValue ,d=>d.StartTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, d=> d.StartTime <= dto.EndTime)
 			.OrderByDescending(d => d.StartTime)
@@ -2919,7 +2928,7 @@ public class OrderController : BaseController
         if (dto.EndTime.HasValue)
 	        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
-		var (total, items) = await _orderRepository.Queryable(viewFilter: false)
+		var (total, items) = await _orderRepository.Queryable(canView: false)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
@@ -2928,8 +2937,8 @@ public class OrderController : BaseController
             .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
             .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
             .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
-            .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-            .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
+            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
 			.Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
             .Where(x => x.Status != EOrderStatus.BackToProvince)
             .OrderBy(d => d.Status)
@@ -2952,14 +2961,14 @@ public class OrderController : BaseController
         if (dto.StartTimeEnd.HasValue)
             dto.StartTimeEnd = dto.StartTimeEnd.Value.AddDays(1).AddSeconds(-1);
 
-        var (total, items) = await _orderRepository.Queryable(viewFilter: false)
+        var (total, items) = await _orderRepository.Queryable(canView: false)
             .Where(x => x.Workflow.Steps.Any(s => s.Status < EWorkflowStepStatus.Handled && s.StepHandlers.Any(d => d.OrgId == OrgSeedData.CenterId)))
             .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
             .Where(x => x.Status != EOrderStatus.BackToProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No!.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title!.Contains(dto.Title!))
             .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, x => x.CreationTime >= dto.StCreationTime && x.CreationTime <= dto.EndCreationTime)
-            .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, x => x.CreationTime >= dto.StartTimeSt && x.CreationTime <= dto.StartTimeEnd)
+            .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, x => x.StartTime >= dto.StartTimeSt && x.StartTime <= dto.StartTimeEnd)
             .WhereIF(!string.IsNullOrEmpty(dto.StepName), x => x.Workflow.Steps.Any(s => s.Name == dto.StepName))
             .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
             .WhereIF(dto.Status.HasValue, x => x.Status == dto.Status)
@@ -3004,7 +3013,7 @@ public class OrderController : BaseController
         if (dto.EndTime.HasValue)
 	        dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 		var (total, items) = await _orderRepository
-            .Queryable(viewFilter: true, handlerFilter: !isHandled)
+            .Queryable(canView: true, hasHandled: !isHandled)
             .Includes(d => d.OrderSpecials)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword) || d.Title.Contains(dto.Keyword))
@@ -3012,12 +3021,13 @@ public class OrderController : BaseController
             .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => !d.CounterSignType.HasValue)
             .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办
             .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now)//即将超期 未办
-            .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-            .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
+            .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
 			.Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
             .Where(d => d.Status != EOrderStatus.BackToProvince)
-			.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
-			.OrderByDescending(d => d.StartTime)
+            //.Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id).NotAny())
+            .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State == 0) == false)
+            .OrderByDescending(d => d.StartTime)
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
         var page1 = new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
@@ -3029,7 +3039,7 @@ public class OrderController : BaseController
                     : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept)
             .ToArray();
 
-        var (total2, items2) = await _orderRepository.Queryable(viewFilter: false)
+        var (total2, items2) = await _orderRepository.Queryable(canView: false)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status))
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword!) || d.Title.Contains(dto.Keyword!))
@@ -3063,11 +3073,11 @@ public class OrderController : BaseController
         var oneSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.OneOrgSendBack)?.SettingValue[0]);
         var twoSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TwoOrgSendBack)?.SettingValue[0]);
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, cancellationToken: HttpContext.RequestAborted);
-		var order = await _orderRepository
-	        .Queryable()
-	        .Includes(d => d.Workflow)
-	        .FirstAsync(d => d.Id == workflow.ExternalId);
-		if (oneSendBack || twoSendBack)
+        var order = await _orderRepository
+            .Queryable()
+            .Includes(d => d.Workflow)
+            .FirstAsync(d => d.Id == workflow.ExternalId);
+        if (oneSendBack || twoSendBack)
         {
             var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
                 dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
@@ -3079,7 +3089,7 @@ public class OrderController : BaseController
                 .AnyAsync();
             if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息!");
 
-            
+
             if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行退回!");
             if ((oneSendBack && isOrgToCenter) || (twoSendBack && isSecondToFirstOrgLevel))
             {
@@ -3102,21 +3112,21 @@ public class OrderController : BaseController
             }
             else
             {
-               var flowDirection =  await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
-               var processType = flowDirection  == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-               await _orderRepository.Updateable().SetColumns(o => new Order() {  ProcessType = processType })
-	               .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
-				//发送短信TODO
-			}
+                var flowDirection = await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
+                var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
+                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
+                //发送短信TODO
+            }
         }
         else
         {
-			var flowDirection = await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
+            var flowDirection = await _workflowApplication.PreviousAsync(dto, HttpContext.RequestAborted);
             var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-            await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType })
-	            .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
-			//发送短信TODO
-		}
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
+                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
+            //发送短信TODO
+        }
     }
 
     /// <summary>
@@ -3145,13 +3155,13 @@ public class OrderController : BaseController
         //执行退回
         if (sendBack.State == ESendBackAuditState.End)
         {
-			var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
-			var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-			await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType })
-				.Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
-			//发送短信TODO
+            var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
+            var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
+                .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
+            //发送短信TODO
 
-		}
+        }
         await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
     }
 
@@ -3181,13 +3191,13 @@ public class OrderController : BaseController
             //执行退回
             if (sendBack.State == ESendBackAuditState.End)
             {
-	            var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
+                var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted);
                 var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-                await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType })
-	                .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
-				//发送短信TODO
+                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
+                    .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
+                //发送短信TODO
 
-			}
+            }
             await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted);
         }
 
@@ -3477,11 +3487,11 @@ public class OrderController : BaseController
             //if (dto.AlterTime)
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter? EProcessType.Zhiban : EProcessType.Jiaoban;
-			//var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
-			//	ETimeType.WorkDay,
-			//	dto.TimeLimit.Value, order.AcceptTypeCode);
-			await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime,ProcessType = processType })
+            var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+            //var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now,
+            //	ETimeType.WorkDay,
+            //	dto.TimeLimit.Value, order.AcceptTypeCode);
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
@@ -3607,15 +3617,15 @@ public class OrderController : BaseController
                     ETimeType.WorkDay,
                     dto.TimeLimit.Value, order.AcceptTypeCode);
                 endTime = expiredTime.EndTime;
-                await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.EndTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
+                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.EndTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
             }
             var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-			await _orderRepository.Updateable().SetColumns(o => new Order() { ProcessType = processType })
-	            .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
-			await _workflowApplication.RecallAsync(recall, endTime, HttpContext.RequestAborted);
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType })
+                .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
+            await _workflowApplication.RecallAsync(recall, endTime, HttpContext.RequestAborted);
             var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId);
             if (publish != null)
             {
@@ -3631,7 +3641,7 @@ public class OrderController : BaseController
                 await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted);
             }
             var reTransactNum = order.ReTransactNum.HasValue ? order.ReTransactNum.Value + 1 : 1;
-            await _orderRepository.Updateable().SetColumns(o => new Order() { ReTransactNum = reTransactNum }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ReTransactNum = reTransactNum }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
 
             var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None);
             if (visit != null)
@@ -3685,7 +3695,7 @@ public class OrderController : BaseController
             //{
             var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
             var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-			await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
+            await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
@@ -3782,7 +3792,7 @@ public class OrderController : BaseController
                 //{
                 var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
                 var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-				await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
+                await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ProcessType = processType })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
@@ -4673,12 +4683,12 @@ public class OrderController : BaseController
         {
             var workflow = await _workflowDomainService.SignToSomebodyAsync(
                 order.WorkflowId,
-                _sessionContext.RequiredUserId, _sessionContext.UserName, 
+                _sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 HttpContext.RequestAborted);
 
             order.HandlerOrgs = workflow.HandlerOrgs;
-            order.HandlerUsers= workflow.HandlerUsers;
+            order.HandlerUsers = workflow.HandlerUsers;
             order.FlowedOrgIds = workflow.FlowedOrgIds;
             order.FlowedUserIds = workflow.FlowedUserIds;
         }
@@ -4749,7 +4759,7 @@ public class OrderController : BaseController
                         var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == item.Source, HttpContext.RequestAborted);
                         if (order is null)
                         {
-                            order = _mapper.Map<Order>(item);
+                            order = _mapper.Map<Orders.Order>(item);
                             //order.Source = item;
                             var id = await _orderRepository.AddAsync(order, HttpContext.RequestAborted);
                             if (!string.IsNullOrEmpty(id))
@@ -4984,25 +4994,214 @@ public class OrderController : BaseController
         };
         return rsp;
     }
-	#endregion
-
-	#region 副本工单
-
-	/// <summary>
-	/// 获取副本工单列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[HttpGet("order_copy/list")]
-	public async Task<PagedDto<OrderDto>> OrderCopyList([FromQuery] OrderCopyListDto dto)
-	{
-		var (total, items) = await _orderCopyRepository.Queryable()
-            .Where(x=>x.OrderId == dto.OrderId)
-			.WhereIF(!string.IsNullOrEmpty(dto.Keyword),x => x.No.Contains(dto.Keyword!))
-			.OrderByDescending(x => x.CreationTime)
-			.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-		return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-	}
-
-	#endregion
+    #endregion
+
+    #region 副本工单
+
+    /// <summary>
+    /// 获取副本工单列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("order_copy/list")]
+    public async Task<PagedDto<OrderDto>> OrderCopyList([FromQuery] OrderCopyListDto dto)
+    {
+        var (total, items) = await _orderCopyRepository.Queryable()
+            .Where(x => x.OrderId == dto.OrderId)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+    }
+
+    #endregion
+
+    #region 外部市民管理
+
+    /// <summary>
+    /// 下载外部市民导入模板
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("download-externalcitizens-template")]
+    public async Task<object> DownLoadCitizensTemplate()
+    {
+        List<ExternalCitizensExcelContent> list = new List<ExternalCitizensExcelContent>();
+        ExternalCitizensExcelContent excelContent = new ExternalCitizensExcelContent() { };
+        list.Add(excelContent);
+        return _exportApplication.ExportData(list, "demo.xlsx");
+    }
+
+    /// <summary>
+    /// 导入外部市民
+    /// </summary>
+    /// <param name="file"></param>
+    /// <returns></returns>
+    [HttpPost("import-externalcitizens")]
+    public async Task<object> ImportExternalcitizens(IFormFile file)
+    {
+        using (var stream = new MemoryStream())
+        {
+            file.CopyTo(stream);
+            var list = MiniExcel.Query<ExternalCitizensExcelContent>(stream).ToList();
+            int count = 0;
+            int errorCount = 0;
+            int addCount = 0;
+            //int modifyCount = 0;
+            List<ExternalCitizensExcelContent> listreturn = new List<ExternalCitizensExcelContent>();
+            if (list != null && list.Count > 0)
+            {
+                count = list.Count;
+                foreach (var item in list)
+                {
+                    try
+                    {
+                        var externalcitizens = await _externalCitizensRepository.GetAsync(x => x.PhoneNum == item.PhoneNum, HttpContext.RequestAborted);
+                        if (externalcitizens is null)
+                        {
+                            externalcitizens = _mapper.Map<ExternalCitizens>(item);
+                            var id = await _externalCitizensRepository.AddAsync(externalcitizens, HttpContext.RequestAborted);
+                            if (!string.IsNullOrEmpty(id))
+                            {
+                                addCount++;
+                                listreturn.Add(item);
+                            }
+                            else
+                            {
+                                errorCount++;
+                            }
+                        }
+                        else
+                        {
+                            listreturn.Add(item);
+                            //_mapper.Map(item, externalcitizens);
+                            //await _externalCitizensRepository.UpdateAsync(externalcitizens, HttpContext.RequestAborted);
+                            //modifyCount++;
+                        }
+                    }
+                    catch (Exception ex)
+                    {
+                        errorCount++;
+                    }
+                }
+            }
+            return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ResultList = listreturn /*, ModifyCount = modifyCount*/ };
+        }
+    }
+
+    /// <summary>
+    /// 外部市民列表
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("externalcitizens-list")]
+    public async Task<PagedDto<ExternalcitizensRep>> QueryExternalcitizens([FromQuery] QueryExternalcitizensRequest dto)
+    {
+        var (total, items) = await _externalCitizensRepository.Queryable()
+            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNum), x => x.PhoneNum.Contains(dto.PhoneNum))
+            .WhereIF(!string.IsNullOrEmpty(dto.Name), x => x.Name.Contains(dto.Name))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+        return new PagedDto<ExternalcitizensRep>(total, _mapper.Map<IReadOnlyList<ExternalcitizensRep>>(items));
+    }
+
+
+    #endregion
+
+    #region 工单期满时间、来源方式修改
+    /// <summary>
+    /// 修改期满时间  
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("update-orderexpired-time")]
+    public async Task UpdateOrderExpiredTime([FromBody] UpdateOrderExpiredTimeDto dto)
+    {
+        if (dto == null || string.IsNullOrEmpty(dto.Id) || !dto.ExpiredTime.HasValue)
+            throw UserFriendlyException.SameMessage("参数信息有误!");
+
+        var orderData = await _orderRepository.GetAsync(p => p.Id == dto.Id, HttpContext.RequestAborted);
+        if (orderData == null)
+            throw UserFriendlyException.SameMessage("工单查询失败!");
+
+        #region 写入操作记录
+        OrderModifyingRecords orderModifyingRecords = new()
+        {
+            OrderId = orderData.Id,
+            OrderNo = orderData.No,
+            ProvinceNo = orderData.ProvinceNo,
+            UpdateOrderType = EUpdateType.ExpiredTime,
+            OldValue = orderData.ExpiredTime == null ? "" : orderData.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss"),
+            NewValue = dto.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss")
+        };
+        await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted);
+        #endregion
+
+        //写入新的数据
+        orderData.ExpiredTime = dto.ExpiredTime;
+        await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted);
+
+        //向省上推送数据
+        if (dto.IsPush && orderData.Status > EOrderStatus.WaitForAccept)
+        {
+            var orderDto = _mapper.Map<OrderDto>(orderData);
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
+        }
+    }
+
+    /// <summary>
+    /// 修改来源方式
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("update-order-sourcechannel")]
+    public async Task UpdateOrderSourceChannel([FromBody] UpdateOrderSourceChannelDto dto)
+    {
+        if (dto == null || dto.Ids == null || dto.Ids.Count == 0)
+            throw UserFriendlyException.SameMessage("参数信息有误!");
+
+        foreach (var item in dto.Ids)
+        {
+            var orderData = await _orderRepository.GetAsync(p => p.Id == item, HttpContext.RequestAborted);
+
+            if (orderData != null)
+            {
+                #region 写入操作记录
+                OrderModifyingRecords orderModifyingRecords = new()
+                {
+                    OrderId = orderData.Id,
+                    OrderNo = orderData.No,
+                    ProvinceNo = orderData.ProvinceNo,
+                    UpdateOrderType = EUpdateType.SourceChannel,
+                    OldValue = orderData.SourceChannelCode + "_" + orderData.SourceChannel,
+                    NewValue = "QT_其他"
+                };
+                await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted);
+                #endregion
+
+                orderData.SourceChannel = "其他";
+                orderData.SourceChannelCode = "QT";
+                await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted);
+
+                //向省上推送数据
+                if (dto.IsPush)
+                {
+                    var orderDto = _mapper.Map<OrderDto>(orderData);
+                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted);
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// 获取修改记录
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("get-order-modifying-records-list")]
+    public async Task<IReadOnlyList<OrderModifyingRecordsDto>> GetOrderModifyingRecordsList([FromQuery] string Id)
+    {
+
+        var list = await _orderModifyingRecordsRepository.Queryable().Where(p => p.OrderId == Id).OrderByDescending(p => p.CreationTime).ToListAsync();
+        return _mapper.Map<IReadOnlyList<OrderModifyingRecordsDto>>(list);
+    }
+    #endregion
 }

+ 87 - 70
src/Hotline.Api/Controllers/TestController.cs

@@ -93,6 +93,7 @@ public class TestController : BaseController
     private readonly IRepository<WorkflowStepHandler> _workflowStepHandleRepository;
 
     private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
+    private readonly IOrderRepository _orderRepository;
     private readonly IMapper _mapper;
 
 
@@ -130,6 +131,7 @@ public class TestController : BaseController
         IRepository<WorkflowTrace> workflowTraceRepository,
         IRepository<WorkflowStepHandler> workflowStepHandleRepository,
         IRepository<SystemOrganize> systemOrganizeRepository,
+        IOrderRepository orderRepository,
         IMapper mapper
         )
     {
@@ -159,6 +161,8 @@ public class TestController : BaseController
         _workflowTraceRepository = workflowTraceRepository;
         _workflowStepHandleRepository = workflowStepHandleRepository;
         _systemOrganizeRepository = systemOrganizeRepository;
+        _orderRepository = orderRepository;
+        _orderRepository = orderRepository;
         _mapper = mapper;
     }
 
@@ -267,7 +271,14 @@ public class TestController : BaseController
         //await _repositoryts.AddVectorAsync("f595e730-909a-45e4-9138-a84bf15f4662", DateTime.Now,
         //    new List<string> { "xx", "bb" }, HttpContext.RequestAborted);
 
-        //var result = await _repositoryts.SearchAsync(new List<string> { "bb" }, HttpContext.RequestAborted);
+        //await _repositoryts.AddVectorAsync("f595e730-909a-45e4-9138-a84bf15f4663", DateTime.Now,
+        //    new List<string> { "aa", "bb", "cc" }, HttpContext.RequestAborted);
+
+        var result0 = await _repositoryts.SearchAsync(new List<string> { "xx", "aa" }, HttpContext.RequestAborted);
+        var result = await _repositoryts.SearchAsync(new List<string> { "bb" }, HttpContext.RequestAborted);
+        var result1 = await _repositoryts.SearchAsync(new List<string> { "cc", "bb" }, HttpContext.RequestAborted);
+        var result2 = await _repositoryts.SearchAsync(new List<string> { "cc", "xx" }, HttpContext.RequestAborted);
+        var result3 = await _repositoryts.SearchAsync(new List<string> { "aa", "bb", "ss" }, HttpContext.RequestAborted);
 
         //await _repositoryts.UpdateVectorAsync("f595e730-909a-45e4-9138-a84bf15f4662",
         //    new List<string> { "ss", "bb" }, HttpContext.RequestAborted);
@@ -464,82 +475,88 @@ public class TestController : BaseController
         //     .Where(d => !SqlFunc.Subqueryable<WorkflowStepHandler>().Where(x => x.WorkflowStepId == d.StepId).Any())
         //     .ToListAsync(HttpContext.RequestAborted);
 
-        var handlerStepIds = await _workflowStepHandleRepository
-            .Queryable()
-            .Select(d=>d.WorkflowStepId)
-            .ToListAsync(HttpContext.RequestAborted);
-        _logger.LogInformation($"handler stepids: {handlerStepIds.Count}");
-
-        var items = await _workflowTraceRepository
-            .Queryable()
-            .Where(d => !handlerStepIds.Distinct().Contains(d.StepId))
-            .ToListAsync(HttpContext.RequestAborted);
-        _logger.LogInformation($"traces.count: {items.Count}");
+        //var handlerStepIds = await _workflowStepHandleRepository
+        //    .Queryable()
+        //    .Select(d=>d.WorkflowStepId)
+        //    .ToListAsync(HttpContext.RequestAborted);
+        //_logger.LogInformation($"handler stepids: {handlerStepIds.Count}");
 
-        //var items = await _workflowTraceRepository.Queryable()
-        //    .LeftJoin<WorkflowStepHandler>((t, h) => t.StepId == h.WorkflowStepId)
-        //    .Where((t, h) => h == null)
-        //    .Select((t, h) => new { t, h })
+        //var items = await _workflowTraceRepository
+        //    .Queryable()
+        //    .Where(d => !handlerStepIds.Distinct().Contains(d.StepId))
+        //    .ToListAsync(HttpContext.RequestAborted);
+        //_logger.LogInformation($"traces.count: {items.Count}");
+
+        ////var items = await _workflowTraceRepository.Queryable()
+        ////    .LeftJoin<WorkflowStepHandler>((t, h) => t.StepId == h.WorkflowStepId)
+        ////    .Where((t, h) => h == null)
+        ////    .Select((t, h) => new { t, h })
+        ////    .ToListAsync(HttpContext.RequestAborted);
+
+        //var handlerIds = items.Select(d => d)
+        //    .SelectMany(d => d.Handlers)
+        //    .Select(d => d.Key)
+        //    .Distinct()
+        //    .ToList();
+        //var users = await _userRepository.Queryable()
+        //    .Includes(d => d.Organization)
+        //    .Where(d => handlerIds.Contains(d.Id))
+        //    .ToListAsync(HttpContext.RequestAborted);
+        //var orgs = await _systemOrganizeRepository.Queryable()
+        //    .Where(d => handlerIds.Contains(d.Id))
         //    .ToListAsync(HttpContext.RequestAborted);
 
-        var handlerIds = items.Select(d => d)
-            .SelectMany(d => d.Handlers)
-            .Select(d => d.Key)
-            .Distinct()
-            .ToList();
-        var users = await _userRepository.Queryable()
-            .Includes(d => d.Organization)
-            .Where(d => handlerIds.Contains(d.Id))
-            .ToListAsync(HttpContext.RequestAborted);
-        var orgs = await _systemOrganizeRepository.Queryable()
-            .Where(d => handlerIds.Contains(d.Id))
-            .ToListAsync(HttpContext.RequestAborted);
+        //var handlers = new List<WorkflowStepHandler>();
+        //var updateTraces = new List<WorkflowTrace>();
+        //foreach (var item in items)
+        //{
+        //    var trace = item;
+        //    foreach (var traceHandler in trace.Handlers)
+        //    {
+        //        if (!trace.FlowAssignType.HasValue)
+        //        {
+        //            trace.FlowAssignType = traceHandler.Key.Length == 36 ? EFlowAssignType.User : EFlowAssignType.Org;
+        //            updateTraces.Add(trace);
+        //        }
 
-        var handlers = new List<WorkflowStepHandler>();
-        var updateTraces = new List<WorkflowTrace>();
-        foreach (var item in items)
-        {
-            var trace = item;
-            foreach (var traceHandler in trace.Handlers)
-            {
-                if (!trace.FlowAssignType.HasValue)
-                {
-                    trace.FlowAssignType = traceHandler.Key.Length == 36 ? EFlowAssignType.User : EFlowAssignType.Org;
-                    updateTraces.Add(trace);
-                }
+        //        if (trace.FlowAssignType == EFlowAssignType.User)
+        //        {
+        //            var user = users.FirstOrDefault(d => d.Id == traceHandler.Key);
+        //            if (user != null)
+        //            {
+        //                var stepHandler = WorkflowStepHandler.Create(trace.WorkflowId, trace.ExternalId,
+        //                    trace.FlowAssignType.Value, user.Id, user.Name, user.OrgId, user.Organization.Name);
+        //                stepHandler.WorkflowStepId = trace.StepId;
+        //                handlers.Add(stepHandler);
+        //            }
+        //        }
+        //        else
+        //        {
+        //            var org = orgs.FirstOrDefault(d => d.Id == traceHandler.Key);
+        //            if (org != null)
+        //            {
+        //                var stepHandler = WorkflowStepHandler.Create(trace.WorkflowId, trace.ExternalId,
+        //                    trace.FlowAssignType.Value, orgId: org.Id, orgName: org.Name);
+        //                stepHandler.WorkflowStepId = trace.StepId;
+        //                handlers.Add(stepHandler);
+        //            }
+        //        }
+        //    }
+        //}
 
-                if (trace.FlowAssignType == EFlowAssignType.User)
-                {
-                    var user = users.FirstOrDefault(d => d.Id == traceHandler.Key);
-                    if (user != null)
-                    {
-                        var stepHandler = WorkflowStepHandler.Create(trace.WorkflowId, trace.ExternalId,
-                            trace.FlowAssignType.Value, user.Id, user.Name, user.OrgId, user.Organization.Name);
-                        stepHandler.WorkflowStepId = trace.StepId;
-                        handlers.Add(stepHandler);
-                    }
-                }
-                else
-                {
-                    var org = orgs.FirstOrDefault(d => d.Id == traceHandler.Key);
-                    if (org != null)
-                    {
-                        var stepHandler = WorkflowStepHandler.Create(trace.WorkflowId, trace.ExternalId,
-                            trace.FlowAssignType.Value, orgId: org.Id, orgName: org.Name);
-                        stepHandler.WorkflowStepId = trace.StepId;
-                        handlers.Add(stepHandler);
-                    }
-                }
-            }
-        }
+        //_logger.LogInformation($"待更新traces: {updateTraces.Count}");
+        //if (updateTraces.Any())
+        //    await _workflowTraceRepository.UpdateRangeAsync(updateTraces, HttpContext.RequestAborted);
 
-        _logger.LogInformation($"待更新traces: {updateTraces.Count}");
-        if (updateTraces.Any())
-            await _workflowTraceRepository.UpdateRangeAsync(updateTraces, HttpContext.RequestAborted);
+        //_logger.LogInformation($"待更新traces: {handlers.Count}");
+        //if (handlers.Any())
+        //    await _workflowStepHandleRepository.AddRangeAsync(handlers, HttpContext.RequestAborted);
 
-        _logger.LogInformation($"待更新traces: {handlers.Count}");
-        if (handlers.Any())
-            await _workflowStepHandleRepository.AddRangeAsync(handlers, HttpContext.RequestAborted);
+        ///////
+
+        var orders = await _orderRepository.Queryable(hasHandled: true)
+            //.Where(entity=>entity.CreationTime>= DateTime.Now.AddMonths(-1))
+            .ToListAsync(HttpContext.RequestAborted);
     }
 
     [HttpGet("rsa")]

+ 3 - 0
src/Hotline.Application.Contracts/Validators/FlowEngine/StartWorkflowDtoValidator.cs

@@ -6,6 +6,7 @@ using System.Threading.Tasks;
 using FluentValidation;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Application.Contracts.Validators;
+using Hotline.Share.Enums.FlowEngine;
 
 namespace Hotline.Application.Contracts.Validators.FlowEngine
 {
@@ -23,6 +24,8 @@ namespace Hotline.Application.Contracts.Validators.FlowEngine
             RuleFor(d => d.NextStepCode).NotEmpty();
             RuleFor(d => d.IsSms).NotNull();
             RuleFor(d => d.IsStartCountersign).NotNull();
+            RuleFor(d => d.NextHandlers.Count).LessThanOrEqualTo(1)
+                .Unless(d => d.IsStartCountersign);
             RuleFor(d => d.Opinion)
                 .Cascade(CascadeMode.Stop)
                 .NotEmpty()

+ 2 - 1
src/Hotline.Application/CallCenter/Calls/ITrApplication.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.CallCenter;
 
 namespace Hotline.Application.CallCenter.Calls
 {
@@ -9,7 +10,7 @@ namespace Hotline.Application.CallCenter.Calls
         /// </summary>
         /// <param name="telNo"></param>
         /// <returns></returns>
-        Task<TrOnDutyResponseDto> OnSign(string userId,string telNo, CancellationToken cancellationToken);
+        Task<TrOnDutyResponseDto> OnSign(string userId,string telNo, ETelModel telModelState, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询当前用户的分机状态

+ 8 - 6
src/Hotline.Application/CallCenter/Calls/TrApplication.cs

@@ -48,7 +48,7 @@ namespace Hotline.Application.CallCenter.Calls
         /// <param name="telNo"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task<TrOnDutyResponseDto> OnSign(string userId,string telNo,CancellationToken cancellationToken)
+        public async Task<TrOnDutyResponseDto> OnSign(string userId,string telNo,ETelModel telModelState,CancellationToken cancellationToken)
         {
             var work = _userCacheManager.GetWorkByUserNoExp(userId);
             if (work is not null)
@@ -69,7 +69,7 @@ namespace Hotline.Application.CallCenter.Calls
             var telModel = await _trClient.QueryTelsAsync(new Tr.Sdk.Tels.QueryTelRequest() { TelNo = telNo }, cancellationToken);
             if (telModel !=null && telModel.Count>0)
             {
-                work = new Work(_sessionContext.UserId, _sessionContext.UserName, telModel[0].Id, telNo, telModel[0].Password, telModel[0].Description, telModel[0].QueueId,_sessionContext.StaffNo, ETelModel.OrdinaryModel);
+                work = new Work(_sessionContext.UserId, _sessionContext.UserName, telModel[0].Id, telNo, telModel[0].Password, telModel[0].Description, telModel[0].QueueId,_sessionContext.StaffNo, telModelState);
                 await _workRepository.AddAsync(work, cancellationToken);
                 //记录签入日志
                 var actionRecord = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, EActionType.SignIn);
@@ -79,11 +79,11 @@ namespace Hotline.Application.CallCenter.Calls
                 string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
                 if (IsTelNeedVerify)
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = telNo, TelPwd = "", Description = telModel[0].Description, QueueId = telModel[0].QueueId,StartTime = work.StartTime};
+                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId,TelModel = telModelState, TelNo = telNo, TelPwd = "", Description = telModel[0].Description, QueueId = telModel[0].QueueId,StartTime = work.StartTime};
                 }
                 else
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = telNo, TelPwd = telModel[0].Password, Description = telModel[0].Description, QueueId = telModel[0].QueueId,StartTime = work.StartTime };
+                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelModel = telModelState, TelNo = telNo, TelPwd = telModel[0].Password, Description = telModel[0].Description, QueueId = telModel[0].QueueId,StartTime = work.StartTime };
                 }
             }
             throw UserFriendlyException.SameMessage("签入异常,未查询到对应分机信息");
@@ -106,15 +106,17 @@ namespace Hotline.Application.CallCenter.Calls
 
                 bool isCallEndArrange = await _telActionRecordRepository.AnyAsync(x => x.TelNo == work.TelNo && x.UserId == userId && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
 
+                bool isTelMute = await _telActionRecordRepository.AnyAsync(x => x.TelNo == work.TelNo && x.UserId == userId && x.ActionType == EActionType.TelMute && !x.EndTime.HasValue, cancellationToken);
+
                 bool IsTelNeedVerify = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsTelNeedVerify).SettingValue[0]);
                 string callOutQueueId = _systemSettingCacheManager.GetSetting(SettingConstants.CallOutQueueId).SettingValue[0];
                 if (IsTelNeedVerify)
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut= callOutQueueId, TelNo = work.TelNo, TelPwd = "", Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold, IsCallEndArrange = isCallEndArrange };
+                    return new TrOnDutyResponseDto() { QueueCallOut= callOutQueueId, TelNo = work.TelNo, TelPwd = "", Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold, IsCallEndArrange = isCallEndArrange, IsTelMute = isTelMute };
                 }
                 else
                 {
-                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = work.TelNo, TelPwd = work.TelPwd, Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold, IsCallEndArrange = isCallEndArrange };
+                    return new TrOnDutyResponseDto() { QueueCallOut = callOutQueueId, TelNo = work.TelNo, TelPwd = work.TelPwd, Description = work.Description, QueueId = work.QueueId, StartTime = work.StartTime, IsRest = isRest, TelModel = work.TelModel, IsCallHold = isCallHold, IsCallEndArrange = isCallEndArrange,IsTelMute = isTelMute };
                 }
                
             }

+ 144 - 34
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -151,7 +151,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             current.RequiredOrgId, current.OrgName)};
 
         var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto,
-            new List<Kv> { new(current.RequiredUserId, current.UserName) },
+            new FlowStepHandler
+            {
+                Key = current.RequiredUserId,
+                Value = current.UserName,
+                UserId = current.UserId,
+                Username = current.UserName,
+                OrgId = current.RequiredOrgId,
+                OrgName = current.OrgName
+            },
             startStepHandles, expiredTime);
 
         var flowAssignInfo =
@@ -310,7 +318,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             throw UserFriendlyException.SameMessage("结束节点不支持撤回");
         //var isStartCountersign = targetStepDefine.CouldPrevStartCountersign(dto.NextHandlers.Count);
         var flowAssignInfo = await GetNextStepFlowAssignInfoByDefineAsync(targetStepDefine, dto.IsStartCountersign,
-            dto.NextHandlers, cancellationToken);
+            dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList(), cancellationToken);
 
         var stepHandlers = await GetNextStepHandlersAsync(workflow, targetStepDefine, dto, cancellationToken);
 
@@ -691,15 +699,22 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             {
                 //根据汇总对象id找到被汇总节点
                 var summaryTargetStep = workflow.Steps.FirstOrDefault(d =>
-                    d.Status == EWorkflowStepStatus.Handled &&
                     d.StepType == EStepType.Normal &&
                     d.Code == stepDefine.SummaryTargetCode &&
                     d.IsOrigin);
                 if (summaryTargetStep is null)
                     throw UserFriendlyException.SameMessage("未查询到汇总对象节点");
 
-                var handlers = summaryTargetStep.Handlers
-                    .Where(d => d.Key == summaryTargetStep.HandlerId || d.Key == summaryTargetStep.HandlerOrgId).ToList();
+                //var handlers = summaryTargetStep.Handlers
+                //    .Where(d => d.Key == summaryTargetStep.HandlerId || d.Key == summaryTargetStep.HandlerOrgId).ToList();
+
+                var handler = new FlowStepHandler
+                {
+                    Key = summaryTargetStep.HandlerId,
+                    Value = summaryTargetStep.HandlerName,
+                    UserId = summaryTargetStep.HandlerId,
+                    Username = summaryTargetStep.HandlerName
+                };
 
                 nextStepOption = new NextStepOption
                 {
@@ -707,8 +722,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     Value = stepDefine.Name,
                     StepType = stepDefine.StepType,
                     BusinessType = stepDefine.BusinessType,
-                    HandlerType = stepDefine.HandlerType,
-                    Items = handlers
+                    //HandlerType = stepDefine.HandlerType,
+                    HandlerType = EHandlerType.AssignedUser,//指定办理人(业务需求)
+                    Items = new List<FlowStepHandler> { handler }//handlers
                 };
             }
             else
@@ -728,10 +744,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         return stepOptions;
     }
 
-    public async Task<NextStepOption> GetConfigStepAsync(EFlowType flowType, StepDefine stepDefine,
-        CancellationToken cancellationToken)
+    public async Task<NextStepOption> GetConfigStepAsync(EFlowType flowType, StepDefine stepDefine, CancellationToken cancellationToken)
     {
-        var handlers = new List<Kv>();
+        var handlers = new List<FlowStepHandler>();
         if (stepDefine.StepType is EStepType.End)
         {
             return new NextStepOption
@@ -751,8 +766,31 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         switch (stepDefine.HandlerType)
         {
             case EHandlerType.AssignedUser:
+                handlers = await _userRepository.Queryable()
+                    .Includes(d => d.Organization)
+                    .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
+                    .Select(d => new FlowStepHandler
+                    {
+                        Key = d.Id,
+                        Value = d.Name,
+                        UserId = d.Id,
+                        Username = d.Name,
+                        OrgId = d.OrgId,
+                        OrgName = d.Organization.Name,
+                    })
+                    .ToListAsync(cancellationToken);
+                break;
             case EHandlerType.AssignedOrg:
-                handlers = stepDefine.HandlerTypeItems;
+                handlers = await _organizeRepository.Queryable() //stepDefine.HandlerTypeItems;
+                    .Where(d => d.IsEnable && stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Id))
+                    .Select(d => new FlowStepHandler
+                    {
+                        Key = d.Id,
+                        Value = d.Name,
+                        OrgId = d.Id,
+                        OrgName = d.Name
+                    })
+                    .ToListAsync(cancellationToken);
                 break;
             case EHandlerType.Role:
                 //当前操作人所属部门的下级部门并且属于配置包含角色
@@ -760,7 +798,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     .Includes(
                         d => d.Accounts.Where(x =>
                             !x.IsDeleted && x.Status == EAccountStatus.Normal && x.AccountType == EAccountType.Personal).ToList(),
-                        x => x.User)
+                        x => x.User, s => s.Organization)
                     .Where(d => stepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
                     .ToListAsync(cancellationToken);
                 _logger.LogInformation($"角色: {string.Join(",", roles.Select(d => d.Name))}");
@@ -771,7 +809,17 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     && (stepDefine.StepType != EStepType.Summary && stepDefine.BusinessType != EBusinessType.Center))
                     users1 = users1.Where(d => d.OrgId.StartsWith(levelOneOrgId));
 
-                handlers = users1.Where(d => d != null && !string.IsNullOrEmpty(d.Id)).Select(d => new Kv(d.Id, d.Name)).ToList();
+                handlers = users1.Where(d => d != null && !string.IsNullOrEmpty(d.Id))
+                    .Select(d => new FlowStepHandler
+                    {
+                        Key = d.Id,
+                        Value = d.Name,
+                        UserId = d.Id,
+                        Username = d.Name,
+                        OrgId = d.OrgId,
+                        OrgName = d.Organization.Name
+                    })
+                    .ToList();
                 break;
             case EHandlerType.OrgLevel:
                 //当前操作人所属部门的垂直部门并且属于配置orgLevel的部门
@@ -801,7 +849,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                         .ToListAsync(cancellationToken);
                 }
 
-                handlers = orgs1.Select(d => new Kv(d.Id, d.Name)).ToList();
+                handlers = orgs1.Select(d => new FlowStepHandler
+                {
+                    Key = d.Id,
+                    Value = d.Name,
+                    OrgId = d.Id,
+                    OrgName = d.Name
+                })
+                    .ToList();
                 break;
             case EHandlerType.OrgType:
                 var types = stepDefine.HandlerTypeItems.Select(d => d.Key)
@@ -811,7 +866,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     .WhereIF(!isCenter, d => d.Id.StartsWith(levelOneOrgId))
                     .ToListAsync(cancellationToken);
 
-                handlers = orgs2.Select(d => new Kv(d.Id, d.Name)).ToList();
+                handlers = orgs2.Select(d => new FlowStepHandler
+                {
+                    Key = d.Id,
+                    Value = d.Name,
+                    OrgId = d.Id,
+                    OrgName = d.Name
+                })
+                    .ToList();
                 break;
             default:
                 throw new ArgumentOutOfRangeException();
@@ -839,6 +901,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var handlers = prevStep.Handlers
             .Where(d => d.Key == prevStep.HandlerId || d.Key == prevStep.HandlerOrgId).ToList();
         //var handler = prevStep.GetActualHandler()?.GetHandler();
+        var handler = new FlowStepHandler
+        {
+            Key = prevStep.HandlerId,
+            Value = prevStep.HandlerName,
+            UserId = prevStep.HandlerId,
+            Username = prevStep.HandlerName,
+            OrgId = prevStep.HandlerOrgId,
+            OrgName = prevStep.HandlerOrgName
+        };
 
         return new NextStepOption
         {
@@ -847,8 +918,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             BackToCountersignEnd = true,
             StepType = EStepType.Summary,
             BusinessType = prevStep.BusinessType,
-            HandlerType = prevStep.HandlerType,
-            Items = handlers //new List<Kv> { new(prevStep.HandlerId, prevStep.HandlerName) },
+            //HandlerType = prevStep.HandlerType,
+            HandlerType = EHandlerType.AssignedUser,//指定办理人(业务需求)
+            Items = new List<FlowStepHandler> { handler }//handlers //new List<Kv> { new(prevStep.HandlerId, prevStep.HandlerName) },
         };
     }
 
@@ -892,7 +964,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         EBusinessType currentBusinessType, CancellationToken cancellationToken)
     {
         int orgLevel;
-        List<Kv> items;
+        List<FlowStepHandler> items;
         string upperOrgId;
         EBusinessType businessType;
         EFlowDirection? flowDirection = null;
@@ -910,7 +982,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
                     items = await _organizeRepository.Queryable()
                         .Where(d => d.IsCenter)
-                        .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                        .Select(d => new FlowStepHandler
+                        {
+                            Key = d.Id,
+                            Value = d.Name,
+                            OrgId = d.Id,
+                            OrgName = d.Name
+                        })
                         .ToListAsync(cancellationToken);
                 }
                 else
@@ -921,7 +999,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
                     items = await _organizeRepository.Queryable()
                         .Where(d => d.Id == upperOrgId)
-                        .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                        .Select(d => new FlowStepHandler
+                        {
+                            Key = d.Id,
+                            Value = d.Name,
+                            OrgId = d.Id,
+                            OrgName = d.Name
+                        })
                         .ToListAsync(cancellationToken);
                 }
 
@@ -938,7 +1022,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 upperOrgId = _sessionContext.RequiredOrgId.GetHigherOrgId(orgLevel);
                 items = await _organizeRepository.Queryable()
                     .Where(d => d.Id == upperOrgId)
-                    .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                    .Select(d => new FlowStepHandler
+                    {
+                        Key = d.Id,
+                        Value = d.Name,
+                        OrgId = d.Id,
+                        OrgName = d.Name
+                    })
                     .ToListAsync(cancellationToken);
                 break;
             case EDynamicPolicy.OrgDownCenterTop:
@@ -948,7 +1038,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     orgLevel = 1;
                     items = await _organizeRepository.Queryable()
                         .Where(d => !d.IsCenter && d.Level == orgLevel)
-                        .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                        .Select(d => new FlowStepHandler
+                        {
+                            Key = d.Id,
+                            Value = d.Name,
+                            OrgId = d.Id,
+                            OrgName = d.Name
+                        })
                         .ToListAsync(cancellationToken);
                 }
                 else
@@ -957,7 +1053,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     items = await _organizeRepository.Queryable()
                         .Where(d => !d.IsCenter && d.Level == orgLevel &&
                                     d.Id.StartsWith(_sessionContext.RequiredOrgId))
-                        .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                        .Select(d => new FlowStepHandler
+                        {
+                            Key = d.Id,
+                            Value = d.Name,
+                            OrgId = d.Id,
+                            OrgName = d.Name
+                        })
                         .ToListAsync(cancellationToken);
                 }
 
@@ -967,7 +1069,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 orgLevel = _sessionContext.OrgLevel + 1;
                 items = await _organizeRepository.Queryable()
                     .Where(d => d.Level == orgLevel && d.Id.StartsWith(_sessionContext.RequiredOrgId))
-                    .Select(d => new Kv { Key = d.Id, Value = d.Name })
+                    .Select(d => new FlowStepHandler
+                    {
+                        Key = d.Id,
+                        Value = d.Name,
+                        OrgId = d.Id,
+                        OrgName = d.Name
+                    })
                     .ToListAsync(cancellationToken);
                 break;
             default:
@@ -995,7 +1103,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (nextStepDefine.StepType is EStepType.End) return new();
 
         var isStartCountersign = dto.IsStartCountersign;
-        var handlers = dto.NextHandlers;
+        var handlers = dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList();
 
         if (isStartCountersign)
         {
@@ -1103,13 +1211,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             case EHandlerType.Role:
                 if (!handlers.Any())
                 {
-                    var roles = await _roleRepository.Queryable()
-                        .Includes(d => d.Accounts, x => x.User)
-                        .Where(d => nextStepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
-                        .ToListAsync(cancellationToken);
-                    handlers = roles.SelectMany(d => d.Accounts).Distinct()
-                        .Select(d => new Kv(d.Id, d.User.Name))
-                        .ToList();
+                    //var roles = await _roleRepository.Queryable()
+                    //    .Includes(d => d.Accounts, x => x.User)
+                    //    .Where(d => nextStepDefine.HandlerTypeItems.Select(x => x.Key).Contains(d.Name))
+                    //    .ToListAsync(cancellationToken);
+                    //handlers = roles.SelectMany(d => d.Accounts).Distinct()
+                    //    .Select(d => new Kv(d.Id, d.User.Name))
+                    //    .ToList();
+                    handlers = nextStepDefine.HandlerTypeItems;
+                    return FlowAssignInfo.Create(EFlowAssignType.Role, handlers, isStartCountersign);
                 }
 
                 return FlowAssignInfo.Create(EFlowAssignType.User, handlers, isStartCountersign);
@@ -1195,9 +1305,9 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
             cancellationToken: cancellationToken);
-        var step = workflow.Steps.FirstOrDefault(d => 
+        var step = workflow.Steps.FirstOrDefault(d =>
             d.StepHandlers.Any(d => d.OrgId == "001171" || d.OrgId == "001178"));
-        if(step is not null)
+        if (step is not null)
         {
             step.FileJson = await _fileRepository.AddFileAsync(files, workflow.ExternalId, step.Id, cancellationToken);
             var trace = workflow.Traces.First(d => d.StepId == step.Id);

+ 11 - 1
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -4,6 +4,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Orders;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
@@ -11,6 +12,7 @@ using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
+using Hotline.Share.Requests;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Entities;
@@ -65,5 +67,13 @@ namespace Hotline.Application.Orders
         ISugarQueryable<Order> QueryOrders(QueryOrderDto dto);
 
         #endregion
-    }
+
+        /// <summary>
+        /// 未签收统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<Order, WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto);
+
+	}
 }

+ 39 - 10
src/Hotline.Application/Orders/OrderApplication.cs

@@ -17,6 +17,7 @@ using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Quality;
 using Hotline.Share.Enums.Settings;
+using Hotline.Share.Requests;
 using Hotline.Tools;
 using MapsterMapper;
 using SqlSugar;
@@ -171,7 +172,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
         stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
         DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
-        var (total, items) = await _orderRepository.Queryable(viewFilter: true)
+        var (total, items) = await _orderRepository.Queryable(canView: true)
             .WhereIF(dto.IsProvince.HasValue, x => x.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Title.Contains(dto.Keyword!) || x.No.Contains(dto.Keyword!))
             .Where(x => x.ExpiredTime != null &&
@@ -217,7 +218,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     public async Task<PagedDto<OrderDto>> GetToExpireAsync(AboutToExpireListDto dto, CancellationToken cancellationToken)
     {
         DateTime stTime = _timeLimitDomainService.WorkDay(DateTime.Now);
-        var (total, items) = await _orderRepository.Queryable(viewFilter: true)
+        var (total, items) = await _orderRepository.Queryable(canView: true)
             .WhereIF(dto.IsProvince.HasValue, x => x.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Title.Contains(dto.Keyword!) || x.No.Contains(dto.Keyword!))
             //.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No == dto.No)
@@ -305,8 +306,15 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 return ReceiveOrderFromProvinceAsync(dto, dto.Files, current, cancellationToken);
             case ESource.Police110:
             case ESource.CityDataExchangeLz:
-            case ESource.ConvergenceMedia:
+            case ESource.CityDataExchangeYB:
+            case ESource.CityDataExchangeZG:
+            case ESource.CityDataExchangeNJ:
             case ESource.WebPortal:
+            case ESource.ConvergenceMedia:
+            case ESource.IYIBIN:
+            case ESource.ZHYB:
+            case ESource.ZZPT:
+            case ESource.WLLZ:
                 return ReceiveOrderFromOtherPlatformAsync(dto, dto.Files, current, cancellationToken);
             case ESource.Hotline:
             case ESource.HotlineImport:
@@ -399,7 +407,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     {
         var isCenter = _sessionContext.OrgIsCenter;
 
-        return _orderRepository.Queryable(viewFilter: isCenter ? false : true)
+        return _orderRepository.Queryable(canView: isCenter ? false : true)
             .Includes(x => x.OrderScreens)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
             .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
@@ -440,16 +448,37 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .OrderByDescending(d => d.CreationTime);
     }
 
-
-    #region private
-
     /// <summary>
-    /// 接受外部工单(除省平台)
+    /// 未签收统计
     /// </summary>
     /// <param name="dto"></param>
-    /// <param name="cancellationToken"></param>
     /// <returns></returns>
-    private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
+    public ISugarQueryable<Order,WorkflowStep> QueryUnsignedOrders(QueryUnsignedOrdersRequest dto) {
+		if (dto.EndTime.HasValue)
+			dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+		var IsCenter = _sessionContext.OrgIsCenter;
+		return _orderRepository.Queryable()
+            .LeftJoin<WorkflowStep>((x,ws)=>x.Id == ws.ExternalId)
+            .WhereIF(dto.StartTime.HasValue, (x,ws) => ws.CreationTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, (x, ws) => ws.CreationTime <= dto.EndTime)
+            .WhereIF(dto.Level == 0 && IsCenter == false, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
+			.WhereIF(dto.Level == 1,(x,ws)=> ws.AcceptorOrgId == _sessionContext.OrgId)
+            .WhereIF(dto.Level == 2, (x, ws) => ws.AcceptorOrgId.StartsWith(_sessionContext.OrgId))
+            .WhereIF(dto.Signed == 0 ,(x,ws)=>ws.Status == Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
+            .WhereIF(dto.Signed == 1, (x, ws) => ws.Status != Share.Enums.FlowEngine.EWorkflowStepStatus.WaitForAccept)
+			.OrderByDescending((x,ws) => ws.CreationTime);
+	}
+
+
+	#region private
+
+	/// <summary>
+	/// 接受外部工单(除省平台)
+	/// </summary>
+	/// <param name="dto"></param>
+	/// <param name="cancellationToken"></param>
+	/// <returns></returns>
+	private async Task<AddOrderResponse> ReceiveOrderFromOtherPlatformAsync(AddOrderDto dto, List<FileDto> files,
         ISessionContext current, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(dto.ExternalId))

+ 385 - 381
src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs

@@ -26,406 +26,410 @@ using Hotline.Share.Enums.FlowEngine;
 
 namespace Hotline.Application.Orders
 {
-	public class OrderSecondaryHandlingApplication : IOrderSecondaryHandlingApplication, IScopeDependency
-	{
-		private readonly IMapper _mapper;
-		private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
-		private readonly IFileRepository _fileRepository;
-		private readonly IRepository<OrderVisit> _orderVisitRepository;
-		private readonly ISessionContext _sessionContext;
-		private readonly IOrderRepository _orderRepository;
-		private readonly ITimeLimitDomainService _timeLimitDomainService;
-		private readonly ICapPublisher _capPublisher;
-		private readonly IWorkflowApplication _workflowApplication;
-		private readonly IRepository<OrderPublish> _orderPublishRepository;
-		private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
-		private readonly IWorkflowDomainService _workflowDomainService;
-		private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
+    public class OrderSecondaryHandlingApplication : IOrderSecondaryHandlingApplication, IScopeDependency
+    {
+        private readonly IMapper _mapper;
+        private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
+        private readonly IFileRepository _fileRepository;
+        private readonly IRepository<OrderVisit> _orderVisitRepository;
+        private readonly ISessionContext _sessionContext;
+        private readonly IOrderRepository _orderRepository;
+        private readonly ITimeLimitDomainService _timeLimitDomainService;
+        private readonly ICapPublisher _capPublisher;
+        private readonly IWorkflowApplication _workflowApplication;
+        private readonly IRepository<OrderPublish> _orderPublishRepository;
+        private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
+        private readonly IWorkflowDomainService _workflowDomainService;
+        private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
 
-		public OrderSecondaryHandlingApplication(
-			IMapper mapper,
-			IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository,
-			IFileRepository fileRepository,
-			IRepository<OrderVisit> orderVisitRepository,
-			ISessionContext sessionContext,
-			IOrderRepository orderRepository,
-			ITimeLimitDomainService timeLimitDomainService,
-			ICapPublisher capPublisher,
-			IWorkflowApplication workflowApplication,
-			IRepository<OrderPublish> orderPublishRepository,
-			IRepository<OrderPublishHistory> orderPublishHistoryRepository,
-			IWorkflowDomainService workflowDomainService,
-			IRepository<OrderVisitDetail> orderVisitedDetailRepository
-			) {
-			_mapper = mapper;
-			_orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
-			_fileRepository = fileRepository;
-			_orderVisitRepository = orderVisitRepository;
-			_sessionContext = sessionContext;
-			_orderRepository = orderRepository;
-			_timeLimitDomainService = timeLimitDomainService;
-			_capPublisher = capPublisher;
-			_workflowApplication = workflowApplication;
-			_orderPublishRepository = orderPublishRepository;
-			_orderPublishHistoryRepository = orderPublishHistoryRepository;
-			_workflowDomainService = workflowDomainService;
-			_orderVisitedDetailRepository = orderVisitedDetailRepository;
-		}
+        public OrderSecondaryHandlingApplication(
+            IMapper mapper,
+            IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository,
+            IFileRepository fileRepository,
+            IRepository<OrderVisit> orderVisitRepository,
+            ISessionContext sessionContext,
+            IOrderRepository orderRepository,
+            ITimeLimitDomainService timeLimitDomainService,
+            ICapPublisher capPublisher,
+            IWorkflowApplication workflowApplication,
+            IRepository<OrderPublish> orderPublishRepository,
+            IRepository<OrderPublishHistory> orderPublishHistoryRepository,
+            IWorkflowDomainService workflowDomainService,
+            IRepository<OrderVisitDetail> orderVisitedDetailRepository
+            )
+        {
+            _mapper = mapper;
+            _orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
+            _fileRepository = fileRepository;
+            _orderVisitRepository = orderVisitRepository;
+            _sessionContext = sessionContext;
+            _orderRepository = orderRepository;
+            _timeLimitDomainService = timeLimitDomainService;
+            _capPublisher = capPublisher;
+            _workflowApplication = workflowApplication;
+            _orderPublishRepository = orderPublishRepository;
+            _orderPublishHistoryRepository = orderPublishHistoryRepository;
+            _workflowDomainService = workflowDomainService;
+            _orderVisitedDetailRepository = orderVisitedDetailRepository;
+        }
 
-		/// <summary>
-		///  二次办理新增
-		/// </summary>
-		/// <returns></returns>
-		public async Task AddAsync(AddOrderSecondaryHandlingDto dto, CancellationToken cancellationToken)
-		{
-			var model = _mapper.Map<OrderSecondaryHandling>(dto);
-			if (string.IsNullOrEmpty(dto.Id))
-			{
-				model.InitId();
-			}
-			else {
-				model = await _orderSecondaryHandlingRepository.GetAsync(dto.Id , cancellationToken);
-				model.Content = dto.Content;
-			}
-			model.State = ESecondaryHandlingState.Apply;
-			model.ApplyOrgId = _sessionContext.OrgId;
-			model.ApplyOrgName = _sessionContext.OrgName;
-		
-			if (dto.Files.Any())
-				model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", cancellationToken);
+        /// <summary>
+        ///  二次办理新增
+        /// </summary>
+        /// <returns></returns>
+        public async Task AddAsync(AddOrderSecondaryHandlingDto dto, CancellationToken cancellationToken)
+        {
+            var model = _mapper.Map<OrderSecondaryHandling>(dto);
+            if (string.IsNullOrEmpty(dto.Id))
+            {
+                model.InitId();
+            }
+            else
+            {
+                model = await _orderSecondaryHandlingRepository.GetAsync(dto.Id, cancellationToken);
+                model.Content = dto.Content;
+            }
+            model.State = ESecondaryHandlingState.Apply;
+            model.ApplyOrgId = _sessionContext.OrgId;
+            model.ApplyOrgName = _sessionContext.OrgName;
 
-			var visit = await _orderVisitRepository.GetAsync(x => x.Id  == dto.VisitId && x.VisitState != EVisitState.None, cancellationToken);
-			if (visit != null)
-			{
-				model.VisitState = visit.VisitState;
-				visit.VisitState = EVisitState.None;
-				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
-			}
+            if (dto.Files.Any())
+                model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", cancellationToken);
 
-			if (!string.IsNullOrEmpty(dto.Id))
-			{
-				await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
-			}
-			else {
-				await _orderSecondaryHandlingRepository.AddAsync(model, cancellationToken);
-			}
-		}
+            var visit = await _orderVisitRepository.GetAsync(x => x.Id == dto.VisitId && x.VisitState != EVisitState.None, cancellationToken);
+            if (visit != null)
+            {
+                model.VisitState = visit.VisitState;
+                visit.VisitState = EVisitState.None;
+                await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+            }
 
-		public async Task SendBackAsync(SendBackOrderSecondaryHandlingDto dto, CancellationToken cancellationToken) 
-		{
-			var model =await _orderSecondaryHandlingRepository.GetAsync(dto.Id, cancellationToken);
-			model.State = ESecondaryHandlingState.NotApply;
-			model.SendBackContent = dto.SendBackContent;
-			model.AuditUser = _sessionContext.UserName;
-			model.AuditTime = DateTime.Now;
-			model.SendBackNum = model.SendBackNum is null ? 1 : model.SendBackNum + 1;
-			await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
-			var visit = await _orderVisitRepository.GetAsync(x => x.Id == model.VisitId , cancellationToken);
-			if (visit != null)
-			{
-				visit.VisitState = model.VisitState;
-				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
-			}
-		}
+            if (!string.IsNullOrEmpty(dto.Id))
+            {
+                await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+            }
+            else
+            {
+                await _orderSecondaryHandlingRepository.AddAsync(model, cancellationToken);
+            }
+        }
 
+        public async Task SendBackAsync(SendBackOrderSecondaryHandlingDto dto, CancellationToken cancellationToken)
+        {
+            var model = await _orderSecondaryHandlingRepository.GetAsync(dto.Id, cancellationToken);
+            model.State = ESecondaryHandlingState.NotApply;
+            model.SendBackContent = dto.SendBackContent;
+            model.AuditUser = _sessionContext.UserName;
+            model.AuditTime = DateTime.Now;
+            model.SendBackNum = model.SendBackNum is null ? 1 : model.SendBackNum + 1;
+            await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+            var visit = await _orderVisitRepository.GetAsync(x => x.Id == model.VisitId, cancellationToken);
+            if (visit != null)
+            {
+                visit.VisitState = model.VisitState;
+                await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+            }
+        }
 
-		/// <summary>
-		/// 二次办理审批
-		/// </summary>
-		/// <returns></returns>
-		public async Task AuditAsync(AuditOrderSecondaryHandlingDto dto, OrderSecondaryHandling model, CancellationToken cancellationToken)
-		{
-			model.State = dto.State;
-			model.AuditContent = dto.AuditContent;
-			model.AuditId = _sessionContext.UserId;
-			model.AuditUser = _sessionContext.UserName;
-			model.AuditTime = DateTime.Now;
-			if (model.State == ESecondaryHandlingState.End)
-			{
-				var order = await _orderRepository.GetAsync(x => x.Id == model.OrderId, cancellationToken);
-				if (string.IsNullOrEmpty(order.WorkflowId))
-					throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程信息!");
-				var step = await _workflowDomainService.FindLastHandleStepAsync(order.WorkflowId, model.ApplyOrgId, cancellationToken);
-				if (step == null)
-					throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程节点!");
-				var recall = new RecallDto
-				{
-					WorkflowId = order.WorkflowId!,
-					NextStepCode = step.Code,
-					NextStepName = step.Name,
-					NextHandlers = step.Handlers,
-					Opinion = dto.AuditContent,
-					FlowDirection = Share.Enums.FlowEngine.EFlowDirection.CenterToOrg,
-					HandlerType = step.HandlerType,
-					BusinessType = step.BusinessType
-				};
-				var reTransactNum = order.ReTransactNum is null ? 1 : order.ReTransactNum + 1;
-				var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-				var processType = step.FlowDirection == EFlowDirection.OrgToCenter || step.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-				await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ReTransactNum = reTransactNum, ProcessType = processType })
-					.Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
-				var orderDto = _mapper.Map<OrderDto>(order);
-				await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: cancellationToken);
 
-				await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, cancellationToken);
-				var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == model.OrderId);
-				if (publish != null)
-				{
-					var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
-					publishHistory.OrderPublishId = publish.Id;
-					publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
-					publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
-					publishHistory.ArrangeContentAfter = publish.ArrangeContent;
-					publishHistory.ArrangeContentBefor = publish.ArrangeContent;
-					publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
-					publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
-					await _orderPublishHistoryRepository.AddAsync(publishHistory, cancellationToken);
-					await _orderPublishRepository.RemoveAsync(publish, false, cancellationToken);
-				}
-			}
-			else {
-				var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == model.OrderId, cancellationToken);
-				visit.VisitState = model.VisitState;
-				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
-			}
-			await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
-		}
+        /// <summary>
+        /// 二次办理审批
+        /// </summary>
+        /// <returns></returns>
+        public async Task AuditAsync(AuditOrderSecondaryHandlingDto dto, OrderSecondaryHandling model, CancellationToken cancellationToken)
+        {
+            model.State = dto.State;
+            model.AuditContent = dto.AuditContent;
+            model.AuditId = _sessionContext.UserId;
+            model.AuditUser = _sessionContext.UserName;
+            model.AuditTime = DateTime.Now;
+            if (model.State == ESecondaryHandlingState.End)
+            {
+                var order = await _orderRepository.GetAsync(x => x.Id == model.OrderId, cancellationToken);
+                if (string.IsNullOrEmpty(order.WorkflowId))
+                    throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程信息!");
+                var step = await _workflowDomainService.FindLastHandleStepAsync(order.WorkflowId, model.ApplyOrgId, cancellationToken);
+                if (step == null)
+                    throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程节点!");
+                var recall = new RecallDto
+                {
+                    WorkflowId = order.WorkflowId!,
+                    NextStepCode = step.Code,
+                    NextStepName = step.Name,
+                    NextHandlers = new List<FlowStepHandler> { step.GetWorkflowStepHandler() },
+                    Opinion = dto.AuditContent,
+                    FlowDirection = Share.Enums.FlowEngine.EFlowDirection.CenterToOrg,
+                    HandlerType = step.HandlerType,
+                    BusinessType = step.BusinessType
+                };
+                var reTransactNum = order.ReTransactNum is null ? 1 : order.ReTransactNum + 1;
+                var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+                var processType = step.FlowDirection == EFlowDirection.OrgToCenter || step.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
+                await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, ReTransactNum = reTransactNum, ProcessType = processType })
+                    .Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
+                var orderDto = _mapper.Map<OrderDto>(order);
+                await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: cancellationToken);
 
+                await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, cancellationToken);
+                var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == model.OrderId);
+                if (publish != null)
+                {
+                    var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
+                    publishHistory.OrderPublishId = publish.Id;
+                    publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
+                    publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
+                    publishHistory.ArrangeContentAfter = publish.ArrangeContent;
+                    publishHistory.ArrangeContentBefor = publish.ArrangeContent;
+                    publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
+                    publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
+                    await _orderPublishHistoryRepository.AddAsync(publishHistory, cancellationToken);
+                    await _orderPublishRepository.RemoveAsync(publish, false, cancellationToken);
+                }
+            }
+            else
+            {
+                var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == model.OrderId, cancellationToken);
+                visit.VisitState = model.VisitState;
+                await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+            }
+            await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+        }
 
-		/// <summary>
-		/// 获取申请列表
-		/// </summary>
-		/// <returns></returns>
-		public ISugarQueryable<OrderVisitDetail> ApplyQuery(MayScreenListDto dto, CancellationToken cancellationToken)
-		{
-			dto.CreationTimeEnd = DateTime.Now;
-			//dto.CreationTimeStart = DateTime.Now;
-			dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
 
-			var query = _orderVisitedDetailRepository.Queryable(false, true)
-				.Includes(x => x.OrderVisit)
-				.Includes(x => x.OrderVisit, y => y.Order)
-				.Includes(x => x.OrderVisit, y => y.Employee)
-				.Includes(x => x.SecondaryHandling)
-				.LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && s.Status < EScreenStatus.End && s.IsDeleted == false)
-				.Where((x, s) => s.Id == null && (x.SecondaryHandling.State == ESecondaryHandlingState.NotApply || x.SecondaryHandling.Id == null))
-				.Where(x => x.OrderVisit.VisitTime < dto.CreationTimeEnd && x.OrderVisit.VisitTime > dto.CreationTimeStart)
-				.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order!.No!.Contains(dto.No!))
-				.WhereIF(dto.IsProvince.HasValue, x => x.OrderVisit.Order!.IsProvince == dto.IsProvince)
-				.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order!.Title!.Contains(dto.Title!))
-				.WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), x => x.OrderVisit.Order!.SourceChannelCode! == dto.SourceChannel!)
-				.WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.OrderVisit.Order!.AcceptTypeCode! == dto.AcceptType!)
-				.WhereIF(dto.CounterSignType.HasValue, x => x.OrderVisit.Order!.CounterSignType == dto.CounterSignType)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), x => x.OrderVisit.Order!.OrgLevelOneName!.Contains(dto.OrgLevelOneName!))
-				.WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.OrderVisit.Order!.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
-				.WhereIF(dto.ActualHandleTime.HasValue && dto.EndActualHandleTime.HasValue, x => x.OrderVisit.Order!.ActualHandleTime >= dto.ActualHandleTime && x.OrderVisit.Order!.ActualHandleTime <= dto.EndActualHandleTime)
-				.WhereIF(dto.FiledTime.HasValue && dto.EndFiledTime.HasValue, x => x.OrderVisit.Order!.FiledTime == dto.FiledTime && x.OrderVisit.Order!.FiledTime <= dto.EndFiledTime)
-				.WhereIF(dto.CreationTime.HasValue && dto.EndCreationTime.HasValue, x => x.OrderVisit.Order!.CreationTime == dto.CreationTime && x.OrderVisit.Order!.CreationTime <= dto.EndCreationTime)
-				.WhereIF(dto.VisitTime.HasValue && dto.EndVisitTime.HasValue, x => x.OrderVisit.VisitTime == dto.VisitTime && x.OrderVisit.VisitTime <= dto.EndVisitTime)
-				.WhereIF(!string.IsNullOrEmpty(dto.VisitOrgName), x => x.VisitOrgName!.Contains(dto.VisitOrgName!))
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgProcessingResults), x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.OrgProcessingResults)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgHandledAttitude), x => SqlFunc.JsonListObjectAny(x.OrgHandledAttitude, "Key", dto.OrgHandledAttitude))
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason), x => SqlFunc.JsonField(x.OrgNoSatisfiedReason, "Key") == dto.OrgNoSatisfiedReason)
-				.Where((x, s) => x.OrderVisit.VisitState != EVisitState.None && x.OrderVisit.IsCanHandle)
-				.Where((x, s) => x.OrderVisit.Order.CounterSignType == null && x.OrderVisit.Order.ActualHandleOrgCode == _sessionContext.OrgId)
-				;
-			if (_sessionContext.OrgId != null && !_sessionContext.OrgIsCenter)
-			{
-				query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-						(x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
-								  x.OrderVisit.Order.No.Contains(dto.Keyword!))
-					.Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode.StartsWith(_sessionContext.OrgId) && (
-						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
-						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2"
-						|| SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
-						SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
-					));
-			}
-			else
-			{
-				query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-						(x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
-								  x.OrderVisit.Order.No.Contains(dto.Keyword!))
-					.Where((x, s) => 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"
-					));
-			}
+        /// <summary>
+        /// 获取申请列表
+        /// </summary>
+        /// <returns></returns>
+        public ISugarQueryable<OrderVisitDetail> ApplyQuery(MayScreenListDto dto, CancellationToken cancellationToken)
+        {
+            dto.CreationTimeEnd = DateTime.Now;
+            //dto.CreationTimeStart = DateTime.Now;
+            dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
 
-			return query.OrderByDescending((x, s) => x.CreationTime);
-		}
+            var query = _orderVisitedDetailRepository.Queryable(false, true)
+                .Includes(x => x.OrderVisit)
+                .Includes(x => x.OrderVisit, y => y.Order)
+                .Includes(x => x.OrderVisit, y => y.Employee)
+                .Includes(x => x.SecondaryHandling)
+                .LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && s.Status < EScreenStatus.End && s.IsDeleted == false)
+                .Where((x, s) => s.Id == null && (x.SecondaryHandling.State == ESecondaryHandlingState.NotApply || x.SecondaryHandling.Id == null))
+                .Where(x => x.OrderVisit.VisitTime < dto.CreationTimeEnd && x.OrderVisit.VisitTime > dto.CreationTimeStart)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order!.No!.Contains(dto.No!))
+                .WhereIF(dto.IsProvince.HasValue, x => x.OrderVisit.Order!.IsProvince == dto.IsProvince)
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order!.Title!.Contains(dto.Title!))
+                .WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), x => x.OrderVisit.Order!.SourceChannelCode! == dto.SourceChannel!)
+                .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.OrderVisit.Order!.AcceptTypeCode! == dto.AcceptType!)
+                .WhereIF(dto.CounterSignType.HasValue, x => x.OrderVisit.Order!.CounterSignType == dto.CounterSignType)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), x => x.OrderVisit.Order!.OrgLevelOneName!.Contains(dto.OrgLevelOneName!))
+                .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.OrderVisit.Order!.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
+                .WhereIF(dto.ActualHandleTime.HasValue && dto.EndActualHandleTime.HasValue, x => x.OrderVisit.Order!.ActualHandleTime >= dto.ActualHandleTime && x.OrderVisit.Order!.ActualHandleTime <= dto.EndActualHandleTime)
+                .WhereIF(dto.FiledTime.HasValue && dto.EndFiledTime.HasValue, x => x.OrderVisit.Order!.FiledTime == dto.FiledTime && x.OrderVisit.Order!.FiledTime <= dto.EndFiledTime)
+                .WhereIF(dto.CreationTime.HasValue && dto.EndCreationTime.HasValue, x => x.OrderVisit.Order!.CreationTime == dto.CreationTime && x.OrderVisit.Order!.CreationTime <= dto.EndCreationTime)
+                .WhereIF(dto.VisitTime.HasValue && dto.EndVisitTime.HasValue, x => x.OrderVisit.VisitTime == dto.VisitTime && x.OrderVisit.VisitTime <= dto.EndVisitTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.VisitOrgName), x => x.VisitOrgName!.Contains(dto.VisitOrgName!))
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgProcessingResults), x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.OrgProcessingResults)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgHandledAttitude), x => SqlFunc.JsonListObjectAny(x.OrgHandledAttitude, "Key", dto.OrgHandledAttitude))
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason), x => SqlFunc.JsonField(x.OrgNoSatisfiedReason, "Key") == dto.OrgNoSatisfiedReason)
+                .Where((x, s) => x.OrderVisit.VisitState != EVisitState.None && x.OrderVisit.IsCanHandle)
+                .Where((x, s) => x.OrderVisit.Order.CounterSignType == null && x.OrderVisit.Order.ActualHandleOrgCode == _sessionContext.OrgId)
+                ;
+            if (_sessionContext.OrgId != null && !_sessionContext.OrgIsCenter)
+            {
+                query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                        (x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
+                                  x.OrderVisit.Order.No.Contains(dto.Keyword!))
+                    .Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode.StartsWith(_sessionContext.OrgId) && (
+                        SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
+                        SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2"
+                        || SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
+                        SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
+                    ));
+            }
+            else
+            {
+                query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                        (x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
+                                  x.OrderVisit.Order.No.Contains(dto.Keyword!))
+                    .Where((x, s) => 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"
+                    ));
+            }
 
-		/// <summary>
-		/// 二次办理列表查询
-		/// </summary>
-		/// <returns></returns>
-		public ISugarQueryable<OrderSecondaryHandling> Query(SecondaryHandlingListDto dto, CancellationToken cancellationToken)
-		{
-			if (dto.CreationTimeEnd.HasValue)
-				dto.CreationTimeEnd = dto.CreationTimeEnd.Value.AddDays(1).AddSeconds(-1);
-			return _orderSecondaryHandlingRepository.Queryable()
-				.Includes(x => x.Order)
-				.Includes(x => x.VisitDetail)
-				.Includes(x => x.Visit, d => d.Order)
-				.Where(x=>x.State> ESecondaryHandlingState.NotApply)
-				.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-					x => x.Visit.Order.Title.Contains(dto.Keyword!) || x.Visit.Order.No.Contains(dto.Keyword!))
-				.WhereIF(dto.Status is ESecondaryHandlingState.Apply, x => x.State == ESecondaryHandlingState.Apply)
-				.WhereIF(dto.Status is ESecondaryHandlingState.Handled, x => x.State != ESecondaryHandlingState.Apply)
-				.WhereIF(dto.Status is ESecondaryHandlingState.End, x => x.State == ESecondaryHandlingState.End)
-				.WhereIF(dto.Status is ESecondaryHandlingState.Refuse, x => x.State == ESecondaryHandlingState.Refuse)
-				.WhereIF(dto.CreationTimeStart.HasValue, x => x.CreationTime >= dto.CreationTimeStart)
-				.WhereIF(dto.CreationTimeEnd.HasValue, x => x.CreationTime <= dto.CreationTimeEnd)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrderId), x => x.OrderId == dto.OrderId)
-				.OrderByDescending(x => x.CreationTime);
-		}
+            return query.OrderByDescending((x, s) => x.CreationTime);
+        }
 
-		/// <summary>
-		/// 获取实体
-		/// </summary>
-		/// <returns></returns>
-		public async Task<OrderSecondaryHandling> Entity(string id, CancellationToken cancellationToken)
-		{
-			return await _orderSecondaryHandlingRepository.Queryable()
-				.FirstAsync(x => x.Id == id, cancellationToken);
-		}
+        /// <summary>
+        /// 二次办理列表查询
+        /// </summary>
+        /// <returns></returns>
+        public ISugarQueryable<OrderSecondaryHandling> Query(SecondaryHandlingListDto dto, CancellationToken cancellationToken)
+        {
+            if (dto.CreationTimeEnd.HasValue)
+                dto.CreationTimeEnd = dto.CreationTimeEnd.Value.AddDays(1).AddSeconds(-1);
+            return _orderSecondaryHandlingRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.VisitDetail)
+                .Includes(x => x.Visit, d => d.Order)
+                .Where(x => x.State > ESecondaryHandlingState.NotApply)
+                .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                    x => x.Visit.Order.Title.Contains(dto.Keyword!) || x.Visit.Order.No.Contains(dto.Keyword!))
+                .WhereIF(dto.Status is ESecondaryHandlingState.Apply, x => x.State == ESecondaryHandlingState.Apply)
+                .WhereIF(dto.Status is ESecondaryHandlingState.Handled, x => x.State != ESecondaryHandlingState.Apply)
+                .WhereIF(dto.Status is ESecondaryHandlingState.End, x => x.State == ESecondaryHandlingState.End)
+                .WhereIF(dto.Status is ESecondaryHandlingState.Refuse, x => x.State == ESecondaryHandlingState.Refuse)
+                .WhereIF(dto.CreationTimeStart.HasValue, x => x.CreationTime >= dto.CreationTimeStart)
+                .WhereIF(dto.CreationTimeEnd.HasValue, x => x.CreationTime <= dto.CreationTimeEnd)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrderId), x => x.OrderId == dto.OrderId)
+                .OrderByDescending(x => x.CreationTime);
+        }
 
-		/// <summary>
-		/// 二次办理统计
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		public  ISugarQueryable<SecondaryHandlingVo> SecondaryHandlingReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
-		{
-			if (dto.EndTime.HasValue)
-				dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-			return _orderSecondaryHandlingRepository.Queryable()
-				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
-				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
-				.Where(x => x.State == ESecondaryHandlingState.End)
-				.GroupBy(x => new { x.ApplyOrgId, x.ApplyOrgName })
-				.Select(x => new SecondaryHandlingVo
-				{
-					OrgId = x.ApplyOrgId,
-					OrgName = x.ApplyOrgName,
-					Num = SqlFunc.AggregateCount(x.Id)
-				})
-				.OrderByIF(dto.SortRule == 0, x => x.Num, OrderByType.Asc)
-				.OrderByIF(dto.SortRule == 1, x => x.Num, OrderByType.Desc);
-		}
+        /// <summary>
+        /// 获取实体
+        /// </summary>
+        /// <returns></returns>
+        public async Task<OrderSecondaryHandling> Entity(string id, CancellationToken cancellationToken)
+        {
+            return await _orderSecondaryHandlingRepository.Queryable()
+                .FirstAsync(x => x.Id == id, cancellationToken);
+        }
 
-		/// <summary>
-		/// 二次办理统计明细
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
-		{
-			if (dto.EndTime.HasValue)
-				dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-			return _orderSecondaryHandlingRepository.Queryable()
-				.Includes(x=>x.Order)
-				.Includes(x=>x.Visit)
-				.Includes(x=>x.VisitDetail)
-				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
-				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
-				.Where(x=>x.ApplyOrgId == dto.OrgId)
-				.Where(x => x.State == ESecondaryHandlingState.End);
-		}
+        /// <summary>
+        /// 二次办理统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<SecondaryHandlingVo> SecondaryHandlingReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+        {
+            if (dto.EndTime.HasValue)
+                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+            return _orderSecondaryHandlingRepository.Queryable()
+                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+                .Where(x => x.State == ESecondaryHandlingState.End)
+                .GroupBy(x => new { x.ApplyOrgId, x.ApplyOrgName })
+                .Select(x => new SecondaryHandlingVo
+                {
+                    OrgId = x.ApplyOrgId,
+                    OrgName = x.ApplyOrgName,
+                    Num = SqlFunc.AggregateCount(x.Id)
+                })
+                .OrderByIF(dto.SortRule == 0, x => x.Num, OrderByType.Asc)
+                .OrderByIF(dto.SortRule == 1, x => x.Num, OrderByType.Desc);
+        }
 
+        /// <summary>
+        /// 二次办理统计明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+        {
+            if (dto.EndTime.HasValue)
+                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+            return _orderSecondaryHandlingRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.Visit)
+                .Includes(x => x.VisitDetail)
+                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+                .Where(x => x.ApplyOrgId == dto.OrgId)
+                .Where(x => x.State == ESecondaryHandlingState.End);
+        }
 
-		/// <summary>
-		/// 二次办理满意度统计
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		public ISugarQueryable<SecondaryHandlingSatisfactionVo> SecondaryHandlingSatisfactionReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken) 
-		{
-			if (dto.EndTime.HasValue)
-				dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-			return _orderSecondaryHandlingRepository.Queryable()
-				.Includes(x => x.Order)
-				.Includes(x => x.Visit)
-				.Includes(x => x.VisitDetail)
-				.Includes(x => x.Order, o => o.CallRecord)
-				.LeftJoin<SystemOrganize>((x, o) => x.ApplyOrgId == o.Id)
-				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
-				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
-				.WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
-				.GroupBy((x,o) => new { x.ApplyOrgId, x.ApplyOrgName,o.OrgType })
-				.Select((x, o) => new SecondaryHandlingSatisfactionVo()
-				{
-					OrgId = x.ApplyOrgId,
-					OrgName = x.ApplyOrgName,
-					OrgType = o.OrgType,
-					TotalSumCount = SqlFunc.AggregateCount(x.Id),
-					VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
-					SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
-					RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
-					DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
-					NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
-					NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
-					NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
-				});
-		}
 
-		/// <summary>
-		///  二次办理满意度统计明细
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingSatisfactionDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
-		{
-			var key = string.Empty;
-			if (dto.EndTime.HasValue)
-				dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
-			if (!string.IsNullOrEmpty(dto.Header))
-			{
-				switch (dto.Header)
-				{
-					case "verySatisfiedCount":
-						key = "5";
-						break;
-					case "satisfiedCount":
-						key = "4";
-						break;
-					case "regardedAsSatisfiedCount":
-						key = "-1";
-						break;
-					case "defaultSatisfiedCount":
-						key = "0";
-						break;
-					case "noSatisfiedCount":
-						key = "2";
-						break;
-					case "noEvaluateCount":
-						key = "7";
-						break;
-					case "noPutThroughCount":
-						key = "6";
-						break;
-				}
-			}
+        /// <summary>
+        /// 二次办理满意度统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<SecondaryHandlingSatisfactionVo> SecondaryHandlingSatisfactionReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+        {
+            if (dto.EndTime.HasValue)
+                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+            return _orderSecondaryHandlingRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.Visit)
+                .Includes(x => x.VisitDetail)
+                .Includes(x => x.Order, o => o.CallRecord)
+                .LeftJoin<SystemOrganize>((x, o) => x.ApplyOrgId == o.Id)
+                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+                .WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
+                .GroupBy((x, o) => new { x.ApplyOrgId, x.ApplyOrgName, o.OrgType })
+                .Select((x, o) => new SecondaryHandlingSatisfactionVo()
+                {
+                    OrgId = x.ApplyOrgId,
+                    OrgName = x.ApplyOrgName,
+                    OrgType = o.OrgType,
+                    TotalSumCount = SqlFunc.AggregateCount(x.Id),
+                    VerySatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "5", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "5", 1, 0))),//非常满意数
+                    SatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "4", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "4", 1, 0))), //满意数
+                    RegardedAsSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "-1", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "-1", 1, 0))),//视为满意
+                    DefaultSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "0", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "0", 1, 0))),//默认满意
+                    NoSatisfiedCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "2", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "2", 1, 0))),//不满意
+                    NoEvaluateCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "7", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "7", 1, 0))),//未做评价
+                    NoPutThroughCount = SqlFunc.IIF(dto.TypeId == 1, SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == "6", 1, 0)), SqlFunc.AggregateSum(SqlFunc.IIF(SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == "6", 1, 0))),//未接通
+                });
+        }
 
-			return _orderSecondaryHandlingRepository.Queryable()
-				.Includes(x => x.Order)
-				.Includes(x => x.Visit)
-				.Includes(x => x.VisitDetail)
-				.Includes(x => x.Order, o => o.CallRecord)
-				.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
-				.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
-				.WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
-				.WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
-				.WhereIF(dto.TypeId is 1 && !string.IsNullOrEmpty(key), x=> SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == key)
-				.WhereIF(dto.TypeId is 2 && !string.IsNullOrEmpty(key), x => SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == key)
-				.Where(x => x.ApplyOrgId == dto.OrgId)
-				.Where(x => x.State == ESecondaryHandlingState.End);
-		}
+        /// <summary>
+        ///  二次办理满意度统计明细
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public ISugarQueryable<OrderSecondaryHandling> SecondaryHandlingSatisfactionDetailReport(QuerySecondaryHandlingRequest dto, CancellationToken cancellationToken)
+        {
+            var key = string.Empty;
+            if (dto.EndTime.HasValue)
+                dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+            if (!string.IsNullOrEmpty(dto.Header))
+            {
+                switch (dto.Header)
+                {
+                    case "verySatisfiedCount":
+                        key = "5";
+                        break;
+                    case "satisfiedCount":
+                        key = "4";
+                        break;
+                    case "regardedAsSatisfiedCount":
+                        key = "-1";
+                        break;
+                    case "defaultSatisfiedCount":
+                        key = "0";
+                        break;
+                    case "noSatisfiedCount":
+                        key = "2";
+                        break;
+                    case "noEvaluateCount":
+                        key = "7";
+                        break;
+                    case "noPutThroughCount":
+                        key = "6";
+                        break;
+                }
+            }
 
-	}
+            return _orderSecondaryHandlingRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.Visit)
+                .Includes(x => x.VisitDetail)
+                .Includes(x => x.Order, o => o.CallRecord)
+                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.OrgName), x => x.ApplyOrgName.Equals(dto.OrgName))
+                .WhereIF(!string.IsNullOrEmpty(dto.CDPN), x => x.Order.CallRecord.CDPN.Contains(dto.CDPN))
+                .WhereIF(dto.TypeId is 1 && !string.IsNullOrEmpty(key), x => SqlFunc.JsonField(x.VisitDetail.OrgProcessingResults, "Key") == key)
+                .WhereIF(dto.TypeId is 2 && !string.IsNullOrEmpty(key), x => SqlFunc.JsonField(x.VisitDetail.OrgHandledAttitude, "Key") == key)
+                .Where(x => x.ApplyOrgId == dto.OrgId)
+                .Where(x => x.State == ESecondaryHandlingState.End);
+        }
+
+    }
 }

+ 33 - 1
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -3,6 +3,7 @@ using Hotline.Application.FlowEngine;
 using Hotline.Application.Orders;
 using Hotline.Application.Quality;
 using Hotline.Authentications;
+using Hotline.Caching.Interfaces;
 using Hotline.File;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
@@ -22,6 +23,7 @@ using Hotline.Share.Enums.Quality;
 using Hotline.Share.Mq;
 using MapsterMapper;
 using StackExchange.Redis;
+using XF.Domain.Constants;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
@@ -57,6 +59,7 @@ namespace Hotline.Application.Subscribers
         private readonly IRepository<OrderComplement> _orderComplementRepository;
         private readonly ITimeLimitDomainService _timeLimitDomainService;
         private readonly IOrderApplication _orderApplication;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
         public DataSharingSubscriber(
             IRepository<OrderVisit> orderVisitRepository,
@@ -82,7 +85,8 @@ namespace Hotline.Application.Subscribers
             IRepository<Workflow> workflowRepository,
             IRepository<OrderComplement> orderComplementRepository,
             ITimeLimitDomainService timeLimitDomainService,
-            IOrderApplication orderApplication
+            IOrderApplication orderApplication,
+            ISystemSettingCacheManager systemSettingCacheManager
             )
         {
             _orderSendBackRepository = orderSendBackRepository;
@@ -108,6 +112,7 @@ namespace Hotline.Application.Subscribers
             _orderComplementRepository = orderComplementRepository;
             _timeLimitDomainService = timeLimitDomainService;
             _orderApplication = orderApplication;
+            _systemSettingCacheManager = systemSettingCacheManager;
         }
 
         /// <summary>
@@ -708,6 +713,7 @@ namespace Hotline.Application.Subscribers
                 data.IsSuccess = dto.IsSuccess;
                 data.SendTimes = dto.SendTimes;
                 data.Result = dto.Result;
+                data.NewCode = dto.NewCode;
                 await _transpondCityRawDataRepository.UpdateAsync(data, cancellationToken);
             }
         }
@@ -720,5 +726,31 @@ namespace Hotline.Application.Subscribers
         {
             await _transpondCityRawDataRepository.AddAsync(_mapper.Map<TranspondCityRawData>(dto), cancellationToken);
         }
+
+        /// <summary>
+        /// 接收市州互转办理结果
+        /// </summary>
+        [CapSubscribe(EventNames.SharingOrderReceiveHandleOpinionTranspondCity)]
+        public async Task RecTranspondCityReceiveResultAsync(TranspondCityOrderResultDto dto, CancellationToken cancellationToken)
+        {
+            var cityDataUndertakAdvice = _systemSettingCacheManager.GetSetting(SettingConstants.CityDataUndertakAdvice)?.SettingValue[0];
+            if (cityDataUndertakAdvice == "true")
+            {
+                var order = await _orderRepository.GetAsync(p => p.No == dto.No, cancellationToken);
+                if (order != null)
+                {
+                    order.ActualOpinion = dto.Opinion;
+                    await _orderRepository.UpdateAsync(order, cancellationToken);
+                    //后面还需要处理流程中的意见
+                }
+            }
+            //修改推送数据办理结果
+            var data = await _transpondCityRawDataRepository.GetAsync(p => p.OrderCode == dto.No && p.Direction == ETranspondDirection.Out, cancellationToken);
+            if (data != null)
+            {
+                data.ActualOpinion = dto.Opinion;
+                await _transpondCityRawDataRepository.UpdateAsync(data, cancellationToken);
+            }
+        }
     }
 }

+ 5 - 5
src/Hotline.Repository.SqlSugar/BaseRepositoryWorkflow.cs

@@ -17,7 +17,7 @@ public class BaseRepositoryWorkflow<TEntity> : BaseRepository<TEntity>, IReposit
         _dataPermissionFilterBuilder = dataPermissionFilterBuilder;
     }
 
-    public ISugarQueryable<TEntity> Queryable(bool permissionVerify = false, bool includeDeleted = false, bool viewFilter = true, bool? handlerFilter = null)
+    public ISugarQueryable<TEntity> Queryable(bool permissionVerify = false, bool includeDeleted = false, bool canView = true, bool? hasHandled = null)
     {
         if (includeDeleted)
             Db.QueryFilter.Clear();
@@ -26,13 +26,13 @@ public class BaseRepositoryWorkflow<TEntity> : BaseRepository<TEntity>, IReposit
         if (permissionVerify)
             query = query.DataPermissionFiltering(_dataPermissionFilterBuilder);
 
-        if (viewFilter)
+        if (canView)
             query = query.WorkflowViewFiltering(_dataPermissionFilterBuilder);
 
-        if (handlerFilter.HasValue)
-            query = query.WorkflowHandleFiltering(_dataPermissionFilterBuilder, handlerFilter.Value);
+        if (hasHandled.HasValue)
+            query = query.WorkflowHandleFiltering(_dataPermissionFilterBuilder, hasHandled.Value);
         
-        return query;
+        return query.Clone();
     }
 
     public async Task<string> AddAsync(TEntity entity, CancellationToken cancellationToken = default)

+ 15 - 15
src/Hotline.Repository.SqlSugar/DataPermissions/DataPermissionFilterBuilder.cs

@@ -11,27 +11,27 @@ namespace Hotline.Repository.SqlSugar.DataPermissions;
 
 public class DataPermissionFilterBuilder : IDataPermissionFilterBuilder, IScopeDependency
 {
-    private readonly ISessionContext _sessionContext;
 
     public DataPermissionFilterBuilder(ISessionContext sessionContext, IDataPermissionManager dataPermissionManager)
     {
         DataPermissionManager = dataPermissionManager;
-        _sessionContext = sessionContext;
+        SessionContext = sessionContext;
     }
 
+    public ISessionContext SessionContext { get; }
     public IDataPermissionManager DataPermissionManager { get; }
 
     public Expression<Func<TEntity, bool>> Build<TEntity>() where TEntity : class, IEntity<string>, IDataPermission, new()
     {
-        var queryFilterType = DataPermissionManager.GetQueryFilter<TEntity>(_sessionContext);
+        var queryFilterType = DataPermissionManager.GetQueryFilter<TEntity>(SessionContext);
         switch (queryFilterType)
         {
             case ETableAccessLevel.Creator:
-                return d => d.CreatorId == _sessionContext.RequiredUserId;
+                return d => d.CreatorId == SessionContext.RequiredUserId;
             case ETableAccessLevel.Org:
-                return d => d.CreatorOrgId == _sessionContext.RequiredOrgId;
+                return d => d.CreatorOrgId == SessionContext.RequiredOrgId;
             case ETableAccessLevel.OrgAndBelow:
-                return d => d.CreatorOrgId.StartsWith(_sessionContext.RequiredOrgId); //d.AreaId == _sessionContext.AreaId && _sessionContext.OrgLevel <= d.CreatorOrgLevel;
+                return d => d.CreatorOrgId.StartsWith(SessionContext.RequiredOrgId); //d.AreaId == _sessionContext.AreaId && _sessionContext.OrgLevel <= d.CreatorOrgLevel;
             case ETableAccessLevel.All:
                 return d => true;
             case ETableAccessLevel.Deny:
@@ -42,20 +42,20 @@ public class DataPermissionFilterBuilder : IDataPermissionFilterBuilder, IScopeD
 
     public Expression<Func<TEntity, bool>> BuildWithFlowViewFilter<TEntity>() where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
     {
-        var roles = _sessionContext.Roles;
+        var roles = SessionContext.Roles;
         if (roles != null && roles.Contains(RoleSeedData.AdminRole))
             return d => true;
 
-        return d => SqlFunc.JsonArrayAny(d.FlowedUserIds, _sessionContext.RequiredUserId) ||
-                    SqlFunc.JsonArrayAny(d.FlowedOrgIds, _sessionContext.RequiredOrgId);
+        return d => SqlFunc.JsonArrayAny(d.FlowedUserIds, SessionContext.RequiredUserId) ||
+                    SqlFunc.JsonArrayAny(d.FlowedOrgIds, SessionContext.RequiredOrgId);
     }
 
     public Expression<Func<TEntity, bool>> BuildWithFlowHandleFilter<TEntity>(bool canHandle)
         where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
     {
-        var userId = _sessionContext.RequiredUserId;
-        var orgId = _sessionContext.RequiredOrgId;
-        var roles = _sessionContext.Roles;
+        var userId = SessionContext.RequiredUserId;
+        var orgId = SessionContext.RequiredOrgId;
+        var roles = SessionContext.Roles;
         if (roles != null && roles.Contains(RoleSeedData.AdminRole))
             return d => true;
 
@@ -77,9 +77,9 @@ public class DataPermissionFilterBuilder : IDataPermissionFilterBuilder, IScopeD
 
     public Expression<Func<TEntity, Workflow, bool>> BuildIncludeFlowData1<TEntity>() where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
     {
-        var userId = _sessionContext.RequiredUserId;
-        var orgCode = _sessionContext.RequiredOrgId;
-        var roles = _sessionContext.Roles;
+        var userId = SessionContext.RequiredUserId;
+        var orgCode = SessionContext.RequiredOrgId;
+        var roles = SessionContext.Roles;
         if (roles != null && roles.Contains(RoleSeedData.AdminRole))
             return (d, w) => true;
 

+ 2 - 0
src/Hotline.Repository.SqlSugar/DataPermissions/IDataPermissionFilterBuilder.cs

@@ -1,11 +1,13 @@
 using System.Linq.Expressions;
 using Hotline.FlowEngine.Workflows;
+using XF.Domain.Authentications;
 using XF.Domain.Entities;
 
 namespace Hotline.Repository.SqlSugar.DataPermissions;
 
 public interface IDataPermissionFilterBuilder
 {
+    ISessionContext SessionContext { get; }
     IDataPermissionManager DataPermissionManager { get; }
     Expression<Func<TEntity, bool>> Build<TEntity>()
         where TEntity : class, IEntity<string>, IDataPermission, new();

+ 21 - 2
src/Hotline.Repository.SqlSugar/Extensions/DataPermissionExtensions.cs

@@ -1,5 +1,6 @@
 using Hotline.FlowEngine.Workflows;
 using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
 using XF.Domain.Entities;
 
@@ -18,14 +19,32 @@ namespace Hotline.Repository.SqlSugar.Extensions
             IDataPermissionFilterBuilder dataPermissionFilterBuilder)
             where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
         {
-            return queryable.Where(dataPermissionFilterBuilder.BuildWithFlowViewFilter<TEntity>());
+            var session = dataPermissionFilterBuilder.SessionContext;
+            return queryable.LeftJoin<WorkflowTrace>((d, step) => d.Id == step.ExternalId)
+                .Where((d, step) => (step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == session.RequiredUserId) ||
+                                       (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == session.RequiredOrgId) ||
+                                       (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && session.Roles.Contains(step.RoleId)))
+                .Select((d, step) => d)
+                ;
+
+            //return queryable.Where(dataPermissionFilterBuilder.BuildWithFlowViewFilter<TEntity>());
         }
 
         public static ISugarQueryable<TEntity> WorkflowHandleFiltering<TEntity>(this ISugarQueryable<TEntity> queryable,
             IDataPermissionFilterBuilder dataPermissionFilterBuilder, bool canHandle)
             where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
         {
-            return queryable.Where(dataPermissionFilterBuilder.BuildWithFlowHandleFilter<TEntity>(canHandle));
+            var session = dataPermissionFilterBuilder.SessionContext;
+            return queryable.LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
+                    .Where((d, step) => (step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == session.RequiredUserId) ||
+                                             (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == session.RequiredOrgId) ||
+                                             (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && session.Roles.Contains(step.RoleId)))
+                    .WhereIF(canHandle, (d, step) => step.Status != EWorkflowStepStatus.Handled)
+                    .WhereIF(!canHandle, (d, step) => step.Status == EWorkflowStepStatus.Handled)
+                    .Select((d, step) => d)
+                ;
+
+            //return queryable.Where(dataPermissionFilterBuilder.BuildWithFlowHandleFilter<TEntity>(canHandle));
         }
 
         public static TEntity InitDatePermission<TEntity>(this TEntity entity,

+ 59 - 0
src/Hotline.Share/Dtos/Ai/AiDto.cs

@@ -10,6 +10,65 @@ using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Ai
 {
+    public class CallOutTemplateDto
+    {
+        public string TemplateName { get; set; }
+
+        public string TemplateContent { get; set; }
+    }
+
+    public class UpdateCallOutTemplateDto:CallOutTemplateDto
+    {
+        public string Id { get; set; }
+    }
+
+    public record AiCallOutTemplateQueryRequest:PagedRequest
+    {
+        public string TemplateName { get; set; }
+
+        public DateTime? StartTime { get; set; }
+
+        public DateTime? EndTime { get; set; }
+    }
+
+    public record AiCallOutTemplateQueryRep
+    {
+        public string Id { get; set; }
+
+        public string TemplateContent { get; set; }
+
+        /// <summary>
+        /// 模板名称
+        /// </summary>
+        public string TemplateName { get; set; }
+        /// <summary>
+        /// 外呼任务数
+        /// </summary>
+        public int CallOutTaskCount { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        public DateTime CreationTime { get; set; }
+
+        /// <summary>
+        /// 是否启用
+        /// </summary>
+        public bool IsEnable { get; set; }
+
+        /// <summary>
+        /// 创建人
+        /// </summary>
+        public string? CreatorName { get; set; }
+
+        /// <summary>
+        /// 创建部门
+        /// </summary>
+        public string? CreatorOrgName { get; set; }
+    }
+
+
+
     public class AiVisitBackDto
     {
         public string BatchUid { get; set; }

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

@@ -32,7 +32,7 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// 部门等级/分类为:depCodes, 角色为:userIds
     /// </example>
     /// </summary>
-    public List<Kv> NextHandlers { get; set; } = new();
+    public List<FlowStepHandler> NextHandlers { get; set; } = new();
 
     /// <summary>
     /// 是否短信通知
@@ -49,6 +49,11 @@ public class BasicWorkflowDto : EndWorkflowDto
     /// </summary>
     public bool IsStartCountersign { get; set; }
 
+    ///// <summary>
+    ///// 办理方式
+    ///// </summary>
+    //public EHandleMode HandleMode => IsStartCountersign ? EHandleMode.StartCountersign : EHandleMode.Normal;
+
     /// <summary>
     /// 外部业务参数
     /// </summary>

+ 14 - 1
src/Hotline.Share/Dtos/FlowEngine/NextStepOption.cs

@@ -37,7 +37,7 @@ public class NextStepOption : Kv
     /// <summary>
     /// 节点下可选办理对象
     /// </summary>
-    public IReadOnlyList<Kv> Items { get; set; }
+    public IReadOnlyList<FlowStepHandler> Items { get; set; }
 }
 
 public class RecallStepOption : NextStepOption
@@ -46,4 +46,17 @@ public class RecallStepOption : NextStepOption
     /// 该节点原办理对象
     /// </summary>
     public Kv Handler { get; set; }
+}
+
+/// <summary>
+/// 流程办理对象
+/// </summary>
+public class FlowStepHandler : Kv
+{
+    public string? UserId { get; set; }
+    public string? Username { get; set; }
+    public string? OrgId { get; set; }
+    public string? OrgName { get; set; }
+    public string? RoleId { get; set; }
+    public string? RoleName { get; set; }
 }

+ 19 - 2
src/Hotline.Share/Dtos/FlowEngine/Workflow/WorkflowStepDto.cs

@@ -80,7 +80,24 @@ public class WorkflowStepDto
     /// </summary>
     public string? CountersignStartStepId { get; set; }
 
-    #endregion
+	#endregion
 
-    #endregion
+	#endregion
+
+
+	/// <summary>
+	/// 接办时间
+	/// </summary>
+	public DateTime? AcceptTime { get; set; }
+
+	/// <summary>
+	/// 接办人部门code
+	/// </summary>
+	public string? AcceptorOrgId { get; set; }
+
+	public string? AcceptorOrgName { get; set; }
+
+	public string? CreatorOrgId { get; set; }
+
+	public string? CreatorOrgName { get; set; }
 }

+ 5 - 0
src/Hotline.Share/Dtos/Knowledge/KnowledgePagedDto.cs

@@ -100,5 +100,10 @@ namespace Hotline.Share.Dtos.Knowledge
         /// </summary>
         public string? KnowledgeTypeId { get; set; }
 
+        /// <summary>
+        /// 审批类型
+        /// </summary>
+        public string? ModuleCode { get; set; }
+
 	}
 }

+ 25 - 0
src/Hotline.Share/Dtos/Order/ExternalcitizensDto.cs

@@ -0,0 +1,25 @@
+using Hotline.Share.Requests;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Order
+{
+    public record QueryExternalcitizensRequest: PagedRequest
+    {
+        public string PhoneNum { get; set; }
+
+        public string Name { get; set; }
+    }
+
+    public class ExternalcitizensRep
+    {
+        public string PhoneNum { get; set;}
+
+        public string Name { get; set; }
+
+        public DateTime CreationTime { get; set; }
+    }
+}

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

@@ -781,4 +781,13 @@ namespace Hotline.Share.Dtos.Order
     {
 	    public string OrderId { get; set; }
 	}
+
+    public class UnsignedOrderDto { 
+    
+        public OrderDto Order { get; set; }
+
+        public WorkflowStepDto WorkflowStep { get; set; }
+
+        public decimal UnsignedTime { get; set; }
+    }
 }

+ 53 - 0
src/Hotline.Share/Dtos/Order/OrderModifyingRecordsDto.cs

@@ -0,0 +1,53 @@
+using Hotline.Share.Enums.Order;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Share.Dtos.Order
+{
+    public class OrderModifyingRecordsDto
+    {
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string OrderNo { get; set; }
+
+        /// <summary>
+        /// 省编号
+        /// </summary>
+        public string ProvinceNo { get; set; }
+
+        /// <summary>
+        /// 修改类型
+        /// </summary>
+        public EUpdateType UpdateOrderType { get; set; }
+        public string UpdateOrderTypeText => UpdateOrderType.GetDescription();
+        /// <summary>
+        /// 旧值
+        /// </summary>
+        public string OldValue { get; set; }
+
+        /// <summary>
+        /// 新值
+        /// </summary>
+        public string NewValue { get; set; }
+
+        /// <summary>
+        /// 修改人
+        /// </summary>
+        public string? CreatorName { get; set; }
+
+        /// <summary>
+        /// 修改部门
+        /// </summary>
+        public string? CreatorOrgName { get; set; }
+
+        /// <summary>
+        /// 修改时间
+        /// </summary>
+        public DateTime CreationTime { get; set; }
+    }
+}

+ 3 - 2
src/Hotline.Share/Dtos/Order/OrderSpecialDto.cs

@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using XF.Utility.EnumExtensions;
 using Hotline.Share.Enums.FlowEngine;
@@ -37,7 +38,7 @@ namespace Hotline.Share.Dtos.Order
 		/// 部门等级/分类为:depCodes, 角色为:userIds
 		/// </example>
 		/// </summary>
-		public List<Kv> NextHandlers { get; set; } = new();
+		public List<FlowStepHandler> NextHandlers { get; set; } = new();
 
 		/// <summary>
 		/// 特提原因
@@ -102,7 +103,7 @@ namespace Hotline.Share.Dtos.Order
 		/// 部门等级/分类为:depCodes, 角色为:userIds
 		/// </example>
 		/// </summary>
-		public List<Kv> NextHandlers { get; set; } = new();
+		public List<FlowStepHandler> NextHandlers { get; set; } = new();
 
 		//public string? OrgId { get; set; }
 

+ 8 - 8
src/Hotline.Share/Dtos/Order/OrderWaitedDto.cs

@@ -51,15 +51,15 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public DateTime? EndCreationTime { get; set; }
 
-        /// <summary>
-        /// 开始受理时间
-        /// </summary>
-        public DateTime? StartTimeEnd { get; set; }
+		/// <summary>
+		/// 结束受理时间
+		/// </summary>
+		public DateTime? StartTimeEnd { get; set; }
 
-        /// <summary>
-        /// 结束受理时间
-        /// </summary>
-        public DateTime? StartTimeSt { get; set; }
+		/// <summary>
+		/// 开始受理时间
+		/// </summary>
+		public DateTime? StartTimeSt { get; set; }
         
         /// <summary>
         /// 当前节点名称

+ 39 - 0
src/Hotline.Share/Dtos/Order/UpdateOrderExpiredTimeDto.cs

@@ -0,0 +1,39 @@
+namespace Hotline.Share.Dtos.Order
+{
+    /// <summary>
+    /// 修改工单期满时间
+    /// </summary>
+    public class UpdateOrderExpiredTimeDto
+    {
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 新期满时间
+        /// </summary>
+        public DateTime? ExpiredTime { get; set; }
+
+        /// <summary>
+        /// 是否推送省上
+        /// </summary>
+        public bool IsPush { get; set; }
+    }
+
+    /// <summary>
+    /// 修改工单来源方式
+    /// </summary>
+    public class UpdateOrderSourceChannelDto
+    {
+        /// <summary>
+        /// 工单编号集合
+        /// </summary>
+        public List<string> Ids { get; set; }
+
+        /// <summary>
+        /// 是否推送省上
+        /// </summary>
+        public bool IsPush { get; set; }
+    }
+}

+ 22 - 1
src/Hotline.Share/Dtos/OrderTranspond/TranspondCityRawDataDto.cs

@@ -5,7 +5,7 @@ namespace Hotline.Share.Dtos.OrderTranspond
     public class TranspondCityRawDataDto
     {
         /// <summary>
-        /// 工单编号
+        /// 本地工单编号
         /// </summary>
         public string OrderCode { get; set; }
 
@@ -38,5 +38,26 @@ namespace Hotline.Share.Dtos.OrderTranspond
         /// 转出或者转入
         /// </summary>
         public ETranspondDirection Direction { get; set; }
+
+        /// <summary>
+        /// 接收方工单编号
+        /// </summary>
+        public string? NewCode { get; set; }
+
+        /// <summary>
+        /// 市州办理意见
+        /// </summary>
+        public string? ActualOpinion { get; set; }
+
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    public class TranspondCityOrderResultDto
+    {
+        public string No { get; set; }
+
+        public string Opinion { get; set; }
     }
 }

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

@@ -19,6 +19,11 @@ namespace Hotline.Share.Dtos.TrCallCenter
         public string Description { get; set; }
 
         public string QueueId { get; set; }
+
+        /// <summary>
+        /// 外呼分机组(由内部系统提供)
+        /// </summary>
+        public string? CallOutQueue { get; set; }
     }
 
 
@@ -166,6 +171,8 @@ namespace Hotline.Share.Dtos.TrCallCenter
     public class TrOnDutyDto
     {
         public string? TelNo { get; set; }
+
+        public int TelModelState { get; set; }
     }
 
     public class ChangeTelModelDto
@@ -192,6 +199,7 @@ namespace Hotline.Share.Dtos.TrCallCenter
 
         public bool? IsCallEndArrange { get; set; }
 
+        public bool? IsTelMute { get; set; }
         public int Second => CalcSecond();
 
         public ETelModel? TelModel { get; set; }

+ 21 - 0
src/Hotline.Share/Enums/Ai/EAiCallOutTaskState.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Ai
+{
+    public enum EAiCallOutTaskState
+    {
+        [Description("未开始")]
+        NoStarted = 1,
+
+        [Description("进行中")]
+        InProgress = 2,
+
+        [Description("已结束")]
+        Ended = 3,
+    }
+}

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

@@ -16,5 +16,8 @@ namespace Hotline.Share.Enums.CallCenter
 
         [Description("签入签出")]
         SignIn = 3,
+
+        [Description("静音")]
+        TelMute =4,
     }
 }

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

@@ -0,0 +1,22 @@
+namespace Hotline.Share.Enums.FlowEngine;
+
+/// <summary>
+/// 办理方式
+/// </summary>
+public enum EHandleMode
+{
+    /// <summary>
+    /// 正常办理
+    /// </summary>
+    Normal = 0,
+
+    /// <summary>
+    /// 开启会签
+    /// </summary>
+    StartCountersign = 1,
+
+    /// <summary>
+    /// 开启或签
+    /// </summary>
+    StartSignCountersign = 2
+}

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

@@ -25,6 +25,12 @@ public enum EWorkflowStepStatus
     [Description("已办理")]
     Handled = 2,
 
+    ///// <summary>
+    ///// 无需办理(或签流程未办理节点)
+    ///// </summary>
+    //[Description("无需办理")]
+    //NoNeedInSingleCountersign = 3,
+
     ///// <summary>
     ///// 未办理,由结束会签结束掉
     ///// </summary>

+ 18 - 3
src/Hotline.Share/Enums/Order/ESource.cs

@@ -12,7 +12,7 @@ public enum ESource
     /// <summary>
     /// 门户网站
     /// </summary>
-    WebPortal=2,
+    WebPortal = 2,
 
     /// <summary>
     /// 热线平台导入工单
@@ -30,14 +30,29 @@ public enum ESource
     Police110 = 200,
 
     /// <summary>
-    /// 泸州工单互转、 市州互转-宜宾、泸州市州互转工单
+    /// 市州互转--泸州 
     /// </summary>
     CityDataExchangeLz = 300,
 
+    /// <summary>
+    /// 市州互转--宜宾
+    /// </summary>
+    CityDataExchangeYB = 301,
+
+    /// <summary>
+    /// 市州互转--自贡
+    /// </summary>
+    CityDataExchangeZG = 302,
+
+    /// <summary>
+    /// 市州互转--内江
+    /// </summary>
+    CityDataExchangeNJ = 303,
+
     /// <summary>
     /// 宜宾融媒体
     /// </summary>
-    ConvergenceMedia=400,
+    ConvergenceMedia = 400,
 
     /// <summary>
     /// i宜宾

+ 16 - 0
src/Hotline.Share/Enums/Order/EUpdateType.cs

@@ -0,0 +1,16 @@
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.Order
+{
+    /// <summary>
+    /// 工单修改类型
+    /// </summary>
+    public enum EUpdateType
+    {
+        [Description("期满时间修改")]
+        ExpiredTime = 0,
+
+        [Description("来源方式修改")]
+        SourceChannel = 1,
+    }
+}

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

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

+ 5 - 0
src/Hotline.Share/Mq/EventNames.Share.cs

@@ -95,6 +95,11 @@
         /// </summary>
         public const string SharingOrderReceiveTranspondCity = "sharing.order.receive.transpond.city";
 
+        /// <summary>
+        /// 市州互转 接收办理结果
+        /// </summary>
+        public const string SharingOrderReceiveHandleOpinionTranspondCity = "sharing.order.receive.handle.opinion.transpond.city";
+
         /// <summary>
         /// 接受省上上传附件
         /// </summary>

+ 5 - 0
src/Hotline.Share/Requests/DepartmentalProcessingStatisticsDto.cs

@@ -235,6 +235,11 @@ namespace Hotline.Share.Requests
         /// 数据查询类别
         /// </summary>
         public EStatisticsType StatisticsType { get; set; }
+
+        /// <summary>
+        /// 是否省来源
+        /// </summary>
+        public bool? IsProvince { get; set; }
     }
 
     public class SelectOrderId

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

@@ -202,4 +202,17 @@ public record QuerySendOrderDetailRequest : ReportPagedRequest
 	public string UserId { get; set; }
 
 	public string TitleCode { get; set; }
+}
+
+public record QueryUnsignedOrdersRequest : ReportPagedRequest 
+{ 
+	/// <summary>
+	///  0 全部  1 本级  2 下级
+	/// </summary>
+	public int Level { get; set; }
+
+	/// <summary>
+	///  0 未签收  1 签收
+	/// </summary>
+	public int Signed { get; set; }
 }

+ 49 - 0
src/Hotline/Ai/CallOut/CallOutTask.cs

@@ -0,0 +1,49 @@
+
+using Hotline.Share.Enums.Ai;
+using XF.Domain.Repository;
+
+namespace Hotline.Ai.CallOut
+{
+    public class CallOutTask: CreationEntity
+    {
+        /// <summary>
+        /// 任务名称
+        /// </summary>
+        public string TaskName { get; set; }
+
+        /// <summary>
+        /// 状态
+        /// </summary>
+        public EAiCallOutTaskState AiCallOutTaskState { get; set; }
+
+        /// <summary>
+        /// 批次上报结果ID
+        /// </summary>
+        public string? BatchUid { get; set; }
+
+        public string CallOutTemplateId { get; set; }
+        /// <summary>
+        /// 应回访数量
+        /// </summary>
+        public int HasVisitCount { get; set; }
+
+        /// <summary>
+        /// 已回访成功数量
+        /// </summary>
+        public int VisitedCount { get; set; }
+
+        /// <summary>
+        /// 已回访失败数量
+        /// </summary>
+        public int VisitedFailCount { get; set; }
+
+        /// <summary>
+        /// 节日禁呼 0:否 1:是
+        /// </summary>
+        public int FestivalBan { get; set; }
+
+        public DateTime BeginTime { get; set; }
+
+        public DateTime EndTime { get; set; }
+    }
+}

+ 29 - 0
src/Hotline/Ai/CallOut/CallOutTaskDetail.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Ai.CallOut
+{
+    public class CallOutTaskDetail: CreationEntity
+    {
+        public string OuterNo { get; set; }
+
+        public string Name { get; set; }
+
+        public DateTime? CallOutTime { get; set; }
+
+        /// <summary>
+        /// 是否成功
+        /// </summary>
+        public bool? IsSuccess { get; set; }
+
+
+        /// <summary>
+        /// 批此上传成功后任务ID
+        /// </summary>
+        public string? TaskUid { get; set; }
+    }
+}

+ 19 - 0
src/Hotline/Ai/CallOut/CallOutTemplate.cs

@@ -0,0 +1,19 @@
+using Hotline.Orders;
+using SqlSugar;
+using XF.Domain.Repository;
+
+namespace Hotline.Ai.CallOut
+{
+    public class CallOutTemplate: CreationSoftDeleteEntity
+    {
+        public string TemplateName { get; set; }
+
+        public bool IsEnable { get; set; }
+
+        public string TemplateContent { get; set; }
+
+        [Navigate(NavigateType.OneToMany, nameof(CallOutTask.CallOutTemplateId))]
+        public List<CallOutTask> CallOutTasks { get; set; }
+
+    }
+}

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

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Authentications;
+using XF.Domain.Authentications;
 
 namespace Hotline.Authentications
 {
@@ -11,8 +6,8 @@ namespace Hotline.Authentications
     {
         public Police110SessionContext()
         {
-            UserId = "08dc73e3-f77f-4484-8309-bed5e532c9f2";
-            UserName = "市公安局110系统账号";
+            UserId = "e90501d7-c453-e18a-f1fa-3a1177930699";
+            UserName = "市公安局110";
             OrgId = "001180";
             OrgName = "市公安局110";
             OrgLevel = 1;

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

@@ -6,8 +6,8 @@ namespace Hotline.Authentications
     {
         public ProvinceSessionContext()
         {
-            UserId = "08dc73dd-56a7-4e95-80e0-47a8113db235";
-            UserName = "省12345平台系统账号";
+            UserId = "03aba148-e7b1-cd03-bf00-3a1177930508";
+            UserName = "省12345平台";
             OrgId = "001171";
             OrgName = "省12345平台";
             OrgLevel = 1;

+ 2 - 0
src/Hotline/Authentications/SessionContextCreator.cs

@@ -20,6 +20,8 @@ namespace Hotline.Authentications
                     return new Police110SessionContext();
                 case "yb-enterprise":
                     return new YbEnterpriseSessionContext();
+                case "zzpt":
+                    return new ZzptSessionContext();
                 default:
                     throw new ArgumentOutOfRangeException(nameof(source), source, null);
             }

+ 4 - 9
src/Hotline/Authentications/YbEnterpriseSessionContext.cs

@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Authentications;
+using XF.Domain.Authentications;
 
 namespace Hotline.Authentications
 {
@@ -11,10 +6,10 @@ namespace Hotline.Authentications
     {
         public YbEnterpriseSessionContext()
         {
-            UserId = "08dc73e5-3ba9-4436-869a-5345c45471fe";
-            UserName = "企业专办系统账号";
+            UserId = "ce42562c-afc1-764b-1dc8-3a1177930346";
+            UserName = "联系服务企业";
             OrgId = "001181";
-            OrgName = "企业专办";
+            OrgName = "联系服务企业";
             OrgLevel = 1;
         }
 

+ 51 - 0
src/Hotline/Authentications/ZzptSessionContext.cs

@@ -0,0 +1,51 @@
+using XF.Domain.Authentications;
+
+namespace Hotline.Authentications
+{
+    public class ZzptSessionContext : ISessionContext
+    {
+        public ZzptSessionContext()
+        {
+            UserId = "d4cb7151-41fa-a810-6c1e-3a117792fc0c";
+            UserName = "综治平台";
+            OrgId = "001143";
+            OrgName = "综治平台";
+            OrgLevel = 1;
+        }
+
+        /// <summary>
+        /// Id of current tenant or null for host
+        /// </summary>
+        public string? UserId { get; }
+
+        /// <summary>
+        /// Id of current user or throw Exception for guest
+        /// </summary>
+        public string RequiredUserId => UserId ?? throw new ArgumentNullException();
+        public string? UserName { get; }
+        public string? Phone { get; }
+
+        /// <summary>
+        /// Roles
+        /// </summary>
+        public string[] Roles { get; }
+        public string? OrgId { get; set; }
+        public string RequiredOrgId => OrgId ?? throw new ArgumentNullException();
+        public string? OrgName { get; set; }
+        public int OrgLevel { get; set; }
+        public string? OrgAreaCode { get; set; }
+        public bool OrgIsCenter { get; set; }
+
+        /// <summary>
+        /// 部门行政区划名称
+        /// </summary>
+        public string? OrgAreaName { get; set; }
+        public string? AreaId { get; }
+        public string? ClientId { get; }
+
+        /// <summary>
+        /// 工号
+        /// </summary>
+        public string? StaffNo { get; }
+    }
+}

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

@@ -36,8 +36,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询工作流包含当前用户办理权限(是否可办理)
         /// </summary>
-        Task<(Workflow workflow, string? countersignId, bool canPrevious)> GetWorkflowHandlePermissionAsync(
-            string workflowId, string userId, string orgId, CancellationToken cancellationToken = default);
+        Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious)> GetWorkflowHandlePermissionAsync(
+            string workflowId, string userId, string orgId, string[] roleIds, CancellationToken cancellationToken = default);
 
         /// <summary>
         /// 受理,接办
@@ -147,7 +147,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 创建开始节点
         /// </summary>
         WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto,
-            List<Kv> handlers, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime);
+            FlowStepHandler handler, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime);
 
         /// <summary>
         /// 查询未完成节点

+ 41 - 2
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -1,5 +1,6 @@
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Definition;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Enums.FlowEngine;
@@ -14,6 +15,9 @@ public abstract class StepBasicEntity : CreationEntity
 {
     public string WorkflowId { get; set; }
 
+    /// <summary>
+    /// 业务唯一标识
+    /// </summary>
     public string? ExternalId { get; set; }
 
     #region 业务模块(冗余)
@@ -206,6 +210,13 @@ public abstract class StepBasicEntity : CreationEntity
     /// </summary>
     public DateTime? HandleTime { get; set; }
 
+    /// <summary>
+    /// 角色id(如果指派给角色)
+    /// </summary>
+    public string? RoleId { get; set; }
+
+    public string? RoleName { get; set; }
+
     #endregion
 
     #region Definition
@@ -293,7 +304,7 @@ public abstract class StepBasicEntity : CreationEntity
     /// </example>
     /// </summary>
     [SugarColumn(ColumnDataType = "json", IsJson = true)]
-    public List<Kv> NextHandlers { get; set; } = new();
+    public List<FlowStepHandler> NextHandlers { get; set; } = new();
 
     /// <summary>
     /// 下一节点主办,(NextHandlers其中一个, 如果不是会签则只有一个)
@@ -403,10 +414,38 @@ public abstract class StepBasicEntity : CreationEntity
         }
     }
 
+    /// <summary>
+    /// 指派
+    /// </summary>
+    public void Assign(
+        string? handlerId, string? handlerName,
+        string? handlerOrgId, string? handlerOrgName,
+        string? roleId, string? roleName)
+    {
+        HandlerId = handlerId;
+        HandlerName = handlerName;
+        HandlerOrgId = handlerOrgId;
+        HandlerOrgName = handlerOrgName;
+        RoleId = roleId;
+        RoleName = roleName;
+    }
+
     /// <summary>
     /// 是否处于会签流程中(不包含顶层发起会签节点)
     /// </summary>
     public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;
 
     #endregion
-}
+}
+
+/*
+feature: 
+1. step增加字段记录roleId, roleName
+2. 指派时为对应办理对象赋值,办理时为所有办理对象字段赋值
+3. 配置办理对象为角色时,如果未指定办理人则指派给角色办理
+4. thk从默认派单池中分配给对应办理人时指定办理对象
+refactor:
+1. step增加字段记录发起会签或是或签
+2. status增加或签无需办理状态
+3. 办理节点时判断是否立即结束会签或者等全部节点办完再结束
+ */

+ 12 - 4
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -669,6 +669,7 @@ public partial class Workflow
                 HandlerOrgs = HandlerOrgs.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
+            case EFlowAssignType.Role:
                 HandlerUsers.AddRange(handlerObjects);
                 HandlerUsers = HandlerUsers.Distinct().ToList();
                 break;
@@ -719,9 +720,14 @@ public partial class Workflow
     /// 当前用户是否可以办理该流程
     /// </summary>
     /// <returns></returns>
-    public bool CanHandle(string userId, string orgCode) =>
-        Status is EWorkflowStatus.Runnable &&
-        (HandlerUsers.Any(d => d.Key == userId) || HandlerOrgs.Any(d => d.Key == orgCode));
+    public bool IsCanHandle(string userId, string orgId, string[] roleIds)
+    {
+        if (!Steps.Any())
+            throw new UserFriendlyException("未查询节点信息");
+        return Status is EWorkflowStatus.Runnable &&
+               //(HandlerUsers.Any(d => d.Key == userId) || HandlerOrgs.Any(d => d.Key == orgCode));
+               Steps.Any(d => d.IsCanHandle(userId, orgId, roleIds));
+    }
 
     private void RemoveCurrentHandleGroup(string handlerId, string handlerOrg)
     {
@@ -751,6 +757,7 @@ public partial class Workflow
                 FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
+            case EFlowAssignType.Role:
                 if (!FlowedUserIds.Exists(d => d == handler))
                     FlowedUserIds.Add(handler);
                 break;
@@ -770,6 +777,7 @@ public partial class Workflow
                 FlowedOrgIds = FlowedOrgIds.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
+            case EFlowAssignType.Role:
                 FlowedUserIds.AddRange(handlers);
                 FlowedUserIds = FlowedUserIds.Distinct().ToList();
                 break;
@@ -818,7 +826,7 @@ public partial class Workflow
         ResetOption();
         Status = EWorkflowStatus.Runnable;
     }
-    
+
     public void SetAllDuration()
     {
         if (!EndTime.HasValue)

+ 90 - 84
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -76,11 +76,6 @@ namespace Hotline.FlowEngine.Workflows
                 ModuleCode = wfModule.Code,
                 DefinitionId = definition.Id,
                 Status = EWorkflowStatus.Runnable,
-                //TimeLimit = timelimit,
-                //TimeLimitCount = timelimitCount,
-                //TimeLimitUnit = timeType,
-                //ExpiredTime = expiredTime.HasValue ? expiredTime.Value : DateTime.Now.AddDays(1),
-                //NearlyExpiredTime = nearlyExpiredTime,
                 Steps = new(),
                 Traces = new(),
                 WorkflowDefinition = definition,
@@ -113,9 +108,6 @@ namespace Hotline.FlowEngine.Workflows
                     current.RequiredOrgId, current.OrgName,
                     current.OrgAreaCode, current.OrgAreaName,
                     current.OrgLevel);
-                //workflow.ActualHandlerKey = current.RequiredUserId;
-                //workflow.ActualHandlerValue = current.UserName;
-                //workflow.ActualHandlerType = EHandlerType.AssignedUser;
 
                 var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, current, cancellationToken);
                 return;
@@ -234,14 +226,15 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询工作流包含当前用户结束会签权限(是否可结束)
         /// </summary>
-        public async Task<(Workflow, string?, bool)> GetWorkflowHandlePermissionAsync(
-            string workflowId, string userId, string orgId, CancellationToken cancellationToken = default)
+        public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious)> GetWorkflowHandlePermissionAsync(
+            string workflowId, string userId, string orgId, string[] roleIds, CancellationToken cancellationToken = default)
         {
             var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withCountersigns: true,
                 cancellationToken: cancellationToken);
 
+            var canHandle = workflow.IsCanHandle(userId, orgId, roleIds);
             var canPrevious = false;
-            if (workflow.CanHandle(userId, orgId))
+            if (canHandle)
             {
                 var currentStep = FindCurrentStepWaitForHandle(workflow, userId, orgId);
                 if (currentStep.Status is not EWorkflowStepStatus.Handled)
@@ -253,12 +246,12 @@ namespace Hotline.FlowEngine.Workflows
 
             var unCompletedCountersign = workflow.Countersigns
                 .FirstOrDefault(d => !d.IsCompleted() && d.StarterId == userId);
-            if (unCompletedCountersign is null) return (workflow, null, canPrevious);
+            if (unCompletedCountersign is null) return (workflow, null, canHandle, canPrevious);
 
             //var existCountersignEndStep = workflow.Steps.Exists(d =>
             //    d.IsCountersignEndStep && d.CountersignStartStepId == unCompletedCountersign.StartStepId);
             //return (workflow, existCountersignEndStep ? null : unCompletedCountersign.Id, canPrevious);
-            return (workflow, unCompletedCountersign.Id, canPrevious);
+            return (workflow, unCompletedCountersign.Id, canHandle, canPrevious);
         }
 
         /// <summary>
@@ -270,7 +263,7 @@ namespace Hotline.FlowEngine.Workflows
             string? orgAreaCode, string? orgAreaName,
             CancellationToken cancellationToken)
         {
-            if (!workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId)) return;
+            if (!workflow.IsCanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles)) return;
             //工单完成以后查看的场景
             if (workflow.Status != EWorkflowStatus.Runnable) return;
 
@@ -318,7 +311,7 @@ namespace Hotline.FlowEngine.Workflows
             DateTime? expiredTime, List<WorkflowStepHandler> stepHandlers, ISessionContext current,
             CancellationToken cancellationToken)
         {
-            ValidatePermission(workflow, current.RequiredOrgId, current.RequiredUserId);
+            ValidatePermission(workflow, current.RequiredOrgId, current.RequiredUserId, current.Roles);
             //CheckWhetherRunnable(workflow.Status);
 
             #region 办理当前节点
@@ -524,7 +517,7 @@ namespace Hotline.FlowEngine.Workflows
         public async Task<EFlowDirection> PreviousAsync(Workflow workflow, PreviousWorkflowDto dto, User operater,
            ISessionContext current, CancellationToken cancellationToken)
         {
-            ValidatePermission(workflow, operater.OrgId, operater.Id);
+            //ValidatePermission(workflow, operater.OrgId, operater.Id);
 
             var (currentStep, prevStep, countersignStartStep) = GetPreviousStep(workflow, operater.Id, operater.OrgId);
 
@@ -1217,7 +1210,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 创建开始节点
         /// </summary>
         public WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine,
-            BasicWorkflowDto dto, List<Kv> handles, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime)
+            BasicWorkflowDto dto, FlowStepHandler handler, List<WorkflowStepHandler> stepHandlers, DateTime? expiredTime)
         {
             //startstep
             var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
@@ -1231,7 +1224,7 @@ namespace Hotline.FlowEngine.Workflows
             var startStep = _mapper.Map<WorkflowStep>(startStepDefine);
             _mapper.Map(workflow, startStep);
             startStep.FlowAssignType = EFlowAssignType.User;
-            startStep.Handlers = handles;
+            startStep.Handlers = new List<Kv> { new(handler.Key, handler.Value) };
             startStep.StepHandlers = stepHandlers;
             startStep.NextSteps = nextSteps;
             startStep.IsMain = true;
@@ -1240,6 +1233,10 @@ namespace Hotline.FlowEngine.Workflows
             startStep.PrevChosenStepCode = null;
             startStep.StepExpiredTime = expiredTime;
 
+            startStep.Assign(handler.UserId, handler.Username,
+                handler.OrgId, handler.OrgName,
+                handler.RoleId, handler.RoleName);
+
             startStep.InitId();
             return startStep;
         }
@@ -1311,16 +1308,6 @@ namespace Hotline.FlowEngine.Workflows
             if (dto.IsStartCountersign && !counterSignType.HasValue)
                 throw new UserFriendlyException("缺少会签类型参数");
 
-            ////创建会签数据
-            //if (dto.IsStartCountersign)
-            //{
-            //    var exists = workflow.Countersigns.Any(d =>
-            //        !d.IsCompleted() && d.StarterId == _sessionContext.RequiredUserId);
-            //    if (exists)
-            //        throw new UserFriendlyException("该用户在当前流程存在未结束会签");
-            //    await StartCountersignAsync(workflow, step, dto, flowAssignType, counterSignType, expiredTime, cancellationToken);
-            //}
-
             //办理参数
             //_mapper.Map(dto, step);
             step.NextHandlers = dto.NextHandlers;
@@ -1375,10 +1362,10 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private async Task<WorkflowStep> CreateStartStepAsync(Workflow workflow, StepDefine startStepDefine,
-            BasicWorkflowDto dto, List<Kv> handles, List<WorkflowStepHandler> stepHandlers, EWorkflowTraceType traceType,
+            BasicWorkflowDto dto, FlowStepHandler handler, List<WorkflowStepHandler> stepHandlers, EWorkflowTraceType traceType,
             DateTime? expiredTime, CancellationToken cancellationToken)
         {
-            var startStep = CreateStartStep(workflow, startStepDefine, dto, handles, stepHandlers, expiredTime);
+            var startStep = CreateStartStep(workflow, startStepDefine, dto, handler, stepHandlers, expiredTime);
             //await _workflowStepRepository.AddAsync(startStep, cancellationToken);
             await _workflowStepRepository.AddNav(startStep)
                 .Include(d => d.StepHandlers)
@@ -1509,7 +1496,7 @@ namespace Hotline.FlowEngine.Workflows
                 _ => throw new ArgumentOutOfRangeException()
             };
 
-            return await CreateStepsAsync(workflow, nextStepDefine, prevStep, dto, dto.IsStartCountersign,
+            return await CreateStepsAsync(workflow, nextStepDefine, prevStep, dto,
                 flowAssignInfo.FlowAssignType, dto.NextHandlers, stepHandlers, null, EWorkflowStepStatus.WaitForAccept,
                 ECountersignPosition.None, false, EWorkflowTraceType.Normal, handlerType, expiredTime,
                 cancellationToken: cancellationToken);
@@ -1544,7 +1531,7 @@ namespace Hotline.FlowEngine.Workflows
                 ? ECountersignPosition.Multi
                 : ECountersignPosition.Single;
 
-            return CreateStepsAsync(workflow, stepDefine, prevStep, dto, isStartCountersign, flowAssignType, dto.NextHandlers,
+            return CreateStepsAsync(workflow, stepDefine, prevStep, dto, flowAssignType, dto.NextHandlers,
                 stepHandlers, countersignId, EWorkflowStepStatus.WaitForAccept, nextStepCountersignPosition,
                 false, EWorkflowTraceType.Normal, handlerType, expiredTime, cancellationToken: cancellationToken);
         }
@@ -1652,7 +1639,8 @@ namespace Hotline.FlowEngine.Workflows
             EFlowAssignType? flowAssignType, ECounterSignType? counterSignType, DateTime? expiredTime,
             CancellationToken cancellationToken)
         {
-            var countersign = await CreateCountersignAsync(current, workflow, startStep, dto.NextHandlers, flowAssignType,
+            var countersign = await CreateCountersignAsync(current, workflow, startStep,
+                dto.NextHandlers.Select(d => new Kv(d.Key, d.Value)).ToList(), flowAssignType,
                 counterSignType, expiredTime, startStep.CountersignId, cancellationToken);
             startStep.StartCountersign(countersign.Id);
         }
@@ -1951,14 +1939,13 @@ namespace Hotline.FlowEngine.Workflows
                 workflow.SetStatusRunnable();
 
             var targetStepNew = targetIsStartStep
-                ? await CreateStartStepAsync(workflow, targetStepDefine, dto, dto.NextHandlers, stepHandlers, traceType, expiredTime,
-                    cancellationToken)
-                : (await CreateStepsAsync(workflow, targetStepDefine, targetPrevStep, dto, false,
+                ? await CreateStartStepAsync(workflow, targetStepDefine, dto,
+                    dto.NextHandlers.First(), stepHandlers, traceType, expiredTime, cancellationToken)
+                : (await CreateStepsAsync(workflow, targetStepDefine, targetPrevStep, dto,
                     flowAssignInfo.FlowAssignType, dto.NextHandlers, stepHandlers,
                     null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None, true, traceType,
                     null, expiredTime, cancellationToken: cancellationToken)).First();
 
-
             //更新实际办理节点信息
             workflow.UpdateActualStepWhenAssign(targetStepNew, targetStep.HandlerOrgName, targetStep.HandlerOrgId);
 
@@ -1998,9 +1985,9 @@ namespace Hotline.FlowEngine.Workflows
                 throw UserFriendlyException.SameMessage("当前流程状态不可继续流转");
         }
 
-        private void ValidatePermission(Workflow workflow, string OrgId, string UserId)
+        private void ValidatePermission(Workflow workflow, string OrgId, string UserId, string[] roleIds)
         {
-            if (!workflow.CanHandle(UserId, OrgId))
+            if (!workflow.IsCanHandle(UserId, OrgId, roleIds))
                 throw UserFriendlyException.SameMessage("无办理权限");
         }
 
@@ -2015,10 +2002,18 @@ namespace Hotline.FlowEngine.Workflows
             if (workflow.Steps.Any(d => d.StepType == EStepType.End))
                 throw UserFriendlyException.SameMessage("无法重复创建结束节点");
 
-            var handler = new Kv { Key = _sessionContext.UserId, Value = _sessionContext.UserName };
+            var handler = new FlowStepHandler
+            {
+                Key = current.UserId,
+                Value = current.UserName,
+                UserId = current.RequiredUserId,
+                Username = current.UserName,
+                OrgId = current.OrgId,
+                OrgName = current.OrgName,
+            };
 
-            var step = CreateStep(workflow, endStepDefine, prevStep, null, new List<Kv> { handler },
-                stepHandlers, null, null, null, EWorkflowStepStatus.WaitForAccept,
+            var step = CreateStep(workflow, endStepDefine, prevStep, null, handler,
+                stepHandlers, null, null, EWorkflowStepStatus.WaitForAccept,
                 ECountersignPosition.None, DateTime.Now, endStepDefine.Name, true);
 
             //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
@@ -2046,26 +2041,31 @@ namespace Hotline.FlowEngine.Workflows
             List<WorkflowStepHandler> stepHandlers,
             CancellationToken cancellationToken)
         {
-            List<Kv> handlers;
-            if (stepDefine.HandlerType is EHandlerType.AssignedUser or EHandlerType.AssignedOrg)
+            //List<Kv> handlers;
+            //if (stepDefine.HandlerType is EHandlerType.AssignedUser or EHandlerType.AssignedOrg)
+            //{
+            //    handlers = stepDefine.HandlerTypeItems;
+            //}
+            //else
+            //{
+            List<FlowStepHandler> handlers;
+            if (stepDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
+                throw new UserFriendlyException("未指定节点处理者");
+            if (stepDefine.HandlerType == EHandlerType.Role && !dto.NextHandlers.Any())
             {
-                handlers = stepDefine.HandlerTypeItems;
+                var handler = stepDefine.HandlerTypeItems.First();
+                handlers = new List<FlowStepHandler>
+                {
+                    new(){Key = handler.Key, Value = handler.Value, RoleId = handler.Key, RoleName = handler.Value}
+                }; //flowAssignInfo.GetHandlers();
             }
             else
             {
-                if (stepDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
-                    throw new UserFriendlyException("未指定节点处理者");
-                if (stepDefine.HandlerType == EHandlerType.Role && !dto.NextHandlers.Any())
-                {
-                    handlers = flowAssignInfo.GetHandlers();
-                }
-                else
-                {
-                    handlers = dto.NextHandlers;
-                }
+                handlers = dto.NextHandlers;
             }
+            //}
 
-            return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, dto.IsStartCountersign,
+            return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, /*dto.IsStartCountersign,*/
                 flowAssignInfo.FlowAssignType, handlers, stepHandlers, null,
                 EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
                 true, traceType, null, expiredTime, cancellationToken);
@@ -2076,9 +2076,9 @@ namespace Hotline.FlowEngine.Workflows
             StepDefine stepDefine,
             WorkflowStep prevStep,
             BasicWorkflowDto dto,
-            bool isStartCountersign,
+            //bool isStartCountersign,
             EFlowAssignType? flowAssignType,
-            List<Kv> handlers,
+            List<FlowStepHandler> handlers,
             List<WorkflowStepHandler> stepHandlers,
             string? countersignId,
             EWorkflowStepStatus stepStatus,
@@ -2091,29 +2091,30 @@ namespace Hotline.FlowEngine.Workflows
         )
         {
             List<WorkflowStep> steps = new();
-            if (isStartCountersign)
-            {
-                foreach (var handler in handlers)
-                {
-                    var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType,
-                        new List<Kv> { handler }, new(), dto.NextStepCode,
-                        dto.NextMainHandler, countersignId, stepStatus, csPosition, expiredTime,
-                        dto.NextStepName, isOrigin, handlerType, dto.BusinessType);
-
-                    var stepHandler = stepHandlers.First(d => d.GetHandler().Key == handler.Key);
-                    step.StepHandlers = new List<WorkflowStepHandler> { stepHandler };
+            //if (isStartCountersign)
+            //{
 
-                    steps.Add(step);
-                }
-            }
-            else
+            foreach (var handler in handlers)
             {
-                var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, handlers,
-                    stepHandlers, dto.NextStepCode, dto.NextMainHandler, countersignId, stepStatus,
-                    csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType, dto.BusinessType);
+                var isMain = handlers.Count == 1 || (handlers.Count > 1 && handler.Key == dto.NextMainHandler);
+                var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType,
+                    handler, stepHandlers, dto.NextStepCode, countersignId, stepStatus, csPosition, expiredTime,
+                    dto.NextStepName, isOrigin, isMain, handlerType, dto.BusinessType);
+
+                //var stepHandler = stepHandlers.First(d => d.GetHandler().Key == handler.Key);
+                //step.StepHandlers = new List<WorkflowStepHandler> { stepHandler };
 
                 steps.Add(step);
             }
+            //}
+            //else
+            //{
+            //    var step = CreateStep(workflow, stepDefine, prevStep, flowAssignType, handlers,
+            //        stepHandlers, dto.NextStepCode, dto.NextMainHandler, countersignId, stepStatus,
+            //        csPosition, expiredTime, dto.NextStepName, isOrigin, handlerType, dto.BusinessType);
+
+            //    steps.Add(step);
+            //}
 
             //await _workflowStepRepository.AddRangeAsync(steps, cancellationToken);
             await _workflowStepRepository.AddNav(steps)
@@ -2370,32 +2371,33 @@ namespace Hotline.FlowEngine.Workflows
             StepDefine stepDefine,
             WorkflowStep prevStep,
             EFlowAssignType? flowAssignType,
-            List<Kv> handlers,
+            FlowStepHandler handler,
             List<WorkflowStepHandler> stepHandlers,
             string nextStepCode,
-            string? nextMainHandler,
             string? countersignId,
             EWorkflowStepStatus stepStatus,
             ECountersignPosition countersignPosition,
             DateTime? expiredTime,
             string stepName,
             bool isOrigin,
+            bool isMainHandler = false,
             EHandlerType? handlerType = null, //动态节点依据动态策略判断
             EBusinessType? businessType = null
         )
         {
-            if (!handlers.Any())
-                throw new UserFriendlyException($"非法参数, handlers为空, method: {nameof(CreateStep)}");
+            //if (!handlers.Any())
+            //    throw new UserFriendlyException($"非法参数, handlers为空, method: {nameof(CreateStep)}");
             var step = _mapper.Map<WorkflowStep>(stepDefine);
             _mapper.Map(workflow, step);
-            var handlerIds = handlers.Select(d => d.Key).ToList();
-            var isMain = handlers.Count == 1 || (handlers.Count > 1 || handlerIds.First() == nextMainHandler);
+            //todo mainhandler 未赋值
+            //var handlerIds = handlers.Select(d => d.Key).ToList();
+            //var isMain = handlers.Count == 1 || (handlers.Count > 1 || handlerIds.First() == nextMainHandler);
 
             step.FlowAssignType = flowAssignType;
-            step.Handlers = handlers;
+            step.Handlers = new List<Kv> { new(handler.Key, handler.Value) };
             step.StepHandlers = stepHandlers;
             step.NextStepCode = step.StepType is EStepType.End ? string.Empty : nextStepCode;
-            step.IsMain = isMain;
+            step.IsMain = isMainHandler;
             step.PrevStepId = prevStep.Id;
             step.PrevStepCode = prevStep.Code;
             step.CountersignId = countersignId;
@@ -2406,6 +2408,10 @@ namespace Hotline.FlowEngine.Workflows
             step.IsOrigin = isOrigin;
             step.Name = stepName;
 
+            step.Assign(handler.UserId, handler.Username,
+                handler.OrgId, handler.OrgName,
+                handler.RoleId, handler.RoleName);
+
             if (handlerType.HasValue)
                 step.HandlerType = handlerType.Value;
             if (businessType.HasValue)

+ 48 - 0
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -1,9 +1,11 @@
 using Hotline.File;
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine.Definition;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Enums.FlowEngine;
 using SqlSugar;
+using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 
 namespace Hotline.FlowEngine.Workflows;
@@ -186,6 +188,52 @@ public class WorkflowStep : StepBasicEntity
     public WorkflowStepHandler? GetActualHandler() =>
         StepHandlers.FirstOrDefault(d => d.IsActualHandler);
 
+    public FlowStepHandler GetWorkflowStepHandler()
+    {
+        switch (FlowAssignType)
+        {
+            case EFlowAssignType.Org:
+                return new FlowStepHandler
+                {
+                    Key = HandlerOrgId,
+                    Value = HandlerOrgName,
+                    OrgId = HandlerOrgId,
+                    OrgName = HandlerOrgName
+                };
+            case EFlowAssignType.User:
+                return new FlowStepHandler
+                {
+                    Key = HandlerId,
+                    Value = HandlerName,
+                    UserId = HandlerId,
+                    Username = HandlerName,
+                    OrgId = HandlerOrgId,
+                    OrgName = HandlerOrgName
+                };
+            case EFlowAssignType.Role:
+                return new FlowStepHandler
+                {
+                    Key = RoleId,
+                    Value = RoleName,
+                    RoleId = RoleId,
+                    RoleName = RoleName,
+                };
+            default:
+                throw new ArgumentOutOfRangeException();
+        }
+    }
+
+    public bool IsCanHandle(string userId, string orgId, string[] roleIds)
+    {
+        if(Status is EWorkflowStepStatus.Handled) return false;
+        return FlowAssignType switch
+        {
+            EFlowAssignType.Org => !string.IsNullOrEmpty(HandlerOrgId) && HandlerOrgId == orgId,
+            EFlowAssignType.User => !string.IsNullOrEmpty(HandlerId) && HandlerId == userId,
+            EFlowAssignType.Role => !string.IsNullOrEmpty(RoleId) && roleIds.Contains(RoleId),
+            _ => throw new ArgumentOutOfRangeException()
+        };
+    }
     #endregion
 }
 

+ 2 - 2
src/Hotline/FlowEngine/Workflows/WorkflowStepHandler.cs

@@ -46,8 +46,8 @@ public class WorkflowStepHandler : CreationEntity
         return handler;
     }
 
-        public void Assign(EFlowAssignType assignType, string? userId, string? username,
-        string? orgId, string? orgName, string? roleId, string? roleName)
+    public void Assign(EFlowAssignType assignType, string? userId, string? username,
+    string? orgId, string? orgName, string? roleId, string? roleName)
     {
         FlowAssignType = assignType;
         switch (assignType)

+ 16 - 0
src/Hotline/Import/ExternalCitizensExcelContent.cs

@@ -0,0 +1,16 @@
+using MiniExcelLibs.Attributes;
+
+namespace Hotline.Import
+{
+    public class ExternalCitizensExcelContent
+    {
+        [ExcelColumnName("电话")]
+        public string PhoneNum { get; set; }
+
+        /// <summary>
+		/// 姓名
+		/// </summary>
+		[ExcelColumnName("姓名")]
+        public string? Name { get; set; }
+    }
+}

+ 12 - 0
src/Hotline/OrderTranspond/TranspondCityRawData.cs

@@ -47,5 +47,17 @@ namespace Hotline.OrderTranspond
         /// </summary>
         [SugarColumn(ColumnDescription = "转出或者转入")]
         public ETranspondDirection Direction { get; set; }
+
+        /// <summary>
+        /// 接收方工单编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "接收方工单编号")]
+        public string? NewCode { get; set; }
+
+        /// <summary>
+        /// 市州办理意见
+        /// </summary>
+        [SugarColumn(ColumnDescription = "接收方工单编号")]
+        public string? ActualOpinion { get; set; }
     }
 }

+ 2 - 1
src/Hotline/Orders/IOrderDomainService.cs

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 
 namespace Hotline.Orders
@@ -60,7 +61,7 @@ namespace Hotline.Orders
         /// 平均派单
         /// </summary>
         /// <returns></returns>
-        Task<List<Kv>> AverageOrder(CancellationToken cancellationToken);
+        Task<FlowStepHandler> AverageOrder(CancellationToken cancellationToken);
         
         /// <summary>
         /// 登录平均派单

+ 9 - 1
src/Hotline/Orders/Order.cs

@@ -23,7 +23,8 @@ namespace Hotline.Orders
     [Description("工单")]
     [SugarIndex("unique_order_no", nameof(Order.No), OrderByType.Desc, true)]
     [SugarIndex("index_order_creationtime", nameof(Order.CreationTime), OrderByType.Asc)]
-    public partial class Order : PositionWorkflowEntity
+    [SugarIndex("index_order_startTime", nameof(Order.StartTime), OrderByType.Asc)]
+	public partial class Order : PositionWorkflowEntity
     {
         public Order()
         {
@@ -981,4 +982,11 @@ namespace Hotline.Orders
 
         #endregion
     }
+
+    public class UnsignedOrder
+    {
+	    public Order Order { get; set; }
+
+	    public WorkflowStep WorkflowStep { get; set; }
+    }
 }

+ 25 - 7
src/Hotline/Orders/OrderDomainService.cs

@@ -16,6 +16,7 @@ using Hotline.Schedulings;
 using Hotline.Users;
 using Hotline.Share.Dtos;
 using Hotline.Settings.Hotspots;
+using Hotline.Share.Dtos.FlowEngine;
 
 namespace Hotline.Orders;
 
@@ -182,21 +183,38 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     /// 平均派单
     /// </summary>
     /// <returns></returns>
-    public async Task<List<Kv>> AverageOrder(CancellationToken cancellationToken)
+    public async Task<FlowStepHandler> AverageOrder(CancellationToken cancellationToken)
     {
         var time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
         var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
             .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && x.AtWork == true)
             .OrderBy(x => x.SendOrderNum).FirstAsync(cancellationToken);
         if (scheduling is null)
-            return new List<Kv> { new(OrderDefaults.SourceChannel.SendPoolId, "待派单池") };
-
-        var user = await _userRepository.GetAsync(x => x.Id == scheduling.SchedulingUser.UserId, cancellationToken);
-        if (user is null)
-            throw new UserFriendlyException("无效用户编号");
+            //return new List<Kv> { new(OrderDefaults.SourceChannel.SendPoolId, "待派单池") };
+            return new FlowStepHandler
+            {
+                Key = OrderDefaults.SourceChannel.SendPoolId,
+                Value = "待派单池",
+                UserId = OrderDefaults.SourceChannel.SendPoolId,
+                Username = "待派单池",
+            };
+
+        //var user = await _userRepository.GetAsync(x => x.Id == scheduling.SchedulingUser.UserId, cancellationToken);
+        //if (user is null)
+        //    throw new UserFriendlyException("无效用户编号");
         scheduling.SendOrderNum++;
         await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
-        return new List<Kv> { new(user.Id, user.Name) };
+        //return new List<Kv> { new(user.Id, user.Name) };
+        var user = scheduling.SchedulingUser;
+        return new FlowStepHandler
+        {
+            Key = user.UserId,
+            Value = user.UserName,
+            UserId = user.UserId,
+            Username = user.UserName,
+            OrgId = user.OrgId,
+            OrgName = user.OrgIdName
+        };
     }
 
     /// <summary>

+ 44 - 0
src/Hotline/Orders/OrderModifyingRecords.cs

@@ -0,0 +1,44 @@
+using Hotline.Share.Enums.Order;
+using SqlSugar;
+using System.ComponentModel;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    [Description("工单修改记录")]
+    public class OrderModifyingRecords : CreationEntity
+    {
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单ID")]
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单编号")]
+        public string OrderNo { get; set; }
+
+        /// <summary>
+        /// 省编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "省编号")]
+        public string ProvinceNo { get; set; }
+
+        /// <summary>
+        /// 修改类型
+        /// </summary>
+        public EUpdateType UpdateOrderType { get; set; }
+
+        /// <summary>
+        /// 旧值
+        /// </summary>
+        public string OldValue { get; set; }
+
+        /// <summary>
+        /// 新值
+        /// </summary>
+        public string NewValue { get; set; }
+    }
+}

+ 2 - 1
src/Hotline/Orders/OrderSpecial.cs

@@ -7,6 +7,7 @@ using System.Threading.Tasks;
 using Hotline.FlowEngine.Workflows;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
@@ -46,7 +47,7 @@ namespace Hotline.Orders
         public string? StepName { get; set; } = string.Empty;
 
 		[SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
-		public List<Kv> NextHandlers { get; set; }
+		public List<FlowStepHandler> NextHandlers { get; set; }
 
 		/// <summary>
 		/// 特提原因

+ 1 - 0
src/Hotline/README.md

@@ -32,6 +32,7 @@ master, hotfix, fix, dev, feature, release
 | fix | 非紧急bug修复分支,拉取自dev |
 | dev | 开发分支,开发环境共有分支,提供前后端对接环境 |
 | feature | 功能开发分支 |
+| release | 发布分支 |
 
 #### 分支命名规范
 

+ 12 - 3
src/Hotline/Settings/TimeLimits/ITimeLimitDomainService.cs

@@ -86,11 +86,20 @@ namespace Hotline.Settings.TimeLimits
         string CalcTimeInterval(DateTime beginTime, DateTime endTime, bool isCenter);
 
         /// <summary>
-        /// 判断是否工作日
+        /// 时间间隔 小时
         /// </summary>
-        /// <param name="date"></param>
+        /// <param name="beginTime"></param>
+        /// <param name="endTime"></param>
+        /// <param name="isCenter"></param>
         /// <returns></returns>
-        bool IsWorkDay(DateTime date);
+        decimal CalcWorkTimeToHour(DateTime beginTime, DateTime endTime, bool isCenter);
+
+		/// <summary>
+		/// 判断是否工作日
+		/// </summary>
+		/// <param name="date"></param>
+		/// <returns></returns>
+		bool IsWorkDay(DateTime date);
 
         /// <summary>
         /// 获取工作日

+ 40 - 3
src/Hotline/Settings/TimeLimits/TimeLimitDomainService.cs

@@ -183,15 +183,52 @@ namespace Hotline.Settings.TimeLimits
 
         }
 
-
         /// <summary>
-        /// 计算工作时间分钟数
+        /// 计算工作时间小时
         /// </summary>
         /// <param name="beginTime"></param>
         /// <param name="endTime"></param>
         /// <param name="isCenter"></param>
         /// <returns></returns>
-        public int CalcWorkTime(DateTime beginTime, DateTime endTime, bool isCenter)
+        public decimal CalcWorkTimeToHour(DateTime beginTime, DateTime endTime, bool isCenter)
+        {
+	        var min = CalcWorkTime(beginTime, endTime, isCenter);
+	        if (min != 0)
+	        {
+		        if (isCenter)
+		        {
+			        return Math.Round((decimal)min / 60 / 60 / 24, 2);
+		        }
+		        else
+		        {
+			        var workTime = _systemSettingRepository.Get(x => x.Code == SettingConstants.WorkTime);
+			        if (workTime != null)
+			        {
+				        //DateTime WorkBeginTime = DateTime.Parse(beginTime.ToShortDateString() + " " + workTime.SettingValue[0] + ":00");
+				        //DateTime WorkEndTime = DateTime.Parse(beginTime.ToShortDateString() + " " + workTime.SettingValue[1] + ":00");
+
+				        //TimeSpan minuteSpan = new TimeSpan(WorkEndTime.Ticks - WorkBeginTime.Ticks);
+				        ////总时差分钟数
+				        //int minutes = (int)minuteSpan.TotalMinutes;
+
+				        return Math.Round((decimal)min / 60 , 2);
+			        }
+			        return 0;
+		        }
+	        }
+	        return 0;
+
+        }
+
+
+		/// <summary>
+		/// 计算工作时间分钟数
+		/// </summary>
+		/// <param name="beginTime"></param>
+		/// <param name="endTime"></param>
+		/// <param name="isCenter"></param>
+		/// <returns></returns>
+		public int CalcWorkTime(DateTime beginTime, DateTime endTime, bool isCenter)
         {
             if (isCenter)
             {

+ 1 - 1
src/XF.Domain.Repository/Entity.cs

@@ -93,7 +93,7 @@ public abstract class SoftDeleteEntity : Entity, IHasDeletionTime, ISoftDelete
 public abstract class CreationSoftDeleteEntity : CreationEntity, IHasDeletionTime, ISoftDelete
 {
     [SugarColumn(ColumnDescription = "是否删除", DefaultValue = "f")]
-    public bool IsDeleted { get; set; }
+	public bool IsDeleted { get; set; }
 
     /// <summary>
     /// 删除时间

+ 3 - 3
src/XF.Domain.Repository/IRepositoryWorkflow.cs

@@ -27,9 +27,9 @@ namespace XF.Domain.Repository
         /// </summary>
         /// <param name="permissionVerify"></param>
         /// <param name="includeDeleted"></param>
-        /// <param name="viewFilter">是否可查看过滤开关</param>
-        /// <param name="handlerFilter">是否可办理过滤开关</param>
+        /// <param name="canView">是否可查看</param>
+        /// <param name="hasHandled">是否已办理,null: 不过滤</param>
         /// <returns></returns>
-        ISugarQueryable<TEntity> Queryable(bool permissionVerify = false, bool includeDeleted = false, bool viewFilter = false, bool? handlerFilter = null);
+        ISugarQueryable<TEntity> Queryable(bool permissionVerify = false, bool includeDeleted = false, bool canView = false, bool? hasHandled = null);
     }
 }

+ 8 - 0
src/XF.Domain/Constants/SettingConstants.cs

@@ -227,7 +227,15 @@ namespace XF.Domain.Constants
         /// </summary>
         public const string IsRecallToSeatDesignated = "IsRecallToSeatDesignated";
 
+        /// <summary>
+        /// 不参与会签的部门
+        /// </summary>
+        public const string NoSignOrgCode = "NoSignOrgCode";
 
+        /// <summary>
+        /// 市州互转是否接收办理结果
+        /// </summary>
+        public const string CityDataUndertakAdvice = "CityDataUndertakAdvice";
         #region 智能外呼
 
         #region 智能回访

+ 4 - 4
src/XF.Domain/Entities/IWorkflow.cs

@@ -72,10 +72,10 @@ public enum EFlowAssignType
     /// </summary>
     User = 1,
 
-    ///// <summary>
-    ///// 指派到角色
-    ///// </summary>
-    //Role = 2,
+    /// <summary>
+    /// 指派到角色
+    /// </summary>
+    Role = 2,
 }
 
 /// <summary>