Browse Source

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

Dun.Jason 5 months ago
parent
commit
fd3b27af46

+ 289 - 233
src/Hotline.Api/Controllers/OrderController.cs

@@ -71,6 +71,7 @@ using static Lucene.Net.Util.Fst.Util;
 using DocumentFormat.OpenXml.Spreadsheet;
 using System.Threading;
 using Hotline.Caching.Services;
+using Hotline.CallCenter.Calls;
 
 namespace Hotline.Api.Controllers;
 
@@ -310,8 +311,8 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
-                                                                                              //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
-                                                                                              //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
+            //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
+            //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
             .WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState)
             .WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState)
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.Source == ESource.ProvinceStraight)
@@ -382,15 +383,24 @@ public class OrderController : BaseController
     public async Task PublishOrder([FromBody] PublishOrderDto dto)
     {
         //验证订单
-        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-
-
-        if (order is null)
-            throw UserFriendlyException.SameMessage("未找到工单,无法发布");
+        var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted)
+                    ?? throw UserFriendlyException.SameMessage("未找到工单,无法发布");
 
         if (order.Status != EOrderStatus.Filed)
             throw UserFriendlyException.SameMessage("当前状态无法发布");
 
+        var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
+        if (enabled)
+        {
+            // 获取上一次被取消发布的发布信息
+            var publishedDeleted = await _orderPublishRepository.Queryable().Where(m => m.OrderId == dto.Id && m.IsDeleted == true)
+                .OrderByDescending(m => m.CreationTime).FirstAsync(HttpContext.RequestAborted);
+            if (publishedDeleted != null && _sessionContext.RequiredUserId != publishedDeleted.CreatorId)
+            {
+                throw UserFriendlyException.SameMessage($"改工单被取消发布过, 之前的发布人是 [{publishedDeleted.CreatorName}], 您不能发布;");
+            }
+        }
+
         //新增发布工单
         var orderPublish = _mapper.Map<OrderPublish>(dto);
         orderPublish.OrderId = order.Id;
@@ -767,16 +777,28 @@ public class OrderController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPut("publish/cancel")]
-    public async Task<string> PublishCancelAsync([FromBody]PublishCancelInDto dto)
+    [LogFilter("取消发布")]
+    public async Task<string> PublishCancelAsync([FromBody] PublishCancelInDto dto)
     {
         var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled;
         if (enabled == false) return "取消发布功能已被关闭";
+
         var publish = await _orderPublishRepository.GetAsync(dto.OrderPublishId)
-            ?? throw UserFriendlyException.SameMessage("发布单不存在");
+                      ?? throw UserFriendlyException.SameMessage("发布单不存在");
         publish.IsDeleted = true;
+        var order = await _orderRepository.GetAsync(publish.OrderId, HttpContext.RequestAborted) ??
+                    throw UserFriendlyException.SameMessage("工单不存在");
+        if (order.Status != EOrderStatus.Published && order.Status != EOrderStatus.Visited)
+            throw UserFriendlyException.SameMessage("工单状态非[已发布]和[已回访], 不可取消发布.");
+
         await _orderPublishRepository.UpdateAsync(publish);
+        order.Status = EOrderStatus.Filed;
+        // 被取消的工单继续由之前发布的用户继续发布;
+        order.WaitForPublisherId = publish.CreatorId;
+        await _orderRepository.UpdateAsync(order);
         return "取消成功";
     }
+
     #endregion
 
     #region 工单回访
@@ -799,7 +821,7 @@ public class OrderController : BaseController
             .WhereIF(dto.VisitStateQuery == EVisitStateQuery.Visited, d => d.VisitState == EVisitState.Visited)
             .WhereIF(dto.VisitStateQuery == EVisitStateQuery.SMSUnsatisfied, d => d.VisitState == EVisitState.SMSUnsatisfied)
             .WhereIF(dto.VisitStateQuery == EVisitStateQuery.SMSVisiting, d => d.VisitState == EVisitState.SMSVisiting)
-            .WhereIF(dto.VisitStateQuery == EVisitStateQuery.NoPutThrough , d=>d.IsPutThrough == false && d.VisitState != EVisitState.Visited)
+            .WhereIF(dto.VisitStateQuery == EVisitStateQuery.NoPutThrough, d => d.IsPutThrough == false && d.VisitState != EVisitState.Visited)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.StartsWith(dto.Keyword!))
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
             .WhereIF(dto.VisitType != null, d => d.VisitType == dto.VisitType)
@@ -922,20 +944,25 @@ public class OrderController : BaseController
         //获取系统配置智能回访语音URL头
         aiVisitVoiceBaseUrl = _systemSettingCacheManager.GetSetting(SettingConstants.AiVisitVoiceBaseUrl)?.SettingValue[0];
 
-        var histories = await _orderVisitRepository.Queryable()
-            .Includes(m => m.OrderVisitDetails)
-            .Where(m => m.OrderId == orderVisit.OrderId)
-            .Where(m => m.VisitState == EVisitState.None && m.NowEvaluate != null)
-            .Select(m => new OrderVisitDetailHistoryDto
-            {
-                VoiceEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.VoiceEvaluate).First(),
-                SeatEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.SeatEvaluate).First(),
-                VisitOrgName = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitOrgName).First(),
-                OrgProcessingResults = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgProcessingResults).First(),
-                OrgHandledAttitude = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgHandledAttitude).First(),
-                VisitContent = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitContent).First(),
-                VisitTime = m.VisitTime
-            }).ToListAsync();
+        var histories = new List<OrderVisitDetailHistoryDto>();
+        if (_appOptions.Value.IsZiGong)
+        {
+            histories = await _orderVisitRepository.Queryable()
+             .Includes(m => m.OrderVisitDetails)
+             .Where(m => m.OrderId == orderVisit.OrderId)
+             .Where(m => m.VisitState == EVisitState.None && m.NowEvaluate != null)
+             .Select(m => new OrderVisitDetailHistoryDto
+             {
+                 VoiceEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.VoiceEvaluate).First(),
+                 SeatEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.SeatEvaluate).First(),
+                 VisitOrgName = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitOrgName).First(),
+                 OrgProcessingResults = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgProcessingResults).First(),
+                 OrgHandledAttitude = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgHandledAttitude).First(),
+                 VisitContent = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitContent).First(),
+                 VisitTime = m.VisitTime,
+                 CallId = m.CallId
+             }).ToListAsync();
+        }
 
         var seat = orderVisit.OrderVisitDetails.FirstOrDefault(m => m.VisitTarget == EVisitTarget.Seat);
         if (orderVisit.VisitState == EVisitState.WaitForVisit)
@@ -1066,10 +1093,12 @@ public class OrderController : BaseController
                             VisitOrgCode = orgDetail.VisitOrgCode,
                         });
                 }
+
                 if (visitDto.CallId != null)
-                { 
+                {
                     visitDto.CallId = await _callApplication.GetOrSetCallIdAsync(visitDto.CallId, HttpContext.RequestAborted);
                 }
+
                 await _orderApplication.SaveOrderVisit(visitDto, HttpContext.RequestAborted);
                 await _orderVisitRepository.Updateable()
                     .Where(m => m.Id == visit.VisitId)
@@ -1243,22 +1272,22 @@ public class OrderController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [HttpPut("visit/put_through")]
-	public async Task VisitPutThrough([FromBody] VisitPutThroughDto dto ) {
-
-        await _orderVisitRepository.Updateable().SetColumns(x => new OrderVisit { IsPutThrough = false }).Where(x => x.Id == dto.id).ExecuteCommandAsync(HttpContext.RequestAborted);
+    public async Task VisitPutThrough([FromBody] VisitPutThroughDto dto)
+    {
+        await _orderVisitRepository.Updateable().SetColumns(x => new OrderVisit { IsPutThrough = false }).Where(x => x.Id == dto.id)
+            .ExecuteCommandAsync(HttpContext.RequestAborted);
     }
 
+    #endregion
 
-	#endregion
-
-	#region 二次回访申请
+    #region 二次回访申请
 
-	/// <summary>
-	/// 可二次回访申请列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[HttpGet("visitapply/visitagainlist")]
+    /// <summary>
+    /// 可二次回访申请列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("visitapply/visitagainlist")]
     public async Task<PagedDto<OrderCanVisitAgainDto>> OrderVisitAgainList([FromQuery] OrderVisitAgainListDto dto)
     {
         var (total, items) = await _orderVisitedDetailRepository.Queryable()
@@ -1689,32 +1718,33 @@ public class OrderController : BaseController
     {
         //var workflow = await _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted);
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
-	        cancellationToken: HttpContext.RequestAborted);
-        var currentStep = workflow.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
+            cancellationToken: HttpContext.RequestAborted);
+        var currentStep =
+            workflow.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
         if (workflow != null)
         {
-	    
-			var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId)
+            var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId)
                 .FirstAsync(HttpContext.RequestAborted);
             if (orderDelay != null)
             {
-				var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
-				if (!orderDelay.Order.IsProvince)
+                var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
+                if (!orderDelay.Order.IsProvince)
                 {
                     if (result.Steps.Any(x => x.Value == "省审批"))
                     {
                         result.Steps.Remove(result.Steps.First(x => x.Value == "省审批"));
                     }
                 }
+
                 if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审")
                 {
-	                if (result.Steps.Any(x => x.Value == "中心终审"))
-	                {
-		                result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
-	                }
+                    if (result.Steps.Any(x => x.Value == "中心终审"))
+                    {
+                        result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
+                    }
                 }
 
-				return result;
+                return result;
             }
         }
 
@@ -1792,10 +1822,10 @@ public class OrderController : BaseController
             .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
             .WhereIF(dto.DelayState != null, d => d.DelayState == dto.DelayState)
             .WhereIF(dto.DataScope is 1, x => x.CreatorId == _sessionContext.RequiredUserId)
-            .WhereIF(dto.QueryDelayState is EQueryDelayState.Examining , d=>d.DelayState == EDelayState.Examining)
+            .WhereIF(dto.QueryDelayState is EQueryDelayState.Examining, d => d.DelayState == EDelayState.Examining)
             .WhereIF(dto.QueryDelayState is EQueryDelayState.Pass, d => d.DelayState == EDelayState.Pass)
             .WhereIF(dto.QueryDelayState is EQueryDelayState.NoPass, d => d.DelayState == EDelayState.NoPass)
-			.OrderByDescending(d => d.ApplyDelayTime)
+            .OrderByDescending(d => d.ApplyDelayTime)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
         return new PagedDto<OrderDelayDto>(total, _mapper.Map<IReadOnlyList<OrderDelayDto>>(items));
@@ -1893,14 +1923,16 @@ public class OrderController : BaseController
                 result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审"));
             }
         }
-        else {
-	        if (result.Steps.Any(x => x.Value == "中心终审"))
-	        {
-		        result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
-	        }
-		}
+        else
+        {
+            if (result.Steps.Any(x => x.Value == "中心终审"))
+            {
+                result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审"));
+            }
+        }
+
         return result;
-	}
+    }
 
     /// <summary>
     /// 延期页面基础信息
@@ -1913,7 +1945,7 @@ public class OrderController : BaseController
         {
             DelayState = EnumExts.GetDescriptions<EDelayState>(),
             QueryDelayState = EnumExts.GetDescriptions<EQueryDelayState>(),
-			TimeType = EnumExts.GetDescriptions<ETimeType>()
+            TimeType = EnumExts.GetDescriptions<ETimeType>()
         };
         return rsp;
     }
@@ -1940,8 +1972,9 @@ public class OrderController : BaseController
             // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
             dto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5);
         }
-		var (total, items) = await _orderApplication.MayScreenList(dto)
-			.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+
+        var (total, items) = await _orderApplication.MayScreenList(dto)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
         return new PagedDto<OrderVisitDetailDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDetailDto>>(items));
     }
 
@@ -1952,49 +1985,49 @@ public class OrderController : BaseController
     [HttpPost("mayscreen/_export")]
     public async Task<FileStreamResult> ScreenListExport([FromBody] ExportExcelDto<MayScreenListDto> dto)
     {
-	    if (_appOptions.Value.IsYiBin) dto.QueryDto.ScreenType = EOrderScreenType.Org;
+        if (_appOptions.Value.IsYiBin) dto.QueryDto.ScreenType = EOrderScreenType.Org;
 
-	    dto.QueryDto.CreationTimeEnd = DateTime.Now;
-	    dto.QueryDto.CreationTimeStart = DateTime.Now;
-	    if (dto.QueryDto.IsHomePage != null && dto.QueryDto.IsHomePage == true)
-	    {
-		    // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
-		    dto.QueryDto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5);
-	    }
+        dto.QueryDto.CreationTimeEnd = DateTime.Now;
+        dto.QueryDto.CreationTimeStart = DateTime.Now;
+        if (dto.QueryDto.IsHomePage != null && dto.QueryDto.IsHomePage == true)
+        {
+            // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
+            dto.QueryDto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5);
+        }
 
-		var query = _orderApplication.MayScreenList(dto.QueryDto);
-	    List<OrderVisitDetail> data;
-	    if (dto.IsExportAll)
-	    {
-		    data = await query.ToListAsync(HttpContext.RequestAborted);
-	    }
-	    else
-	    {
-		    var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
-		    data = items;
-	    }
+        var query = _orderApplication.MayScreenList(dto.QueryDto);
+        List<OrderVisitDetail> data;
+        if (dto.IsExportAll)
+        {
+            data = await query.ToListAsync(HttpContext.RequestAborted);
+        }
+        else
+        {
+            var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+            data = items;
+        }
 
-	    var dataDtos = _mapper.Map<ICollection<OrderVisitDetailDto>>(data);
+        var dataDtos = _mapper.Map<ICollection<OrderVisitDetailDto>>(data);
 
-	    dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+        dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
 
-	    var dtos = dataDtos
-		    .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass))
-		    .Cast<object>()
-		    .ToList();
+        var dtos = dataDtos
+            .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass))
+            .Cast<object>()
+            .ToList();
 
-	    var stream = ExcelHelper.CreateStream(dtos);
+        var stream = ExcelHelper.CreateStream(dtos);
 
-	    return ExcelStreamResult(stream, "工单甄别待申请列表数据");
+        return ExcelStreamResult(stream, "工单甄别待申请列表数据");
     }
 
 
-	/// <summary>
-	/// 工单甄别列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[HttpGet("screen")]
+    /// <summary>
+    /// 工单甄别列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("screen")]
     public async Task<PagedDto<OrderScreenListDto>> ScreenList([FromQuery] ScreenListDto dto)
     {
         var (total, items) = await _orderApplication.OrderScreenList(dto)
@@ -2033,7 +2066,7 @@ public class OrderController : BaseController
 
         var stream = ExcelHelper.CreateStream(dtos);
 
-        return ExcelStreamResult(stream, "工单甄别列表数据");
+        return ExcelStreamResult(stream, "工单甄别数据");
     }
 
 
@@ -2192,13 +2225,15 @@ public class OrderController : BaseController
                 result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审"));
             }
         }
-        else {
-			if (result.Steps.Any(x => x.Value == "中心班长"))
-			{
-				result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
-			}
-		}
-		return result;
+        else
+        {
+            if (result.Steps.Any(x => x.Value == "中心班长"))
+            {
+                result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
+            }
+        }
+
+        return result;
     }
 
     /// <summary>
@@ -2238,11 +2273,12 @@ public class OrderController : BaseController
 
                 if (!_sessionContext.OrgIsCenter)
                 {
-					if (result.Steps.Any(x => x.Value == "中心班长"))
-					{
-						result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
-					}
-				}
+                    if (result.Steps.Any(x => x.Value == "中心班长"))
+                    {
+                        result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长"));
+                    }
+                }
+
                 return result;
             }
         }
@@ -2262,7 +2298,7 @@ public class OrderController : BaseController
             ScreenStatus = EnumExts.GetDescriptions<EScreenStatus>(),
             OrderScreenType = EnumExts.GetDescriptions<EOrderScreenType>(),
             QueryScreenType = EnumExts.GetDescriptions<EQueryOrderScreenType>(),
-			ScreenType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ScreenType),
+            ScreenType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ScreenType),
             CounterSignType = EnumExts.GetDescriptions<ECounterSignType>(),
             AcceptType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
             SourceChannel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SourceChannel),
@@ -3091,7 +3127,7 @@ public class OrderController : BaseController
                 cancellationToken: HttpContext.RequestAborted);
 
             List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto
-            { Remark = x.Remark, RemarkTime = x.HandleTime, RemarkUser = x.HandlerName }).ToList();
+                { Remark = x.Remark, RemarkTime = x.HandleTime, RemarkUser = x.HandlerName }).ToList();
             dto.OrderRemarks = remarks;
             if (order.Status == EOrderStatus.SendBack || order.Status == EOrderStatus.SendBackAudit || order.Status == EOrderStatus.BackToUnAccept)
             {
@@ -3286,7 +3322,7 @@ public class OrderController : BaseController
     [HttpPost("add-anonymous")]
     [AllowAnonymous]
     [LogFilter("省平台调用记录")]
-	public async Task<AddOrderResponse> AddAnonymous([FromBody] AddOrderDto dto)
+    public async Task<AddOrderResponse> AddAnonymous([FromBody] AddOrderDto dto)
     {
         return await _orderApplication.ReceiveOrderFromExternalAsync(dto, HttpContext.RequestAborted);
     }
@@ -3600,14 +3636,14 @@ public class OrderController : BaseController
         BasicWorkflowDto workflowDto, CancellationToken cancellationToken)
     {
         var isAutoFillSummaryOpinion = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsAutoFillSummaryOpinion).SettingValue[0]);
-        
+
         switch (orderHandleFlowDto.OrderAssignMode)
         {
             case EOrderAssignMode.AdjoinLevel:
                 var nextDto = _mapper.Map<NextWorkflowDto>(workflowDto);
                 nextDto.WorkflowId = startStep.WorkflowId;
                 nextDto.StepId = startStep.Id;
-                
+
                 if (workflowDto.BusinessType == EBusinessType.Send)
                 {
                     // 宜宾需求: 1.是否是派单节点  2.是否存在历史派单节点  3.存在获取上个派单节点  4.不存在走平均派单 
@@ -3640,7 +3676,7 @@ public class OrderController : BaseController
                     }
                 }
 
-                await _workflowDomainService.NextAsync(_sessionContext, nextDto, order.ExpiredTime,isAutoFillSummaryOpinion, cancellationToken);
+                await _workflowDomainService.NextAsync(_sessionContext, nextDto, order.ExpiredTime, isAutoFillSummaryOpinion, cancellationToken);
                 break;
             case EOrderAssignMode.CrossLevel:
                 if (!orderHandleFlowDto.CrossSteps.Any())
@@ -3649,7 +3685,7 @@ public class OrderController : BaseController
                 orderHandleFlowDto.CrossSteps = orderHandleFlowDto.CrossSteps.OrderBy(d => d.Sort).ToList();
                 var stepCount = orderHandleFlowDto.CrossSteps.Count;
                 var unhandleSteps = new List<WorkflowStep> { startStep };
-                for (int i = 0; i < stepCount; i++)
+                for (int i = 0;i < stepCount;i++)
                 {
                     var crossStep = orderHandleFlowDto.CrossSteps[i];
                     var tempSteps = new List<WorkflowStep>();
@@ -3845,7 +3881,7 @@ public class OrderController : BaseController
             IdentityTypeOptions = EnumExts.GetDescriptions<EIdentityType>(),
             OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag),
             FocusOnEvents = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.FocusOnEvent)
-    };
+        };
         return rsp;
     }
 
@@ -3960,21 +3996,31 @@ public class OrderController : BaseController
     }
 
     /// <summary>
-    /// 批量归档
+    /// 批量归档(暂时只支持派单组节点操作)
     /// </summary>
     /// <returns>成功总量</returns>
     [HttpPost("batch-file")]
-    public async Task<string> BatchFile([FromBody]OrderBatchFileDto dto)
+    public async Task<string> BatchFile([FromBody] OrderBatchFileDto dto)
     {
         var orders = await _orderRepository.Queryable()
-            .Includes(w=>w.Workflow,d => d.WorkflowDefinition)
-            .Includes(w=>w.Workflow,d => d.Steps)
-            .Includes(w=>w.Workflow,d => d.Traces)
+            .Includes(w => w.Workflow, d => d.WorkflowDefinition)
+            .Includes(w => w.Workflow, d => d.Steps)
+            .Includes(w => w.Workflow, d => d.Traces)
+            .Includes(w => w.Workflow, d => d.Countersigns)
             .Where(d => dto.OrderIds.Contains(d.Id))
             .ToListAsync(HttpContext.RequestAborted);
         var success = 0;
         foreach (var order in orders)
         {
+            //非派单组节点办理时不允许操作
+            var unhandleSteps = order.Workflow.Steps
+                .Where(d => d.Status != EWorkflowStepStatus.Handled)
+                .ToList();
+            if (unhandleSteps.Count == 0
+                || unhandleSteps.Count > 2
+                || unhandleSteps.First().BusinessType != EBusinessType.Send)
+                continue;
+
             var startStep = order.Workflow.Steps.Where(d => d.StepType == EStepType.Start && d.IsOrigin)
                 .MaxBy(d => d.CreationTime);
             if (startStep?.Status is not EWorkflowStepStatus.Handled || string.IsNullOrEmpty(startStep.Opinion))
@@ -4023,8 +4069,9 @@ public class OrderController : BaseController
             .WhereIF(dto.QueryType is 3,
                 d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.SpecialType == ESpecialType.ReTransact).Any())
             .Where(d => SqlFunc.Subqueryable<OrderDelay>().Where(od => od.OrderId == d.Id && od.DelayState == EDelayState.Examining).NotAny())
-            .Where(d => SqlFunc.Subqueryable<OrderSendBackAudit>().Where(osba => osba.OrderId == d.Id && osba.State == ESendBackAuditState.Apply).NotAny())
-			.WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
+            .Where(d => SqlFunc.Subqueryable<OrderSendBackAudit>().Where(osba => osba.OrderId == d.Id && osba.State == ESendBackAuditState.Apply)
+                .NotAny())
+            .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword))
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
             .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode)
@@ -4043,9 +4090,9 @@ public class OrderController : BaseController
             .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
             .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
             .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
-            .OrderByDescending(d=> d.IsUrgent)
-            .OrderByIF(string.IsNullOrEmpty(dto.SortField),d => d.StartTime ,OrderByType.Desc)
-            .OrderByIF(dto is { SortField: "creationTime", SortRule:0 },d=> d.CreationTime,OrderByType.Asc) //创建时间升序
+            .OrderByDescending(d => d.IsUrgent)
+            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.StartTime, OrderByType.Desc)
+            .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.CreationTime, OrderByType.Asc) //创建时间升序
             .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, d => d.CreationTime, OrderByType.Desc) //创建时间降序
             .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序
             .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序
@@ -4140,7 +4187,7 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName == dto.CenterToOrgHandlerName)
             .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
             .OrderBy(d => d.Status)
-            .OrderByIF(string.IsNullOrEmpty(dto.SortField),d => d.CreationTime, OrderByType.Desc)
+            .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc)
             .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序
             .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序
             .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //期满时间升序
@@ -4269,7 +4316,7 @@ public class OrderController : BaseController
             .FirstAsync(d => d.Id == workflow.ExternalId);
         var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
             dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted);
-		var audit = new OrderSendBackAudit
+        var audit = new OrderSendBackAudit
         {
             OrderId = workflow.ExternalId,
             State = ESendBackAuditState.Apply,
@@ -4390,22 +4437,24 @@ public class OrderController : BaseController
         //执行退回
         if (sendBack.State == ESendBackAuditState.End)
         {
-	        var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
-			if (_appOptions.Value.IsZiGong)
-	        {
-				var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-					order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), HttpContext.RequestAborted);
-				if (prevStep.BusinessType == EBusinessType.Send)
-		        {
-					// 平均派单
-					var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
-					if (averageSendOrder)
-					{
-						var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-						sendBack.SendBackData.Handler = handler;
-					}
-				}
-	        }
+            var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
+            if (_appOptions.Value.IsZiGong)
+            {
+                var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
+                    order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
+                    HttpContext.RequestAborted);
+                if (prevStep.BusinessType == EBusinessType.Send)
+                {
+                    // 平均派单
+                    var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                    if (averageSendOrder)
+                    {
+                        var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                        sendBack.SendBackData.Handler = handler;
+                    }
+                }
+            }
+
             //string applicantId, string applicantOrgId, string[] applicantRoleIds,
             //    ISessionContext current, CancellationToken cancellationToken);
             sendBack.SendBackData.ExpiredTime = order.ExpiredTime;
@@ -4458,23 +4507,24 @@ public class OrderController : BaseController
             //执行退回
             if (sendBack.State == ESendBackAuditState.End)
             {
-	            var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
-				if (_appOptions.Value.IsZiGong)
-	            {
-					var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
-						order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), HttpContext.RequestAborted);
-					if (prevStep.BusinessType == EBusinessType.Send)
-					{
-						// 平均派单
-						var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
-						if (averageSendOrder)
-						{
-							var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-							sendBack.SendBackData.Handler = handler;
-						}
-					}
-				}
-				
+                var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId);
+                if (_appOptions.Value.IsZiGong)
+                {
+                    var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync(
+                        order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
+                        HttpContext.RequestAborted);
+                    if (prevStep.BusinessType == EBusinessType.Send)
+                    {
+                        // 平均派单
+                        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                        if (averageSendOrder)
+                        {
+                            var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                            sendBack.SendBackData.Handler = handler;
+                        }
+                    }
+                }
+
                 sendBack.SendBackData.ExpiredTime = order.ExpiredTime;
                 var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData,
                     sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(),
@@ -4805,26 +4855,27 @@ public class OrderController : BaseController
             .AnyAsync();
         if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息!");
         var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == dto.OrderId);
-		await _orderApplication.SpecialVerify(dto, order, HttpContext.RequestAborted);
-		if (string.IsNullOrEmpty(dto.Cause))
-		{
-			dto.Cause = dto.Reason;
-		}
+        await _orderApplication.SpecialVerify(dto, order, HttpContext.RequestAborted);
+        if (string.IsNullOrEmpty(dto.Cause))
+        {
+            dto.Cause = dto.Reason;
+        }
 
-		var  workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: HttpContext.RequestAborted);
+        var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true,
+            cancellationToken: HttpContext.RequestAborted);
         var currentStep = workflow.Steps.FirstOrDefault(x => x.Status != EWorkflowStepStatus.Handled);
         if (currentStep is null)
-	        currentStep = workflow.Steps.OrderByDescending(x => x.CreationTime).FirstOrDefault(x => x.StepType == EStepType.End);
+            currentStep = workflow.Steps.OrderByDescending(x => x.CreationTime).FirstOrDefault(x => x.StepType == EStepType.End);
 
-		if (string.IsNullOrEmpty(dto.Cause))
-		{
-			dto.Cause = dto.Reason;
-		}
+        if (string.IsNullOrEmpty(dto.Cause))
+        {
+            dto.Cause = dto.Reason;
+        }
 
-		var model = _mapper.Map<OrderSpecial>(dto);
-        model.OrgId = currentStep is null ? _sessionContext.RequiredOrgId: currentStep.HandlerOrgId;
+        var model = _mapper.Map<OrderSpecial>(dto);
+        model.OrgId = currentStep is null ? _sessionContext.RequiredOrgId : currentStep.HandlerOrgId;
         model.OrgName = currentStep is null ? _sessionContext.OrgName : currentStep.HandlerOrgName;
-		var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
+        var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
         model.StepName = step.Name;
         model.StepCode = step.Code;
         model.Status = order.Status;
@@ -4924,13 +4975,13 @@ public class OrderController : BaseController
             //	ETimeType.WorkDay,
             //	dto.TimeLimit.Value, order.AcceptTypeCode);
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-            {
-                ExpiredTime = expiredTime.ExpiredTime,
-                NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                ProcessType = processType,
-                Status = EOrderStatus.Special
-            })
+                {
+                    ExpiredTime = expiredTime.ExpiredTime,
+                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                    ProcessType = processType,
+                    Status = EOrderStatus.Special
+                })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -4995,12 +5046,12 @@ public class OrderController : BaseController
     }
 
 
-	/// <summary>
-	/// 工单重办信息
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[HttpPost("re_transact")]
+    /// <summary>
+    /// 工单重办信息
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPost("re_transact")]
     [LogFilter("工单重办")]
     public async Task Add([FromBody] OrderReTransactDto dto)
     {
@@ -5025,14 +5076,15 @@ public class OrderController : BaseController
 
         var model = _mapper.Map<OrderSpecial>(dto);
 
-        var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, cancellationToken: HttpContext.RequestAborted);
+        var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true,
+            cancellationToken: HttpContext.RequestAborted);
         var currentStep = workflow.Steps.FirstOrDefault(x => x.Status != EWorkflowStepStatus.Handled);
         if (currentStep is null)
-	        currentStep = workflow.Steps.OrderByDescending(x => x.CreationTime).FirstOrDefault(x => x.StepType == EStepType.End);
+            currentStep = workflow.Steps.OrderByDescending(x => x.CreationTime).FirstOrDefault(x => x.StepType == EStepType.End);
 
         model.OrgId = currentStep is null ? _sessionContext.RequiredOrgId : currentStep.HandlerOrgId;
         model.OrgName = currentStep is null ? _sessionContext.OrgName : currentStep.HandlerOrgName;
-		var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
+        var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted);
         model.StepName = step.Name;
         model.StepCode = step.Code;
         model.State = 1;
@@ -5062,18 +5114,18 @@ public class OrderController : BaseController
 
         if (model.State == 1)
         {
-	        if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
-	        {
-		        // 平均派单
-		        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
-		        if (averageSendOrder)
-		        {
-			        var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-			        dto.NextHandlers = new List<FlowStepHandler> { handler };
-		        }
-	        }
-
-			var recall = new RecallDto
+            if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
+            {
+                // 平均派单
+                var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                if (averageSendOrder)
+                {
+                    var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                    dto.NextHandlers = new List<FlowStepHandler> { handler };
+                }
+            }
+
+            var recall = new RecallDto
             {
                 WorkflowId = dto.WorkflowId!,
                 NextStepCode = dto.NextStepCode,
@@ -5103,11 +5155,11 @@ public class OrderController : BaseController
 
                 endTime = expiredTime.EndTime;
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-                {
-                    ExpiredTime = expiredTime.EndTime,
-                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne
-                })
+                    {
+                        ExpiredTime = expiredTime.EndTime,
+                        NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                        NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne
+                    })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5190,17 +5242,18 @@ public class OrderController : BaseController
         var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId);
         if (special.State == 1)
         {
-	        if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
-	        {
-		        // 平均派单
-		        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
-		        if (averageSendOrder)
-		        {
-			        var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-			        dto.NextHandlers = new List<FlowStepHandler> { handler };
-		        }
-	        }
-			var recall = new RecallDto
+            if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send)
+            {
+                // 平均派单
+                var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                if (averageSendOrder)
+                {
+                    var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                    dto.NextHandlers = new List<FlowStepHandler> { handler };
+                }
+            }
+
+            var recall = new RecallDto
             {
                 WorkflowId = special.WorkflowId!,
                 NextStepCode = special.NextStepCode,
@@ -5237,6 +5290,7 @@ public class OrderController : BaseController
                     expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
                 }
             }
+
             if (expiredTime.ExpiredTime < order.ExpiredTime)
             {
                 expiredTime.ExpiredTime = order.ExpiredTime.Value;
@@ -5248,13 +5302,13 @@ public class OrderController : BaseController
                 ? EProcessType.Zhiban
                 : EProcessType.Jiaoban;
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-            {
-                ExpiredTime = expiredTime.ExpiredTime,
-                NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                ProcessType = processType,
-                Status = EOrderStatus.Special
-            })
+                {
+                    ExpiredTime = expiredTime.ExpiredTime,
+                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                    ProcessType = processType,
+                    Status = EOrderStatus.Special
+                })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5372,23 +5426,25 @@ public class OrderController : BaseController
                         expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
                     }
                 }
+
                 if (expiredTime.ExpiredTime < order.ExpiredTime)
                 {
                     expiredTime.ExpiredTime = order.ExpiredTime.Value;
                     expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
                     expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
                 }
+
                 var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                     ? EProcessType.Zhiban
                     : EProcessType.Jiaoban;
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-                {
-                    ExpiredTime = expiredTime.ExpiredTime,
-                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                    ProcessType = processType,
-                    Status = EOrderStatus.Special
-                })
+                    {
+                        ExpiredTime = expiredTime.ExpiredTime,
+                        NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                        NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                        ProcessType = processType,
+                        Status = EOrderStatus.Special
+                    })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5531,7 +5587,7 @@ public class OrderController : BaseController
                 d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
-                                                                                                     //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
+            //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel) //来源渠道
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
@@ -7270,7 +7326,7 @@ public class OrderController : BaseController
         {
             await _orderRepository.Updateable()
                 .SetColumns(o => new Orders.Order()
-                { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept })
+                    { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept })
                 .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
         }
         else

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

@@ -828,6 +828,7 @@ namespace Hotline.Api.Controllers
                     var orderPublish = await _orderPublishRepository.GetAsync(p => p.OrderId == data.Id, HttpContext.RequestAborted);
                     if (orderPublish != null)
                     {
+                        orderDetail.PubFlag = "1";
                         orderDetail.FlowTitle = orderPublish.ArrangeTitle;
                         orderDetail.FlowContent = orderPublish.ArrangeContent;
                         orderDetail.FlowResult = orderPublish.ArrangeOpinion;

+ 34 - 3
src/Hotline.Application.Tests/Controller/OrderControllerTest.cs

@@ -15,6 +15,7 @@ using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos.File;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Order.Publish;
 using Hotline.Share.Dtos.Users;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
@@ -34,6 +35,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 
 namespace Hotline.Application.Tests.Controller;
@@ -205,8 +207,37 @@ public class OrderControllerTest : TestBase
         await _orderController.PublishCancelAsync(new PublishCancelInDto { OrderPublishId = publish.Id });
         var visit = await _orderVisitRepository.GetAsync(m => m.OrderId == order.Id);
         var publishCount = await _orderPublishRepository.Queryable().Where(m => m.OrderId == order.Id && m.IsDeleted == false).CountAsync();
-        publishCount.ShouldBe(0);
-        visit.ShouldNotBeNull();
-        visit.VisitState.ShouldBe(EVisitState.Visited);
+        publishCount.ShouldBe(0, "发布工单数据已经被删除, 应该是0条");
+        visit.ShouldNotBeNull("回访信息不存在");
+        visit.VisitState.ShouldBe(EVisitState.Visited, "回访状态应该是已回访");
+
+        orderEntity = await _orderRepository.GetAsync(order.Id);
+        orderEntity.Status.ShouldBe(EOrderStatus.Filed);
+        var publishList = await _orderController.PublishOrderList(new QueryOrderPublishDto 
+        {
+            PageSize = 1000,
+            QuerySelf = true
+        });
+
+        publishList.Items.Any(m => m.Id == order.Id).ShouldBeTrue("工单发布列表中没有取消的工单");
+        SetZuoXi();
+        // 验证是否能非上次发布人员发布
+        try
+        {
+            await _orderController.PublishOrder(new PublishOrderDto { Id = order.Id });
+        }
+        catch (UserFriendlyException e)
+        {
+            e.Message.Contains("您不能发布").ShouldBeTrue();
+        }
+
+        // 验证被取消前的发布人能否继续发布
+        SetPaiDanYuan();
+        var inDto = _fixture.Create<PublishOrderDto>();
+        inDto.Id = order.Id;
+        await _orderController.PublishOrder(inDto);
+        var published = await _orderPublishRepository.Queryable().Where(m => m.OrderId == order.Id && m.IsDeleted == false).FirstAsync();
+        published.ShouldNotBeNull();
+        published.IsDeleted.ShouldBeFalse();
     }
 }

+ 1 - 0
src/Hotline.Application.Tests/Infrastructure/TestSettingConstants.cs

@@ -7,6 +7,7 @@ using System.Threading.Tasks;
 namespace Hotline.Application.Tests.Infrastructure;
 public static class TestSettingConstants
 {
+    public const string ZuoXiAccountName = "UnitTestZuoXi";
     public const string PaiDanYuanAccountName = "UnitTestPDY";
     public const string FirstOrgAccountName = "cs";
     public const string SecondOrgAccountName = "cs21";

+ 1 - 1
src/Hotline.Application.Tests/TestBase.cs

@@ -58,7 +58,7 @@ public class TestBase
 
     public void SetZuoXi()
     {
-        SetOperator("坐席", "市民热线服务中心", "单元测试派单员", "001", "13408389849", EUserType.Seat, TestSettingConstants.PaiDanYuanAccountName);
+        SetOperator("坐席", "市民热线服务中心", "单元测试坐席", "001", "13408389849", EUserType.Seat, TestSettingConstants.ZuoXiAccountName);
     }
 
     private void SetOperator(string displayName, string fullOrgName, string name, string orgId, string phoneNo, EUserType userType, string userName)

+ 1 - 0
src/Hotline.Application/Mappers/WorkflowMapperConfigs.cs

@@ -44,6 +44,7 @@ public class WorkflowMapperConfigs : IRegister
             ;
 
         config.ForType<WorkflowStep, WorkflowTrace>()
+            .Ignore(d=>d.Workflow)
             .Ignore(d => d.ParentId)
             .Ignore(d => d.TraceType)
             .Map(d => d.StepId, s => s.Id)

+ 50 - 38
src/Hotline.Application/Orders/OrderApplication.cs

@@ -114,8 +114,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<OrderObserve> _orderObserveRepository;
     private readonly IOrderTerminateRepository _orderTerminateRepository;
     private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
+    private readonly IOrderDelayRepository _orderDelayRepository;
 
-    public OrderApplication(
+	public OrderApplication(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         IWorkflowDomainService workflowDomainService,
@@ -151,7 +152,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IRepository<TranspondCityRawData> transpondCityRawDataRepository,
         IRepository<OrderObserve> orderObserveRepository,
         IOrderTerminateRepository orderTerminateRepository,
-        IRepository<OrderPublishHistory> orderPublishHistoryRepository)
+        IRepository<OrderPublishHistory> orderPublishHistoryRepository,
+        IOrderDelayRepository orderDelayRepository)
     {
         _orderDomainService = orderDomainService;
         _workflowDomainService = workflowDomainService;
@@ -189,7 +191,9 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _orderTerminateRepository = orderTerminateRepository;
         _orderPublishHistoryRepository = orderPublishHistoryRepository;
         _sessionContext = sessionContext;
-    }
+        _orderDelayRepository = orderDelayRepository;
+
+	}
 
     /// <summary>
     /// 更新工单办理期满时间(延期调用,其他不调用)
@@ -2561,37 +2565,44 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var screen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == dto.OrderId && (int)x.Status < 2).ToListAsync(cancellationToken);
         //var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == dto.OrderId);
         var sendBackAudit = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == ESendBackAuditState.Apply).ToListAsync(cancellationToken);
-        //if (_appOptions.Value.IsYiBin)
-        //{
-        //	if (screen.Any())
-        //	{
-        //		_orderScreenRepository.RemoveRangeAsync(screen, true, cancellationToken);
-        //	}
-
-        //	if (sendBackAudit.Any())
-        //	{
-        //		_orderSendBackAuditRepository.RemoveRangeAsync(sendBackAudit, true, cancellationToken);
-        //	}
-
-        //	if (order.Workflow.IsInCountersign)
-        //	{
-        //		var workflowStep = await _workflowStepRepository.Queryable().Where(x => x.Id == order.Workflow.TopCountersignStepId).FirstAsync(cancellationToken);
-        //		if (workflowStep != null)
-        //		{
-        //			var dtoEnd = new EndCountersignDto() { CountersignId = workflowStep.StartCountersignId };
-        //			await EndCountersign(dtoEnd,cancellationToken);
-        //		}
-        //	}
-        //}
-        //else
-        //{
-        if (screen.Any()) throw UserFriendlyException.SameMessage("工单存在甄别中的信息!");
+        var orderDelay = await _orderDelayRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.DelayState == EDelayState.Examining).ToListAsync(cancellationToken);
 
-        if (sendBackAudit.Any())
-            throw UserFriendlyException.SameMessage("该工单存在正在审核中的退回,不能办理");
+		if (_appOptions.Value.IsYiBin)
+        {
+            if (screen.Any())
+            {
+               await  _orderScreenRepository.RemoveRangeAsync(screen, true, cancellationToken);
+            }
 
-        if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行特提!");
-        //}
+            if (sendBackAudit.Any())
+            {
+               await _orderSendBackAuditRepository.RemoveRangeAsync(sendBackAudit, true, cancellationToken);
+            }
+
+            if (orderDelay.Any())
+            {
+                await _orderDelayRepository.RemoveRangeAsync(orderDelay, true, cancellationToken);
+            }
+
+            if (order.Workflow.IsInCountersign)
+            {
+                var workflowStep = await _workflowStepRepository.Queryable().Where(x => x.Id == order.Workflow.TopCountersignStepId).FirstAsync(cancellationToken);
+                if (workflowStep != null)
+                {
+                    var dtoEnd = new EndCountersignDto() { CountersignId = workflowStep.StartCountersignId };
+                    await EndCountersign(dtoEnd, cancellationToken);
+                }
+            }
+        }
+        else
+        {
+            if (screen.Any()) throw UserFriendlyException.SameMessage("工单存在甄别中的信息!");
+
+            if (sendBackAudit.Any())
+                throw UserFriendlyException.SameMessage("该工单存在正在审核中的退回,不能办理");
+
+            if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行特提!");
+        }
     }
 
     public async Task EndCountersign(EndCountersignDto dto, CancellationToken cancellationToken)
@@ -2700,7 +2711,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             }
 
             _mapper.Map(expiredTimeConfig, order);
-            await _orderRepository.UpdateAsync(order, cancellationToken);
+            //await _orderRepository.UpdateAsync(order, cancellationToken);
             //特提(撤回至发起)
             if (!string.IsNullOrEmpty(order.WorkflowId))
             {
@@ -2721,13 +2732,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                     order.ExpiredTime, nextHandler, cancellationToken);
                 order.FileEmpty();
 
-                var status = EOrderStatus.WaitForAccept;
+                order.Status = EOrderStatus.WaitForAccept;
                 if (isPaiDan)
                 {
-	                status = EOrderStatus.Handling;
+	                order.Status = EOrderStatus.Handling;
                 }
-                await _orderRepository.Updateable().SetColumns(o => new Order { Status = status }).Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
-                //await _orderRepository.UpdateAsync(order, cancellationToken);
+                //await _orderRepository.Updateable().SetColumns(o => new Order { Status = status }).Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
+                
                 //处理回访和发布信息
 
                 var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == order.Id);
@@ -2753,9 +2764,10 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 }
 
             }
+            await _orderRepository.UpdateAsync(order, cancellationToken);
             //await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, "省工单重派", current, cancellationToken);
         }
-        return _mapper.Map<AddOrderResponse>(order);
+		return _mapper.Map<AddOrderResponse>(order);
     }
 
     /// <summary>

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

@@ -937,6 +937,11 @@ namespace Hotline.Share.Dtos.Order
         public string? OrgHandledAttitudeValue => this.OrgHandledAttitude?.Value;
         public string? VisitContent { get; set; }
         public DateTime? VisitTime { get; set; }
+
+        /// <summary>
+        /// 通话Id
+        /// </summary>
+        public string? CallId { get; set; }
     }
 
     public class DistributionVisitRspDto

+ 3 - 0
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -369,6 +369,9 @@ public abstract class StepBasicEntity : CreationEntity
     #endregion
     #endregion
 
+    [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
+    public Workflow Workflow { get; set; }
+    
     #region method
 
     /// <summary>

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

@@ -387,18 +387,16 @@ public partial class Workflow
     public List<WorkflowCountersign> Countersigns { get; set; }
 
     /// <summary>
-    /// 节点,依据流转进度动态生成或删除
+    /// 节点,依据流转进度动态生成或删除
     /// </summary>
-    //[SugarColumn(IsIgnore = true)]
     [Navigate(NavigateType.OneToMany, nameof(WorkflowStep.WorkflowId))]
     public List<WorkflowStep> Steps { get; set; }
 
     /// <summary>
     /// 流转记录
     /// </summary>
-    //[SugarColumn(IsIgnore = true)]
     [Navigate(NavigateType.OneToMany, nameof(WorkflowTrace.WorkflowId))]
-    public List<WorkflowTrace> Traces { get; set; } = new();
+    public List<WorkflowTrace> Traces { get; set; }
 
     #region Method
 

+ 2 - 19
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -543,22 +543,13 @@ namespace Hotline.FlowEngine.Workflows
                 query = query.Includes(d => d.Countersigns, x => x.Members);
             if (withSteps)
                 query = query.Includes(d => d.Steps);
-            //if (withTraces)
-            //    query = query.Includes(d => d.Traces);
+            if (withTraces)
+                query = query.Includes(d => d.Traces);
 
             var workflow = await query.FirstAsync(cancellationToken);
             if (workflow is null)
                 throw new UserFriendlyException("无效workflowId");
 
-            //if (withSteps)
-            //{
-            //    var steps = await _workflowStepRepository.Queryable()
-            //        .Where(d => d.WorkflowId == workflow.Id)
-            //        .OrderBy(d => d.CreationTime)
-            //        .ToTreeAsync(d => d.Steps, d => d.ParentId, null);
-            //    workflow.Steps = steps;
-            //}
-
             if (withTracesTree)
             {
                 workflow.Traces = await _workflowTraceRepository.Queryable()
@@ -567,14 +558,6 @@ namespace Hotline.FlowEngine.Workflows
                     .ToTreeAsync(d => d.Traces, d => d.ParentId, null);
             }
 
-            if (withTraces)
-            {
-                workflow.Traces = await _workflowTraceRepository.Queryable()
-                    .Where(d => d.WorkflowId == workflow.Id)
-                    .OrderBy(d => d.CreationTime)
-                    .ToListAsync(cancellationToken);
-            }
-
             return workflow;
         }
 

+ 2 - 8
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -12,16 +12,10 @@ namespace Hotline.FlowEngine.Workflows;
 
 public class WorkflowStep : StepBasicEntity
 {
-    [Navigate(NavigateType.ManyToOne, nameof(WorkflowId))]
-    public Workflow Workflow { get; set; }
-
-    [Navigate(NavigateType.OneToOne, nameof(Id),
+   [Navigate(NavigateType.OneToOne, nameof(Id),
         nameof(Workflows.WorkflowTrace.StepId))]
     public WorkflowTrace WorkflowTrace { get; set; }
-
-    //[Navigate(NavigateType.OneToMany, nameof(WorkflowStepHandler.WorkflowStepId))]
-    //public List<WorkflowStepHandler> StepHandlers { get; set; }
-
+    
     #region Method
 
     /// <summary>