Bläddra i källkod

Merge branch 'release/yibin' of http://git.12345lm.cn/Fengwo/hotline into release/yibin

Dun.Jason 9 månader sedan
förälder
incheckning
d54613005b

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

@@ -689,6 +689,7 @@ namespace Hotline.Api.Controllers
                                 aiOrderVisitDetail.OrderVisit.VisitTime = DateTime.Now;
                                 aiOrderVisitDetail.OrderVisit.RecordUrl = recordUrl;
                                 aiOrderVisitDetail.OrderVisit.IsPutThrough = true;
+                                aiOrderVisitDetail.OrderVisit.RecordUrl = recordUrl;
                                 aiOrderVisitDetail.OrderVisit.VisitType = Share.Enums.Order.EVisitType.ChipVoiceVisit;
                                 aiOrderVisitDetail.OrderVisit.AiVisitTime();
                                 aiOrderVisitDetail.IsSuccess = true;

+ 38 - 38
src/Hotline.Api/Controllers/CommonPController.cs

@@ -22,7 +22,7 @@ namespace Hotline.Api.Controllers
     /// <summary>
     /// 常用意见接口
     /// </summary>
-    public class CommonPController: BaseController
+    public class CommonPController : BaseController
     {
         private readonly ISystemCommonOpinionDomainService _commonOpinionDomainService;
         private readonly ISystemAreaDomainService _systemAreaDomainService;
@@ -35,20 +35,20 @@ namespace Hotline.Api.Controllers
         private readonly IOrderScreenRepository _orderScreenRepository;
         private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
 
-		public CommonPController(
+        public CommonPController(
             ISystemCommonOpinionDomainService commonOpinionDomainService,
             ISystemAreaDomainService systemAreaDomainService,
             ISessionContext sessionContext,
             IRepository<TrCallRecord> trCallRecordRepository,
             IOrderRepository orderRepository,
-			IMapper mapper,
+            IMapper mapper,
             IOrderDelayRepository orderDelayRepository,
             ITimeLimitDomainService timeLimitDomainService,
             IOrderScreenRepository orderScreenRepository,
             IRepository<OrderVisitDetail> orderVisitedDetailRepository)
         {
             _commonOpinionDomainService = commonOpinionDomainService;
-            _systemAreaDomainService= systemAreaDomainService;
+            _systemAreaDomainService = systemAreaDomainService;
             _mapper = mapper;
             _sessionContext = sessionContext;
             _trCallRecordRepository = trCallRecordRepository;
@@ -56,10 +56,10 @@ namespace Hotline.Api.Controllers
             _orderDelayRepository = orderDelayRepository;
             _timeLimitDomainService = timeLimitDomainService;
             _orderScreenRepository = orderScreenRepository;
-            _orderVisitedDetailRepository= orderVisitedDetailRepository;
-		}
+            _orderVisitedDetailRepository = orderVisitedDetailRepository;
+        }
+
 
-       
 
         #region 省市区
         /// <summary>
@@ -80,34 +80,34 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("home_data")]
-        public async Task<Object> GetHomeData() 
+        public async Task<Object> GetHomeData()
         {
             var tadayTime = DateTime.Now.ToString("yyyy-MM-dd");
-			//中心
-			if (_sessionContext.OrgIsCenter)
-	        {
-		        var orderQuery = _orderRepository.Queryable(false, false, false)
-			        .Includes(o => o.Workflow, w => w.Steps);
-				//今日来电
-				var tadayCalls = await _trCallRecordRepository.Queryable()
-	                .Where(x => x.CallDirection == Share.Enums.CallCenter.ECallDirection.In && tadayTime.Equals(x.CreatedTime.ToString("yyyy-MM-dd"))).ToListAsync();
-				var callNum = tadayCalls.Count();
+            //中心
+            if (_sessionContext.OrgIsCenter)
+            {
+                var orderQuery = _orderRepository.Queryable(false, false, false)
+                    .Includes(o => o.Workflow, w => w.Steps);
+                //今日来电
+                var tadayCalls = await _trCallRecordRepository.Queryable()
+                    .Where(x => x.CallDirection == Share.Enums.CallCenter.ECallDirection.In && tadayTime.Equals(x.CreatedTime.ToString("yyyy-MM-dd"))).ToListAsync();
+                var callNum = tadayCalls.Count();
                 var validCallNum = tadayCalls.Where(x => x.Duration > 0 || x.QueueTims > 0 || x.RingTimes > 0).Count();
-				//今日接通率
-                var answeredNum = tadayCalls.Where(x=>x.Duration > 0).Count();
-				var answeredRate = validCallNum > 0 ? Math.Round((double.Parse(answeredNum.ToString()) / double.Parse(validCallNum.ToString())) * 100, 2) + "%" : "-";
-				//今日受理工单
-				var tadayOrders = await orderQuery
-	                .Where(o => tadayTime.Equals(o.CreationTime.ToString("yyyy-MM-dd"))).ToListAsync();
-				var orderNum = tadayOrders.Count();
-				var directlyNum = tadayOrders.Where(o=> o.ProcessType == Share.Enums.Order.EProcessType.Zhiban).Count();
+                //今日接通率
+                var answeredNum = tadayCalls.Where(x => x.Duration > 0).Count();
+                var answeredRate = validCallNum > 0 ? Math.Round((double.Parse(answeredNum.ToString()) / double.Parse(validCallNum.ToString())) * 100, 2) + "%" : "-";
+                //今日受理工单
+                var tadayOrders = await orderQuery
+                    .Where(o => tadayTime.Equals(o.CreationTime.ToString("yyyy-MM-dd"))).ToListAsync();
+                var orderNum = tadayOrders.Count();
+                var directlyNum = tadayOrders.Where(o => o.ProcessType == Share.Enums.Order.EProcessType.Zhiban).Count();
                 return new { CallNum = callNum, ValidCallNum = validCallNum, AnsweredNum = answeredNum, AnsweredRate = answeredRate, OrderNum = orderNum, DirectlyNum = directlyNum };
-			}
+            }
             //部门
             //今日待办 tasksOkNum
             //var time = DateTime.Parse(tadayTime);
             //工单
-			var order = await _orderRepository.Queryable()
+            var order = await _orderRepository.Queryable()
                .Where(o => SqlFunc.JsonListObjectAny(o.HandlerUsers, "Key", _sessionContext.RequiredUserId) || SqlFunc.JsonListObjectAny(o.HandlerOrgs, "Key", _sessionContext.RequiredOrgId))
                .GroupBy(o => o.Id).MergeTable()
                .Select(o => new
@@ -116,32 +116,32 @@ namespace Hotline.Api.Controllers
                    havExpired = SqlFunc.AggregateSum(SqlFunc.IIF(DateTime.Now > o.ExpiredTime!.Value, 1, 0)),
                    countersignHandle = SqlFunc.AggregateSum(SqlFunc.IIF(o.CounterSignType.HasValue, 1, 0)),
 
-			   }).FirstAsync();
+               }).FirstAsync();
             var aboutExpire = order?.aboutExpire ?? 0;
             var havExpired = order?.havExpired ?? 0;
             var countersignHandle = order?.countersignHandle ?? 0;
             //延期
             var delay = await _orderDelayRepository.Queryable()
-                .Includes(x=>x.Workflow)
-                .Where(x=> SqlFunc.JsonListObjectAny(x.HandlerUsers, "Key", _sessionContext.RequiredUserId) || SqlFunc.JsonListObjectAny(x.HandlerOrgs, "Key", _sessionContext.RequiredOrgId))
+                .Includes(x => x.Workflow)
+                .Where(x => SqlFunc.JsonListObjectAny(x.HandlerUsers, "Key", _sessionContext.RequiredUserId) || SqlFunc.JsonListObjectAny(x.HandlerOrgs, "Key", _sessionContext.RequiredOrgId))
                 .Where(x => x.DelayState == EDelayState.Examining).CountAsync();
             //甄别
             var screenAudit = await _orderScreenRepository.Queryable()
-                .Includes(x=>x.Workflow)
-				 .Where(x => SqlFunc.JsonListObjectAny(x.HandlerUsers, "Key", _sessionContext.RequiredUserId) || SqlFunc.JsonListObjectAny(x.HandlerOrgs, "Key", _sessionContext.RequiredOrgId))
-				.Where(x =>  x.Status == EScreenStatus.Apply)
+                .Includes(x => x.Workflow)
+                 .Where(x => SqlFunc.JsonListObjectAny(x.HandlerUsers, "Key", _sessionContext.RequiredUserId) || SqlFunc.JsonListObjectAny(x.HandlerOrgs, "Key", _sessionContext.RequiredOrgId))
+                .Where(x => x.Status == EScreenStatus.Apply)
                 .CountAsync();
-			var workTime = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
-			var screenHandle = await _orderVisitedDetailRepository.Queryable(false, true)
+            var workTime = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
+            var screenHandle = await _orderVisitedDetailRepository.Queryable(false, true)
                 .Includes(x => x.OrderVisit)
                 .LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && s.Status < EScreenStatus.End && s.IsDeleted == false)
                 .Where((x, s) => s.Id == null)
                 .Where(x => x.OrderVisit.VisitTime < DateTime.Now && x.OrderVisit.VisitTime > workTime)
-                .Where((x, s) => x.OrderVisit.VisitState != EVisitState.None && x.OrderVisit.IsCanHandle)
+                .Where((x, s) => x.OrderVisit.VisitState == EVisitState.Visited && x.OrderVisit.IsCanHandle)
                 .Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode == _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")).CountAsync();
-			return new { AboutExpire = aboutExpire, HavExpired = havExpired, CountersignHandle = countersignHandle, ScreenAudit = screenAudit, Delay = delay, ScreenHandle = screenHandle };
+            return new { AboutExpire = aboutExpire, HavExpired = havExpired, CountersignHandle = countersignHandle, ScreenAudit = screenAudit, Delay = delay, ScreenHandle = screenHandle };
         }
-	}
+    }
 }

+ 183 - 139
src/Hotline.Api/Controllers/OrderController.cs

@@ -1,4 +1,5 @@
-using DotNetCore.CAP;
+using Consul;
+using DotNetCore.CAP;
 using Hotline.Api.Filter;
 using Hotline.Application.ExportExcel;
 using Hotline.Application.FlowEngine;
@@ -1475,7 +1476,7 @@ public class OrderController : BaseController
     {
         var isHandled = dto.IsApply.HasValue && dto.IsApply.Value;
         var (total, items) = await _orderDelayRepository
-            .Queryable(hasHandled: !isHandled)
+            .Queryable(hasHandled: isHandled)
             .Includes(d => d.Order)
             .Includes(d => d.Workflow)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
@@ -1644,7 +1645,7 @@ public class OrderController : BaseController
         var view = dto.source == 1;
         var handler = dto.source == 1 && dto.Status is EScreenStatus.Apply;
 
-        var query = _orderScreenRepository.Queryable(canView: view, hasHandled: handler)
+        var query = _orderScreenRepository.Queryable(hasHandled: !handler)
             .Includes(d => d.Order)
             .Includes(d => d.VisitDetail)
             .Includes(d => d.Visit, v => v.Order)
@@ -1939,7 +1940,7 @@ public class OrderController : BaseController
                             OrderId = order.Id,
                             PushPlatform = EPushPlatform.Sms,
                             Remark = order.Title,
-                            Name = user.PhoneNo,
+                            Name = user.Name,
                             TemplateCode = "1003",
                             Params = new List<string>() { order.No },
                             TelNumber = user.PhoneNo,
@@ -2182,7 +2183,7 @@ public class OrderController : BaseController
                             OrderId = order.Id,
                             PushPlatform = EPushPlatform.Sms,
                             Remark = order.Title,
-                            Name = user.PhoneNo,
+                            Name = user.Name,
                             TemplateCode = "1002",
                             Params = new List<string>() { order.No },
                             TelNumber = user.PhoneNo,
@@ -2416,7 +2417,7 @@ public class OrderController : BaseController
         //{
         //	if (roles != null && roles.Contains(item)) dto.CanHandle = true;
         //}
-		if (!string.IsNullOrEmpty(order.WorkflowId))
+        if (!string.IsNullOrEmpty(order.WorkflowId))
         {
             var result = await _workflowDomainService.GetWorkflowHandlePermissionAsync(
                 order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
@@ -2425,6 +2426,7 @@ public class OrderController : BaseController
             dto.CountersignId = result.CountersignId;
             dto.CanHandle = result.CanHandle;
             dto.CanPrevious = result.CanPrevious;
+            dto.PreviousOpinion = result.previousOpinion;
 
             await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
@@ -2500,16 +2502,16 @@ public class OrderController : BaseController
         dto.RepeatableEventDetails = repeatables;
         if (!string.IsNullOrEmpty(dto.WorkflowId))
         {
-			var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
-				cancellationToken: HttpContext.RequestAborted);
-            var centerOpinion = workflow.Steps.Where(x => x.HandlerOrgId == OrgSeedData.CenterId).OrderByDescending(x=>x.CreationTime).Select(x=>x.Opinion).First();
-            dto.CenterOpinion = string.IsNullOrEmpty(centerOpinion)? string.Empty: centerOpinion;
-            var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x=>x.CreationTime).FirstAsync();
-            dto.SendBackOpinion = sendBack is { Id: not null } && !string.IsNullOrEmpty(sendBack.AuditContent) ? sendBack.AuditContent : string.Empty;
-            List<OrderRemarksDto> remarks = workflow.Steps.Where(x=> !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
+            var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
+                cancellationToken: HttpContext.RequestAborted);
+            var centerOpinion = workflow.Steps.Where(x => x.HandlerOrgId == OrgSeedData.CenterId).OrderByDescending(x => x.CreationTime).Select(x => x.Opinion).First();
+            dto.CenterOpinion = string.IsNullOrEmpty(centerOpinion) ? string.Empty : centerOpinion;
+            var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x => x.CreationTime).FirstAsync();
+            dto.SendBackOpinion = sendBack is { Id: not null } && !string.IsNullOrEmpty(sendBack.Content) ? sendBack.Content : string.Empty;
+            List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
             dto.OrderRemarks = remarks;
-		}
-		return dto;
+        }
+        return dto;
     }
 
     /// <summary>
@@ -3080,81 +3082,81 @@ public class OrderController : BaseController
         if (dto.EndTime.HasValue)
             dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
-        //var (total, items) = await _orderRepository
-        //    .Queryable(hasHandled: !isHandled)
-        //    .Includes(d => d.OrderSpecials)
-        //    .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-        //    .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)//即将超期 未办
-        //    .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-        //    .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-        //    //.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))
-        //    .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-        //    .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
-        //    .OrderByDescending(d => d.StartTime)
-        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);
-
-        if (!isHandled)
-        {
-            var (total, items) = await _orderRepository
-                .Queryable(hasHandled: !isHandled)
-                .Includes(d => d.OrderSpecials)
-                .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-                .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)//即将超期 未办
-                .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-                .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-                //.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))
-                .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-                .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
-                .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-                .OrderByDescending(d => d.StartTime)
-                .ToPagedListAsync(dto, HttpContext.RequestAborted);
-            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-        }
-        else
-        {
-            var (total, items) = await _orderRepository.Queryable()
-                .Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
-                    .Where(step => step.ExternalId == d.Id && step.TraceState != EWorkflowTraceState.StepRemoveByPrevious &&
-                                                                 ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-                                                                  (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-                                                                  (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
-                                                                 step.Status == EWorkflowStepStatus.Handled).Any())
-                .Includes(d => d.OrderSpecials)
-                .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-                .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)//即将超期 未办
-                .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-                .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-                //.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))
-                .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
-                .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
-                .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-                .OrderByDescending(d => d.StartTime)
-
-                .ToPagedListAsync(dto, HttpContext.RequestAborted);
-            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-        }
+        var (total, items) = await _orderRepository
+            .Queryable(hasHandled: isHandled)
+            .Includes(d => d.OrderSpecials)
+            .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
+            .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)//即将超期 未办
+            .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
+            .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+            //.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))
+            .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
+            .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
+            .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
+            .OrderByDescending(d => d.StartTime)
+            .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
+        //if (isHandled)
+        //{
+        //    var (total, items) = await _orderRepository
+        //        .Queryable(hasHandled: isHandled)
+        //        .Includes(d => d.OrderSpecials)
+        //        .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
+        //        .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)//即将超期 未办
+        //        .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
+        //        .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+        //        //.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))
+        //        .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
+        //        .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
+        //        .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+        //        .OrderByDescending(d => d.StartTime)
+        //        .ToPagedListAsync(dto, HttpContext.RequestAborted);
+        //    return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+        //}
+        //else
+        //{
+        //    var (total, items) = await _orderRepository.Queryable()
+        //        .Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
+        //            .Where(step => step.ExternalId == d.Id && step.TraceState != EWorkflowTraceState.StepRemoveByPrevious &&
+        //                                                         ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+        //                                                          (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+        //                                                          (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
+        //                                                         step.Status == EWorkflowStepStatus.Handled).Any())
+        //        .Includes(d => d.OrderSpecials)
+        //        .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(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
+        //        .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)//即将超期 未办
+        //        .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
+        //        .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+        //        //.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))
+        //        .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime)
+        //        .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime)
+        //        .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+        //        .OrderByDescending(d => d.StartTime)
+
+        //        .ToPagedListAsync(dto, HttpContext.RequestAborted);
+        //    return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+        //}
+        return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
-
-
+    
     /// <summary>
     /// 查询坐席待办
     /// </summary>
@@ -3170,58 +3172,75 @@ public class OrderController : BaseController
         if (dto.EndTime.HasValue)
             dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
 
-        //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!))
-        //    .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
-        //    .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.CreationTime >= dto.StartTime)
-        //    .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
-        //    .Where(d => (string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)))
-        //    .Where(d => string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)
-        //    .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
-        //    .Where(x => x.Status != EOrderStatus.BackToProvince && x.Status < EOrderStatus.Filed)
-        //    .OrderBy(d => d.Status)
-        //    .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
-        //    .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
-        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);
+        var query = _orderRepository.Queryable();
+        if(dto.IsHandled.HasValue)
+        {
+            var hasHandled = dto.IsHandled.Value;
+            query = query.Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
+                .Where(step => step.ExternalId == d.Id &&
+                               (hasHandled || step.Status != EWorkflowStepStatus.Handled) &&
+                               (!hasHandled || step.Status == EWorkflowStepStatus.Handled && step.TraceState != EWorkflowTraceState.StepRemoveByPrevious) &&
+                               ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+                                (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                                (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)))).Any() || 
+                                     (string.IsNullOrEmpty(d.WorkflowId) && 
+                                      (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId))
+            );
+        }
 
-        var (total, items) = await _orderRepository.Queryable()
-            .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
-            .Where((d, step) =>
-                ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
-                (!string.IsNullOrEmpty(d.WorkflowId) &&
-                ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-                 (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-                 (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
-                 (((dto.IsHandled.HasValue && dto.IsHandled == false) && step.Status != EWorkflowStepStatus.Handled) ||
-                ((dto.IsHandled.HasValue && dto.IsHandled == true) && step.Status == EWorkflowStepStatus.Handled)))))
+        var (total, items) = await query
             .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.Title.StartsWith(dto.Keyword!))
-            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
             .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
             .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.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
+            //.Where(d => (string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)))
+            //.Where(d => string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)
             .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
-            .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
-            .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+            .Where(x => x.Source < ESource.MLSQ || x.Source > ESource.WZSC)
+            .Where(x => x.Status != EOrderStatus.BackToProvince && x.Status < EOrderStatus.Filed)
             .OrderBy(d => d.Status)
             .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
             .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
-            .Select((d, step) => d)
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
 
+        //var (total, items) = await _orderRepository.Queryable()
+        //    .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
+        //    .Where((d, step) =>
+        //        ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
+        //        (!string.IsNullOrEmpty(d.WorkflowId) &&
+        //        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+        //         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+        //         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
+        //         (((dto.IsHandled.HasValue && dto.IsHandled == false) && step.Status != EWorkflowStepStatus.Handled) ||
+        //        ((dto.IsHandled.HasValue && dto.IsHandled == true) && step.Status == EWorkflowStepStatus.Handled)))))
+        //    .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.Title.StartsWith(dto.Keyword!))
+        //    .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No)
+        //    .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue)
+        //    .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.CreationTime >= dto.StartTime)
+        //    .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
+        //    .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+        //    .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
+        //    .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+        //    .OrderBy(d => d.Status)
+        //    .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc)
+        //    .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc)
+        //    .Select((d, step) => d)
+        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);
+
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
-
-
+    
     /// <summary>
     /// 查询中心待办
     /// </summary>
@@ -3233,33 +3252,58 @@ public class OrderController : BaseController
         if (dto.StartTimeEnd.HasValue)
             dto.StartTimeEnd = dto.StartTimeEnd.Value.AddDays(1).AddSeconds(-1);
 
+        //var (total, items) = await _orderRepository.Queryable()
+        //    //.LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
+        //    //.Where((d, step) =>
+        //    // ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
+        //    //  (!string.IsNullOrEmpty(d.WorkflowId) &&
+        //    //   ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
+        //    //    (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+        //    //    (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
+        //    //   ( step.Status != EWorkflowStepStatus.Handled )
+        //    //  )))
+        //    //.Where(d => d.Workflow.Steps.Any(s => s.Status < EWorkflowStepStatus.Handled && s.HandlerOrgId == OrgSeedData.CenterId))
+        //    .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
+        //    .Where((d, step) => (step.Id == null || (step.HandlerOrgId == OrgSeedData.CenterId && step.Status < EWorkflowStepStatus.Handled)))
+        //    .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
+        //    .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
+        //    .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
+        //    .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
+        //    .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, d => d.CreationTime >= dto.StCreationTime && d.CreationTime <= dto.EndCreationTime)
+        //    .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, d => d.StartTime >= dto.StartTimeSt && d.StartTime <= dto.StartTimeEnd)
+        //    .WhereIF(!string.IsNullOrEmpty(dto.StepName), d => d.ActualHandleStepName == dto.StepName)
+        //    .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
+        //    .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
+        //    .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.AcceptorName!.Contains(dto.AcceptorName!))
+        //    .WhereIF(dto.ExpiredStatus is EExpiredStatus.Normal, d => DateTime.Now < d.NearlyExpiredTime)
+        //    .WhereIF(dto.ExpiredStatus is EExpiredStatus.GoingToExpired, d => DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime)
+        //    .WhereIF(dto.ExpiredStatus is EExpiredStatus.Expired, d => DateTime.Now >= d.ExpiredTime)
+        //    .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+        //    .OrderBy(d => d.Status)
+        //    .OrderBy(d => d.CreationTime, OrderByType.Desc)
+        //    .ToPagedListAsync(dto, HttpContext.RequestAborted);
+
         var (total, items) = await _orderRepository.Queryable()
-            //.LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
-            //.Where((d, step) =>
-            // ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) ||
-            //  (!string.IsNullOrEmpty(d.WorkflowId) &&
-            //   ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) ||
-            //    (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
-            //    (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) &&
-            //   ( step.Status != EWorkflowStepStatus.Handled )
-            //  )))
-            //.Where(d => d.Workflow.Steps.Any(s => s.Status < EWorkflowStepStatus.Handled && s.HandlerOrgId == OrgSeedData.CenterId))
-            .LeftJoin<WorkflowStep>((d, step) => d.Id == step.ExternalId)
-            .Where((d, step) => (step.Id == null || (step.HandlerOrgId == OrgSeedData.CenterId && step.Status < EWorkflowStepStatus.Handled)))
+            .Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
+                .Where(step => step.ExternalId == d.Id &&
+                                step.HandlerOrgId == OrgSeedData.CenterId &&
+                                step.Status < EWorkflowStepStatus.Handled).Any() ||
+                        string.IsNullOrEmpty(d.WorkflowId)
+            )
             .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC)
             .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed)
-            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
-            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
+            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No!)
+            .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.StartsWith(dto.Title!))
             .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, d => d.CreationTime >= dto.StCreationTime && d.CreationTime <= dto.EndCreationTime)
             .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, d => d.StartTime >= dto.StartTimeSt && d.StartTime <= dto.StartTimeEnd)
             .WhereIF(!string.IsNullOrEmpty(dto.StepName), d => d.ActualHandleStepName == dto.StepName)
-            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName == dto.ActualHandleOrgName!)
             .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status)
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.AcceptorName!.Contains(dto.AcceptorName!))
             .WhereIF(dto.ExpiredStatus is EExpiredStatus.Normal, d => DateTime.Now < d.NearlyExpiredTime)
             .WhereIF(dto.ExpiredStatus is EExpiredStatus.GoingToExpired, d => DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime)
             .WhereIF(dto.ExpiredStatus is EExpiredStatus.Expired, d => DateTime.Now >= d.ExpiredTime)
-            .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent.Value)
+            .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value)
             .OrderBy(d => d.Status)
             .OrderBy(d => d.CreationTime, OrderByType.Desc)
             .ToPagedListAsync(dto, HttpContext.RequestAborted);
@@ -3296,7 +3340,7 @@ public class OrderController : BaseController
         if (dto.EndTime.HasValue)
             dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
         var (total, items) = await _orderRepository
-            .Queryable(hasHandled: !isHandled)
+            .Queryable(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))

+ 179 - 122
src/Hotline.Api/Controllers/TestController.cs

@@ -202,28 +202,49 @@ public class TestController : BaseController
     }
     [HttpGet("testo111")]
     [AllowAnonymous]
-    public async Task<object> Test111(DateTime StartTime, DateTime? EndTime)
+    public async Task Test111(DateTime StartTime, DateTime? EndTime)
     {
 
         var list = await _orderRepository.Queryable()
-                 .Where(p => p.CreationTime >= StartTime && p.CreationTime <= EndTime)
-                 .Select(p => new
-                 {
-                     AreaCode = p.AreaCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
-                     Hour = p.CreationTime.Hour
-
-                 }).MergeTable()
-                 .LeftJoin<SystemArea>((p,a)=>p.AreaCode==a.Id)
-                 .GroupBy((p, a) => a.AreaName)
-                 .GroupBy((p, a) => p.Hour)
-                 .Select((p, a) => new
-                 {
-                     AreaCode = a.AreaName,
-                     Hour = p.Hour,
-                     count = SqlFunc.AggregateCount(p.AreaCode)
-                 }).ToPivotTableAsync(p => p.AreaCode, p => p.Hour, p => p.Sum(x => x.count));
-
-        return list;
+           .Where(p => p.CreationTime >= StartTime && p.CreationTime <= EndTime && p.Status >= EOrderStatus.Filed)
+           .Where(p => p.CreationTimeHandleDuration == null || p.CenterToOrgHandleDuration == null)
+           .ToListAsync();
+
+        if (list.Any())
+        {
+            foreach (var item in list)
+            {
+                var creationTimeHandleDurationWorkday = item.ActualHandleTime.HasValue
+                  ? _timeLimitDomainService.CalcWorkTime(item.CreationTime, item.ActualHandleTime.Value,
+                  item.ProcessType is EProcessType.Zhiban)
+                  : 0;
+                var centerToOrgHandleDurationWorkday = item.ActualHandleTime.HasValue && item.CenterToOrgTime.HasValue
+                    ? _timeLimitDomainService.CalcWorkTime(item.CenterToOrgTime.Value, item.ActualHandleTime.Value,
+                    item.ProcessType is EProcessType.Zhiban)
+                    : 0;
+
+                item.CreationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday;
+                item.CenterToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday;
+
+                if (item.ActualHandleTime.HasValue)
+                {
+                    var count = Math.Round((item.ActualHandleTime - item.CreationTime).Value.TotalSeconds);
+                    item.CreationTimeHandleDuration = count <= 0 ? 1 : count;
+                }
+                else
+                    item.CreationTimeHandleDuration = 0;
+
+                if (item.ActualHandleTime.HasValue && item.CenterToOrgTime.HasValue)
+                {
+                    var count = Math.Round((item.ActualHandleTime - item.CenterToOrgTime).Value.TotalSeconds);
+                    item.CenterToOrgHandleDuration = count <= 0 ? 1 : count;
+                }
+                else
+                    item.CenterToOrgHandleDuration = 0;
+
+                await _orderRepository.UpdateAsync(item, HttpContext.RequestAborted);
+            }
+        }
     }
 
     [HttpGet("testo")]
@@ -560,19 +581,20 @@ public class TestController : BaseController
 
         var orderIds = orders.Select(d => d.Id).ToList();
         var steps = await _workflowStepRepository.Queryable()
-            .Where(d => orderIds.Contains(d.ExternalId) && 
+            .Where(d => orderIds.Contains(d.ExternalId) &&
                         d.BusinessType == EBusinessType.Send &&
                         d.Status == EWorkflowStepStatus.Handled)
-            .OrderBy(d=>d.CreationTime)
+            .OrderBy(d => d.CreationTime)
             .ToListAsync(HttpContext.RequestAborted);
 
+        _logger.LogWarning($"取到steps: {steps.Count} 条");
         var updateOrders = new List<Order>();
         foreach (var order in orders)
         {
             var step = steps.Where(d => d.ExternalId == order.Id)
                 .OrderBy(d => d.CreationTime)
                 .FirstOrDefault();
-            if(step is null) continue;
+            if (step is null) continue;
 
             order.CenterToOrgTime = step.HandleTime;
             order.CenterToOrgHandlerId = step.HandlerId;
@@ -599,128 +621,163 @@ public class TestController : BaseController
 
             updateOrders.Add(order);
         }
-        
+
+        _logger.LogWarning($"更新工单:{updateOrders.Count} 条");
         await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
     }
 
-    /// <summary>
-    /// 赋值handlerId
-    /// </summary>
-    /// <returns></returns>
+
     [AllowAnonymous]
     [HttpPost("t4")]
     public async Task TestExportExcel1()
     {
-        var orders = await _orderRepository.Queryable()
-            .Includes(d => d.OrderExtension)
-            .InnerJoin<Workflow>((o, w) => o.WorkflowId == w.Id)
-            .Where((o, w) => o.Status < EOrderStatus.Filed && w.Status == EWorkflowStatus.Completed)
-            .ToListAsync(HttpContext.RequestAborted);
-        _logger.LogWarning($"order count: {orders.Count}");
+        //var orders = await _orderRepository.Queryable()
+        //    .Includes(d => d.OrderExtension)
+        //    .InnerJoin<Workflow>((o, w) => o.WorkflowId == w.Id)
+        //    .Where((o, w) => o.Status < EOrderStatus.Filed && w.Status == EWorkflowStatus.Completed)
+        //    .ToListAsync(HttpContext.RequestAborted);
+        //_logger.LogWarning($"order count: {orders.Count}");
 
-        var workflowIds = orders.Select(d => d.WorkflowId).ToList();
-        var workflows = await _workflowRepository.Queryable()
-            .Includes(d => d.Steps, x => x.WorkflowTrace)
-            //.Includes(d=>d.Traces)
-            .Where(d => workflowIds.Contains(d.Id))
-            .ToListAsync(HttpContext.RequestAborted);
+        //var workflowIds = orders.Select(d => d.WorkflowId).ToList();
+        //var workflows = await _workflowRepository.Queryable()
+        //    .Includes(d => d.Steps, x => x.WorkflowTrace)
+        //    //.Includes(d=>d.Traces)
+        //    .Where(d => workflowIds.Contains(d.Id))
+        //    .ToListAsync(HttpContext.RequestAborted);
 
-        var updateOrders = new List<Order>();
-        foreach (var order in orders)
-        {
-            var workflow = workflows.First(d => d.Id == order.WorkflowId);
+        //var updateOrders = new List<Order>();
+        //foreach (var order in orders)
+        //{
+        //    var workflow = workflows.First(d => d.Id == order.WorkflowId);
+
+        //    _mapper.Map(workflow, order);
+        //    var now = DateTime.Now;
+        //    var handleDuration = order.StartTime.HasValue
+        //        ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
+        //        now, order.ProcessType is EProcessType.Zhiban)
+        //        : 0;
+        //    var fileDuration = order.CenterToOrgTime.HasValue
+        //        ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value,
+        //            now, order.ProcessType is EProcessType.Zhiban)
+        //        : 0;
+        //    var allDuration = order.StartTime.HasValue
+        //        ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, now,
+        //        order.ProcessType is EProcessType.Zhiban)
+        //        : 0;
+        //    var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
+        //           ? _timeLimitDomainService.CalcWorkTime(order.CreationTime, order.ActualHandleTime.Value,
+        //           order.ProcessType is EProcessType.Zhiban)
+        //           : 0;
+        //    var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
+        //        ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value, order.ActualHandleTime.Value,
+        //        order.ProcessType is EProcessType.Zhiban)
+        //        : 0;
+
+        //    order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+
+        //    var endStep = workflow.Steps.FirstOrDefault(d => d.StepType == EStepType.End);
+        //    //var endTrace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.StepType == EStepType.End)?.WorkflowTrace;
+        //    if (endStep is null)
+        //    {
+        //        _logger.LogWarning($"endStep 为空, orderNo:{order.No}");
+        //        continue;
+        //    }
 
-            _mapper.Map(workflow, order);
-            var now = DateTime.Now;
-            var handleDuration = order.StartTime.HasValue
-                ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value,
-                now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var fileDuration = order.CenterToOrgTime.HasValue
-                ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value,
-                    now, order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var allDuration = order.StartTime.HasValue
-                ? _timeLimitDomainService.CalcWorkTime(order.StartTime.Value, now,
-                order.ProcessType is EProcessType.Zhiban)
-                : 0;
-            var creationTimeHandleDurationWorkday = order.ActualHandleTime.HasValue
-                   ? _timeLimitDomainService.CalcWorkTime(order.CreationTime, order.ActualHandleTime.Value,
-                   order.ProcessType is EProcessType.Zhiban)
-                   : 0;
-            var centerToOrgHandleDurationWorkday = order.ActualHandleTime.HasValue && order.CenterToOrgTime.HasValue
-                ? _timeLimitDomainService.CalcWorkTime(order.CenterToOrgTime.Value, order.ActualHandleTime.Value,
-                order.ProcessType is EProcessType.Zhiban)
-                : 0;
+        //    var step = workflow.Steps.FirstOrDefault(d => d.Id == endStep.PrevStepId);
+        //    //var trace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.Id == endTrace.PrevStepId)?.WorkflowTrace;
+        //    if (step is null)
+        //    {
+        //        _logger.LogWarning($"step 为空, orderNo:{order.No}");
+        //        continue;
+        //    }
 
-            order.File(now, handleDuration, fileDuration, allDuration, creationTimeHandleDurationWorkday, centerToOrgHandleDurationWorkday);
+        //    var trace = step.WorkflowTrace;
+        //    order.FileUserId = trace.HandlerId;
+        //    order.FileUserName = trace.HandlerName;
+        //    order.FileUserOrgId = trace.HandlerOrgId;
+        //    order.FileUserOrgName = trace.HandlerOrgName;
+        //    order.FileOpinion = trace.Opinion;
 
-            var endStep = workflow.Steps.FirstOrDefault(d => d.StepType == EStepType.End);
-            //var endTrace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.StepType == EStepType.End)?.WorkflowTrace;
-            if (endStep is null)
-            {
-                _logger.LogWarning($"endStep 为空, orderNo:{order.No}");
-                continue;
-            }
+        //    //记录冗余归档数据
+        //    if (workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
+        //    {
+        //        order.FileUserRole = EFileUserType.Dispatch;
+        //    }
+        //    else
+        //    {
+        //        order.FileUserRole = EFileUserType.Seat;
+        //    }
+        //    if (order.ProcessType == EProcessType.Jiaoban)
+        //    {
+        //        order.FileUserRole = EFileUserType.Org;
+        //    }
 
-            var step = workflow.Steps.FirstOrDefault(d => d.Id == endStep.PrevStepId);
-            //var trace = workflow.Steps.FirstOrDefault(d => d.WorkflowTrace.Id == endTrace.PrevStepId)?.WorkflowTrace;
-            if (step is null)
-            {
-                _logger.LogWarning($"step 为空, orderNo:{order.No}");
-                continue;
-            }
+        //    //是否已解决
+        //    order.IsResolved = true;//notification.Dto.External == null ? false : notification.Dto.External.IsResolved;
 
-            var trace = step.WorkflowTrace;
-            order.FileUserId = trace.HandlerId;
-            order.FileUserName = trace.HandlerName;
-            order.FileUserOrgId = trace.HandlerOrgId;
-            order.FileUserOrgName = trace.HandlerOrgName;
-            order.FileOpinion = trace.Opinion;
+        //    //await _orderRepository.UpdateAsync(order, cancellationToken);
+        //    updateOrders.Add(order);
 
-            //记录冗余归档数据
-            if (workflow.Steps.Any(x => x.BusinessType == Share.Enums.FlowEngine.EBusinessType.Send))
-            {
-                order.FileUserRole = EFileUserType.Dispatch;
-            }
-            else
-            {
-                order.FileUserRole = EFileUserType.Seat;
-            }
-            if (order.ProcessType == EProcessType.Jiaoban)
-            {
-                order.FileUserRole = EFileUserType.Org;
-            }
+        //    //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
+        //    var orderFlowDto = new OrderFlowDto
+        //    {
+        //        Order = _mapper.Map<OrderDto>(order),
+        //        WorkflowTrace = _mapper.Map<WorkflowTraceDto>(trace)
+        //    };
+        //    var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, HttpContext.RequestAborted);
+        //    if (callRecord != null)
+        //    {
+        //        orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
+        //    }
+        //    //这里需要判断是否是警情退回
+        //    orderFlowDto.IsNonPoliceReturn = false;//notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
+        //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: HttpContext.RequestAborted);
+        //    //写入质检  针对受理之后直接结束的工单
+        //    await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, HttpContext.RequestAborted);
+
+        //    //司法行政监督管理-工单处理
+        //    await _enforcementApplication.AddEnforcementOrderAsync(order, HttpContext.RequestAborted);
+        //}
 
-            //是否已解决
-            order.IsResolved = true;//notification.Dto.External == null ? false : notification.Dto.External.IsResolved;
+        //_logger.LogWarning($"更新orders:{updateOrders.Count}");
+        //await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
+    }
 
-            //await _orderRepository.UpdateAsync(order, cancellationToken);
-            updateOrders.Add(order);
+    [AllowAnonymous]
+    [HttpGet("t5")]
+    public async Task Test5()
+    {
+        var traces = await _workflowTraceRepository.Queryable()
+            .Where(d => d.Status == EWorkflowStepStatus.Handled && d.HandlerOrgAreaCode == null)
+            .ToListAsync(HttpContext.RequestAborted);
 
-            //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, cancellationToken); //由CallAccept改为OtherAccept
-            var orderFlowDto = new OrderFlowDto
-            {
-                Order = _mapper.Map<OrderDto>(order),
-                WorkflowTrace = _mapper.Map<WorkflowTraceDto>(trace)
-            };
-            var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId, HttpContext.RequestAborted);
-            if (callRecord != null)
+        var orgIds = traces.Select(d => d.HandlerOrgId).ToList();
+        var orgs = await _systemOrganizeRepository.Queryable()
+            .Where(d => orgIds.Contains(d.Id))
+            .ToListAsync(HttpContext.RequestAborted);
+
+        var updateSteps = new List<WorkflowTrace>();
+        foreach (var trace in traces)
+        {
+            var org = orgs.FirstOrDefault(d => d.Id == trace.HandlerOrgId);
+            if (org == null)
             {
-                orderFlowDto.TrCallRecordDto = _mapper.Map<TrCallDto>(callRecord);
+                _logger.LogWarning($"未找到部门,Id:{trace.HandlerOrgId}");
+                continue;
             }
-            //这里需要判断是否是警情退回
-            orderFlowDto.IsNonPoliceReturn = false;//notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
-            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: HttpContext.RequestAborted);
-            //写入质检  针对受理之后直接结束的工单
-            await _qualityApplication.AddQualityAsync(EQualitySource.Accepted, order.Id, HttpContext.RequestAborted);
-
-            //司法行政监督管理-工单处理
-            await _enforcementApplication.AddEnforcementOrderAsync(order, HttpContext.RequestAborted);
+
+            if (!trace.HandlerOrgIsCenter.HasValue)
+                trace.HandlerOrgIsCenter = org.IsCenter;
+            if (string.IsNullOrEmpty(trace.HandlerOrgAreaCode))
+                trace.HandlerOrgAreaCode = org.AreaCode;
+            if (string.IsNullOrEmpty(trace.HandlerOrgAreaName))
+                trace.HandlerOrgAreaName = org.AreaName;
+
+            updateSteps.Add(trace);
         }
 
-        _logger.LogWarning($"更新orders:{updateOrders.Count}");
-        await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
+        _logger.LogWarning($"更新数据:{updateSteps.Count} 条");
+        await _workflowTraceRepository.UpdateRangeAsync(updateSteps, HttpContext.RequestAborted);
     }
 
     [HttpGet("rsa")]

+ 2 - 2
src/Hotline.Api/Hotline.Api.csproj

@@ -7,7 +7,7 @@
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
     <NoWarn>$(NoWarn);1591;8618;1803;</NoWarn>
   </PropertyGroup>
-
+  
   <ItemGroup>
     <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
     <PackageReference Include="Fw.Utility.Client" Version="1.0.0" />
@@ -28,7 +28,7 @@
 
   <ItemGroup>
     <None Update="Template\宜宾交办单模版.doc">
-      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
   </ItemGroup>
 

BIN
src/Hotline.Api/Template/宜宾交办单模版.doc


+ 2 - 2
src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs

@@ -171,7 +171,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                                             OrderId = order.Id,
                                             PushPlatform = EPushPlatform.Sms,
                                             Remark = order.Title,
-                                            Name = item.PhoneNo,
+                                            Name = item.Name,
                                             TemplateCode = "1007",
                                             Params = new List<string>() { order.No },
                                             TelNumber = item.PhoneNo,
@@ -195,7 +195,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                                         OrderId = order.Id,
                                         PushPlatform = EPushPlatform.Sms,
                                         Remark = order.Title,
-                                        Name = item.PhoneNo,
+                                        Name = item.Name,
                                         TemplateCode = "1007",
                                         Params = new List<string>() { order.No },
                                         TelNumber = item.PhoneNo,

+ 1 - 1
src/Hotline.Application/Handlers/FlowEngine/WorkflowPreviousHandler.cs

@@ -123,7 +123,7 @@ namespace Hotline.Application.Handlers.FlowEngine
                                             OrderId = order.Id,
                                             PushPlatform = EPushPlatform.Sms,
                                             Remark = order.Title,
-                                            Name = user.PhoneNo,
+                                            Name = user.Name,
                                             TemplateCode = "1004",
                                             Params = new List<string>() { order.No },
                                             TelNumber = user.PhoneNo,

+ 2 - 2
src/Hotline.Application/Handlers/FlowEngine/WorkflowStartHandler.cs

@@ -127,7 +127,7 @@ namespace Hotline.Application.Handlers.FlowEngine
                                                 OrderId = order.Id,
                                                 PushPlatform = EPushPlatform.Sms,
                                                 Remark = order.Title,
-                                                Name = item.PhoneNo,
+                                                Name = item.Name,
                                                 TemplateCode = "1007",
                                                 Params = new List<string>() { order.No },
                                                 TelNumber = item.PhoneNo,
@@ -149,7 +149,7 @@ namespace Hotline.Application.Handlers.FlowEngine
                                             OrderId = order.Id,
                                             PushPlatform = EPushPlatform.Sms,
                                             Remark = order.Title,
-                                            Name = item.PhoneNo,
+                                            Name = item.Name,
                                             TemplateCode = "1007",
                                             Params = new List<string>() { order.No },
                                             TelNumber = item.PhoneNo,

+ 12 - 9
src/Hotline.Application/Orders/OrderApplication.cs

@@ -194,20 +194,23 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto)
     {
-        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
-        var value = setting?.SettingValue[0];
-        value = string.IsNullOrEmpty(value) ? "0" : value;
-        DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
-        stTime = _timeLimitDomainService.WorkDay(stTime);
-        DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
-        return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
+		//var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderAboutToExpire);
+		//var value = setting?.SettingValue[0];
+		//value = string.IsNullOrEmpty(value) ? "0" : value;
+		//DateTime stTime = DateTime.Now.AddDays(int.Parse(value));
+		//stTime = _timeLimitDomainService.WorkDay(stTime);
+		//DateTime stTime2 = _timeLimitDomainService.WorkDay(DateTime.Now);
+		DateTime? dateTime = DateTime.Now;
+		return _orderRepository.Queryable(canView: true).Includes(d => d.OrderDelays)
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
             .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
             .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
-            .Where(d => d.ExpiredTime != null &&
-            d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
+               //&& stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value
+			//.Where(d => d.ExpiredTime != null &&
+   //         d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
+            .Where(d=>d.Status < EOrderStatus.Filed && dateTime > d.NearlyExpiredTime && dateTime < d.ExpiredTime)
             .OrderByDescending(d => d.CreationTime);
     }
 

+ 19 - 10
src/Hotline.Repository.SqlSugar/Extensions/DataPermissionExtensions.cs

@@ -20,7 +20,6 @@ namespace Hotline.Repository.SqlSugar.Extensions
             where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
         {
             var session = dataPermissionFilterBuilder.SessionContext;
-
             return queryable.Where(d => SqlFunc.Subqueryable<WorkflowTrace>()
                     .Where(step => step.ExternalId == d.Id &&
                             ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == session.RequiredUserId) ||
@@ -39,18 +38,28 @@ namespace Hotline.Repository.SqlSugar.Extensions
         }
 
         public static ISugarQueryable<TEntity> WorkflowHandleFiltering<TEntity>(this ISugarQueryable<TEntity> queryable,
-            IDataPermissionFilterBuilder dataPermissionFilterBuilder, bool canHandle)
+            IDataPermissionFilterBuilder dataPermissionFilterBuilder, bool hasHandled)
             where TEntity : class, IEntity<string>, IDataPermission, IWorkflow, new()
         {
             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(d => SqlFunc.Subqueryable<WorkflowTrace>()
+                .Where(step => step.ExternalId == d.Id &&
+                               (hasHandled || step.Status != EWorkflowStepStatus.Handled) &&
+                               (!hasHandled || step.Status == EWorkflowStepStatus.Handled && step.TraceState != EWorkflowTraceState.StepRemoveByPrevious) &&
+                               ((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))))
+                .Any()
+            );
+
+            //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(hasHandled, (d, step) => step.Status == EWorkflowStepStatus.Handled)
+            //        .WhereIF(!hasHandled, (d, step) => step.Status != EWorkflowStepStatus.Handled)
+            //        .Select((d, step) => d)
+            //    ;
 
             //return queryable.Where(dataPermissionFilterBuilder.BuildWithFlowHandleFilter<TEntity>(canHandle));
         }

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

@@ -353,6 +353,11 @@ namespace Hotline.Share.Dtos.Order
         /// 是否可办理
         /// </summary>
         public bool CanHandle { get; set; }
+        
+        /// <summary>
+        /// 退回意见
+        /// </summary>
+        public string? PreviousOpinion { get; set; }
 
         /// <summary>
         /// 延期申请数量

+ 1 - 1
src/Hotline.Share/Dtos/OrderExportWord/OrderSubmissionForm.cs

@@ -87,7 +87,7 @@ namespace Hotline.Share.Dtos.OrderExportWord
         /// <summary>
         /// 实际办理意见
         /// </summary>
-        public string? ActualOpinion { get; set; }
+        public string? FileOpinion { get; set; }
 
         /// <summary>
         /// 回访部门信息

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

@@ -36,7 +36,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询工作流包含当前用户办理权限(是否可办理)
         /// </summary>
-        Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious)> GetWorkflowHandlePermissionAsync(
+        Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious,string? previousOpinion)> GetWorkflowHandlePermissionAsync(
             string workflowId, string userId, string orgId, string[] roleIds, CancellationToken cancellationToken = default);
 
         /// <summary>

+ 1 - 1
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -330,7 +330,7 @@ public abstract class StepBasicEntity : CreationEntity
     /// <summary>
     /// 办理意见
     /// </summary>
-    [SugarColumn(Length = 2000)]
+    [SugarColumn(Length = 8000)]
     public string? Opinion { get; set; }
 
     /// <summary>

+ 1 - 1
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -148,7 +148,7 @@ public partial class Workflow : CreationEntity
     /// <summary>
     /// 实际办理意见(办理中...or 最终办理意见)
     /// </summary>
-    [SugarColumn(Length = 2000)]
+    [SugarColumn(Length = 8000)]
     public string ActualOpinion { get; set; } = "办理中...";
 
     /// <summary>

+ 103 - 57
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -29,7 +29,9 @@ namespace Hotline.FlowEngine.Workflows
         private readonly IRepository<WorkflowStep> _workflowStepRepository;
         private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IRepository<WorkflowSupplement> _workflowSupplementRepository;
+
         private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
+
         //private readonly IRepository<WorkflowStepHandler> _workflowStepHandlerRepository;
         private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
@@ -104,7 +106,8 @@ namespace Hotline.FlowEngine.Workflows
 
             if (firstStepDefine.StepType is EStepType.End)
             {
-                await _mediator.Publish(new StartWorkflowNotify(workflow, dto, flowAssignInfo, startStep.WorkflowTrace), cancellationToken);
+                await _mediator.Publish(new StartWorkflowNotify(workflow, dto, flowAssignInfo, startStep.WorkflowTrace),
+                    cancellationToken);
 
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
                 workflow.UpdateActualStepWhenHandle(startStep,
@@ -113,7 +116,8 @@ namespace Hotline.FlowEngine.Workflows
                     current.OrgAreaCode, current.OrgAreaName,
                     current.OrgLevel);
 
-                var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, current, expiredTime, cancellationToken);
+                var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, current, expiredTime,
+                    cancellationToken);
                 return;
             }
 
@@ -230,10 +234,13 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询工作流包含当前用户结束会签权限(是否可结束)
         /// </summary>
-        public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious)> GetWorkflowHandlePermissionAsync(
-            string workflowId, string userId, string orgId, string[] roleIds, CancellationToken cancellationToken = default)
+        public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, string?
+                previousOpinion)>
+            GetWorkflowHandlePermissionAsync(
+                string workflowId, string userId, string orgId, string[] roleIds,
+                CancellationToken cancellationToken = default)
         {
-            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withCountersigns: true,
+            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withTraces: true, withCountersigns: true,
                 cancellationToken: cancellationToken);
 
             var canHandle = workflow.IsCanHandle(userId, orgId, roleIds);
@@ -248,14 +255,21 @@ namespace Hotline.FlowEngine.Workflows
                 }
             }
 
+            var unhandlePreviousTrace = workflow.Traces.FirstOrDefault(d =>
+                d.Status is not EWorkflowStepStatus.Handled &&
+                d.TraceType is EWorkflowTraceType.Previous);
+            var previousOpinion = unhandlePreviousTrace?.Opinion ?? null;
+
             var unCompletedCountersign = workflow.Countersigns
                 .FirstOrDefault(d => !d.IsCompleted() && d.StarterId == userId);
-            if (unCompletedCountersign is null) return (workflow, null, canHandle, canPrevious);
+            if (unCompletedCountersign is null) 
+                return (workflow, null, canHandle, canPrevious, previousOpinion);
 
             //var existCountersignEndStep = workflow.Steps.Exists(d =>
             //    d.IsCountersignEndStep && d.CountersignStartStepId == unCompletedCountersign.StartStepId);
             //return (workflow, existCountersignEndStep ? null : unCompletedCountersign.Id, canPrevious);
-            return (workflow, unCompletedCountersign.Id, canHandle, canPrevious);
+
+            return (workflow, unCompletedCountersign.Id, canHandle, canPrevious, previousOpinion);
         }
 
         /// <summary>
@@ -267,7 +281,8 @@ namespace Hotline.FlowEngine.Workflows
             string? orgAreaCode, string? orgAreaName,
             CancellationToken cancellationToken)
         {
-            if (!workflow.IsCanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles)) return;
+            if (!workflow.IsCanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
+                    _sessionContext.Roles)) return;
             //工单完成以后查看的场景
             if (workflow.Status != EWorkflowStatus.Runnable) return;
 
@@ -411,18 +426,24 @@ namespace Hotline.FlowEngine.Workflows
             //会签办理节点办理时更新会签members字段
             if (currentStep.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single)
             {
-                //会签中正常办理节点,更新会签members办理状态
-                var countersign =
-                    workflow.Countersigns.FirstOrDefault(d => !d.IsCompleted() && d.Id == currentStep.CountersignId);
-                if (countersign is null)
-                    throw new UserFriendlyException(
-                        $"会签数据异常, workflowId: {currentStep.WorkflowId}, countersignId: {currentStep.CountersignId}",
-                        "会签数据异常");
-                countersign.MemberHandled(current.RequiredUserId, current.RequiredOrgId);
-                //update cs
-                await _workflowCountersignRepository.UpdateNav(countersign)
-                    .Include(d => d.Members)
-                    .ExecuteCommandAsync();
+                if (!string.IsNullOrEmpty(currentStep.CountersignId))
+                {
+                    //会签中正常办理节点,更新会签members办理状态
+                    var countersign =
+                        workflow.Countersigns.FirstOrDefault(d =>
+                            !d.IsCompleted() && d.Id == currentStep.CountersignId);
+                    if (countersign is not null)
+                    {
+                        //throw new UserFriendlyException(
+                        //    $"会签数据异常, workflowId: {currentStep.WorkflowId}, countersignId: {currentStep.CountersignId}",
+                        //    "会签数据异常");
+                        countersign.MemberHandled(current.RequiredUserId, current.RequiredOrgId);
+                        //update cs
+                        await _workflowCountersignRepository.UpdateNav(countersign)
+                            .Include(d => d.Members)
+                            .ExecuteCommandAsync();
+                    }
+                }
             }
 
             await _workflowStepRepository.UpdateRangeAsync(updateSteps, cancellationToken);
@@ -458,7 +479,8 @@ namespace Hotline.FlowEngine.Workflows
             //检查是否流转到流程终点
             if (nextStepDefine.StepType is EStepType.End)
             {
-                var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, current, expiredTime, cancellationToken);
+                var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, current, expiredTime,
+                    cancellationToken);
                 return;
             }
 
@@ -526,7 +548,8 @@ namespace Hotline.FlowEngine.Workflows
         {
             //ValidatePermission(workflow, operater.OrgId, operater.Id);
 
-            var (currentStep, prevStep, countersignStartStep) = GetPreviousStep(workflow, applicantId, applicantOrgId, applicantRoleIds);
+            var (currentStep, prevStep, countersignStartStep) =
+                GetPreviousStep(workflow, applicantId, applicantOrgId, applicantRoleIds);
 
             //保存附件
             if (dto.Files.Any())
@@ -590,7 +613,8 @@ namespace Hotline.FlowEngine.Workflows
             //await _workflowTraceRepository.UpdateAsync(trace, cancellationToken);
 
             //复制上一个节点为待接办
-            var newPrevStep = await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
+            var newPrevStep =
+                await DuplicateStepWithTraceAsync(workflow, prevStep, EWorkflowTraceType.Previous, cancellationToken);
 
             //remove workflow.steps
             await _workflowStepRepository.RemoveRangeAsync(removeSteps, cancellationToken);
@@ -621,7 +645,8 @@ namespace Hotline.FlowEngine.Workflows
             return GetFlowDirection(currentStep.BusinessType, prevStep.BusinessType);
         }
 
-        private async Task UpdateTracesStateAsync(List<WorkflowTrace> traces, EWorkflowTraceState traceState, CancellationToken cancellationToken)
+        private async Task UpdateTracesStateAsync(List<WorkflowTrace> traces, EWorkflowTraceState traceState,
+            CancellationToken cancellationToken)
         {
             foreach (var trace in traces)
             {
@@ -643,7 +668,8 @@ namespace Hotline.FlowEngine.Workflows
             if (currentStep.IsInCountersign() && !isCurrentTopCountersignEndStep)
                 throw UserFriendlyException.SameMessage("会签节点不支持退回");
 
-            if (workflow.FlowType is EFlowType.Review && currentStep.StepType is EStepType.Start && currentStep.IsOrigin)
+            if (workflow.FlowType is EFlowType.Review && currentStep.StepType is EStepType.Start &&
+                currentStep.IsOrigin)
                 throw UserFriendlyException.SameMessage("当前流程已退回到开始节点");
 
             //当退回操作遇到会签时,删除所有会签节点直达topCsStep
@@ -679,7 +705,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询派单池中流程节点id
         /// </summary>
-        public async Task<IReadOnlyList<string>> GetUnhandleStepIdsFromSendPoolAsync(string sendPoolId, CancellationToken cancellationToken)
+        public async Task<IReadOnlyList<string>> GetUnhandleStepIdsFromSendPoolAsync(string sendPoolId,
+            CancellationToken cancellationToken)
         {
             return await _workflowStepRepository.Queryable()
                 .Where(d => SqlFunc.JsonListObjectAny(d.Handlers, "Key", sendPoolId))
@@ -761,7 +788,8 @@ namespace Hotline.FlowEngine.Workflows
         /// 批量修改工单办理对象
         /// </summary>
         public async Task ChangeHandlerBatchAsync(
-            IReadOnlyList<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps)> handlers,
+            IReadOnlyList<(string userId, string username, string orgId, string orgName, ICollection<WorkflowStep> steps
+                )> handlers,
             CancellationToken cancellationToken)
         {
             foreach (var handler in handlers)
@@ -791,11 +819,11 @@ namespace Hotline.FlowEngine.Workflows
         public async Task<ICollection<Kv>> GetLevelOneOrgsAsync(string workflowId, CancellationToken cancellation)
         {
             var traces = await _workflowTraceRepository.Queryable()
-                 .LeftJoin<SystemOrganize>((t, o) => t.HandlerOrgId == o.Id)
-                 .Where((t, o) => t.WorkflowId == workflowId &&
-                                  !string.IsNullOrEmpty(t.HandlerOrgId) &&
-                                  o.Level == 1)
-                 .ToListAsync(cancellation);
+                .LeftJoin<SystemOrganize>((t, o) => t.HandlerOrgId == o.Id)
+                .Where((t, o) => t.WorkflowId == workflowId &&
+                                 !string.IsNullOrEmpty(t.HandlerOrgId) &&
+                                 o.Level == 1)
+                .ToListAsync(cancellation);
 
             //var handlers = await _workflowStepHandlerRepository.Queryable()
             //    .InnerJoin<WorkflowTrace>((wsh, wt) => wsh.WorkflowStepId == wt.StepId)
@@ -831,7 +859,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 更新未办理节点的期满时间
         /// </summary>
-        public async Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime expiredTime, CancellationToken cancellation)
+        public async Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime expiredTime,
+            CancellationToken cancellation)
         {
             var steps = await _workflowStepRepository.Queryable()
                 .Includes(d => d.WorkflowTrace)
@@ -853,7 +882,8 @@ namespace Hotline.FlowEngine.Workflows
         /// 查询该部门最后办理节点
         /// </summary>
         /// <returns></returns>
-        public async Task<WorkflowStep> FindLastHandleStepAsync(string workflowId, string orgId, CancellationToken cancellation)
+        public async Task<WorkflowStep> FindLastHandleStepAsync(string workflowId, string orgId,
+            CancellationToken cancellation)
         {
             return await _workflowStepRepository.Queryable()
                 .Where(d => d.WorkflowId == workflowId && d.HandlerOrgId == orgId && d.StepType != EStepType.End)
@@ -865,7 +895,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询流转方向
         /// </summary>
-        public EFlowDirection GetFlowDirection(EBusinessType sourceStepBusinessType, EBusinessType directionStepBusinessType)
+        public EFlowDirection GetFlowDirection(EBusinessType sourceStepBusinessType,
+            EBusinessType directionStepBusinessType)
         {
             switch (sourceStepBusinessType)
             {
@@ -899,9 +930,11 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 流程被签收至某个用户(更新流转对象,办理对象,节点办理对象以及stepHandlers)
         /// </summary>
-        public async Task<Workflow> SignToSomebodyAsync(string workflowId, string userId, string username, string orgId, string orgName, CancellationToken cancellationToken)
+        public async Task<Workflow> SignToSomebodyAsync(string workflowId, string userId, string username, string orgId,
+            string orgName, CancellationToken cancellationToken)
         {
-            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withTraces: true, cancellationToken: cancellationToken);
+            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withTraces: true,
+                cancellationToken: cancellationToken);
             workflow.Assign(EFlowAssignType.User, _sessionContext.RequiredUserId);
 
             workflow.HandlerOrgs = new();
@@ -949,7 +982,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查找当前会签内所有节点(含start,end)
         /// </summary>
-        private void SearchCountersignSteps(WorkflowStep startStep, List<WorkflowStep> steps, ref List<WorkflowStep> csSteps)
+        private void SearchCountersignSteps(WorkflowStep startStep, List<WorkflowStep> steps,
+            ref List<WorkflowStep> csSteps)
         {
             if (startStep.IsStartCountersign)
             {
@@ -991,7 +1025,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 撤回至开始节点
         /// </summary>
-        public async Task RecallToStartStepAsync(string workflowId, string opinion, ISessionContext current, CancellationToken cancellationToken)
+        public async Task RecallToStartStepAsync(string workflowId, string opinion, ISessionContext current,
+            CancellationToken cancellationToken)
         {
             //todo 1.当前待办节点删掉 2.当前待办trace更新(status, opinion) 3.复制startStep为待办 4.更新workflow(status, csStatus, handlers) 5.publish event
             var workflow = await GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, withTraces: true,
@@ -1211,7 +1246,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 查询当前待办理节点
         /// </summary>
-        public WorkflowStep FindCurrentStepWaitForHandle(Workflow workflow, string userId, string orgId, string[] roleIds) =>
+        public WorkflowStep FindCurrentStepWaitForHandle(Workflow workflow, string userId, string orgId,
+            string[] roleIds) =>
             GetUnHandleStep(workflow.Steps, orgId, userId, roleIds);
 
         /// <summary>
@@ -1227,7 +1263,8 @@ namespace Hotline.FlowEngine.Workflows
         /// 查询所有办理部门及实际办理部门
         /// </summary>
         /// <returns></returns>
-        public async Task<(Kv, IReadOnlyList<Kv>)> GetHandleOrgsAsync(string workflowId, CancellationToken cancellationToken)
+        public async Task<(Kv, IReadOnlyList<Kv>)> GetHandleOrgsAsync(string workflowId,
+            CancellationToken cancellationToken)
         {
             var workflow = await GetWorkflowAsync(workflowId, withTraces: true, cancellationToken: cancellationToken);
             var steps = workflow.Traces
@@ -1273,7 +1310,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 撤销流程
         /// </summary>
-        public async Task CancelAsync(CancelDto dto, DateTime? expiredTime, ISessionContext current, CancellationToken cancellationToken)
+        public async Task CancelAsync(CancelDto dto, DateTime? expiredTime, ISessionContext current,
+            CancellationToken cancellationToken)
         {
             var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
                 cancellationToken: cancellationToken);
@@ -1286,7 +1324,7 @@ namespace Hotline.FlowEngine.Workflows
 
             var basicDto = _mapper.Map<BasicWorkflowDto>(dto);
             var endTrace = await EndAsync(workflow, basicDto, endStepDefine, currentStep, current,
-               expiredTime, cancellationToken: cancellationToken);
+                expiredTime, cancellationToken: cancellationToken);
 
             await _mediator.Publish(new CancelWorkflowNotify(workflow), cancellationToken);
         }
@@ -1359,7 +1397,8 @@ namespace Hotline.FlowEngine.Workflows
             //};
 
             //create endStep
-            var endStep = await CreateEndStepAsync(current, workflow, endStepDefine, currentStep, expiredTime, cancellationToken);
+            var endStep = await CreateEndStepAsync(current, workflow, endStepDefine, currentStep, expiredTime,
+                cancellationToken);
             workflow.Steps.Add(endStep);
 
             //update endTrace
@@ -1528,11 +1567,13 @@ namespace Hotline.FlowEngine.Workflows
                         if (dto.BackToCountersignEnd)
                         {
                             // csStartStep.prev
-                            var csStartStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
+                            var csStartStep =
+                                workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
                             if (csStartStep is null)
                                 throw new UserFriendlyException("未查询到会签节点");
 
-                            nextSteps = await CreateCsEndStepsByTargetPrevAsync(workflow, csStartStep, dto, expiredTime, cancellationToken);
+                            nextSteps = await CreateCsEndStepsByTargetPrevAsync(workflow, csStartStep, dto, expiredTime,
+                                cancellationToken);
                         }
                         else
                         {
@@ -1651,7 +1692,8 @@ namespace Hotline.FlowEngine.Workflows
             //会签未全部办理则不创建汇总节点
 
             var csInnerSteps = workflow.Steps.Where(d => d.PrevStepId == countersignStartStep.Id).ToList();
-            if (csInnerSteps.Any(d => d.Status != EWorkflowStepStatus.Handled || (d.IsStartCountersign && !d.IsStartedCountersignEnd)))
+            if (csInnerSteps.Any(d =>
+                    d.Status != EWorkflowStepStatus.Handled || (d.IsStartCountersign && !d.IsStartedCountersignEnd)))
                 return nextSteps;
             //if (csInnerSteps.All(d => d.Status == EWorkflowStepStatus.Handled))
             //{
@@ -1726,9 +1768,9 @@ namespace Hotline.FlowEngine.Workflows
         private void HandleStep(ISessionContext current, WorkflowStep step, string opinion, string nextStepCode)
         {
             step.Handle(current.RequiredUserId, current.UserName,
-                 current.RequiredOrgId, current.OrgName,
-                 current.OrgAreaCode, current.OrgAreaName,
-                 current.OrgIsCenter, opinion, nextStepCode);
+                current.RequiredOrgId, current.OrgName,
+                current.OrgAreaCode, current.OrgAreaName,
+                current.OrgIsCenter, opinion, nextStepCode);
 
             //var handler = step.FindActualHandler(current.Roles, current.RequiredUserId, current.RequiredOrgId);
             //if (handler is not null)
@@ -1739,7 +1781,8 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 开始会签(创建会签数据,更新currentStep会签数据)
         /// </summary>
-        private async Task StartCountersignAsync(ISessionContext current, Workflow workflow, WorkflowStep startStep, BasicWorkflowDto dto,
+        private async Task StartCountersignAsync(ISessionContext current, Workflow workflow, WorkflowStep startStep,
+            BasicWorkflowDto dto,
             EFlowAssignType? flowAssignType, ECounterSignType? counterSignType, DateTime? expiredTime,
             CancellationToken cancellationToken)
         {
@@ -1841,7 +1884,6 @@ namespace Hotline.FlowEngine.Workflows
             //    .ExecuteCommandAsync();
 
 
-
             await CreateTraceAsync(workflow, newStep, traceType, cancellationToken);
 
             return newStep;
@@ -1902,7 +1944,8 @@ namespace Hotline.FlowEngine.Workflows
         //    await _workflowTraceRepository.UpdateRangeAsync(uncompleteTraces, cancellationToken);
         //}
 
-        private async Task RecallTraceAsync(List<WorkflowTrace> traces, string opinion, ISessionContext current, CancellationToken cancellationToken)
+        private async Task RecallTraceAsync(List<WorkflowTrace> traces, string opinion, ISessionContext current,
+            CancellationToken cancellationToken)
         {
             //未办理的traces
             //var uncompleteTraces =
@@ -2080,6 +2123,7 @@ namespace Hotline.FlowEngine.Workflows
                 {
                     trace.TraceState = EWorkflowTraceState.StepRemoveByRecall;
                 }
+
                 updateTraces.AddRange(traces);
             }
 
@@ -2165,7 +2209,7 @@ namespace Hotline.FlowEngine.Workflows
             };
 
             var step = CreateStep(workflow, endStepDefine, prevStep, EFlowAssignType.User, handler,
-                 null, null, EWorkflowStepStatus.WaitForAccept,
+                null, null, EWorkflowStepStatus.WaitForAccept,
                 ECountersignPosition.None, expiredTime, endStepDefine.Name, true);
 
             //step.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
@@ -2207,7 +2251,7 @@ namespace Hotline.FlowEngine.Workflows
                 var handler = stepDefine.HandlerTypeItems.First();
                 handlers = new List<FlowStepHandler>
                 {
-                    new(){Key = handler.Key, Value = handler.Value, RoleId = handler.Key, RoleName = handler.Value}
+                    new() { Key = handler.Key, Value = handler.Value, RoleId = handler.Key, RoleName = handler.Value }
                 }; //flowAssignInfo.GetHandlers();
             }
             else
@@ -2374,7 +2418,8 @@ namespace Hotline.FlowEngine.Workflows
                 var updateSteps = new List<WorkflowStep>();
                 var updateTraces = new List<WorkflowTrace>();
 
-                HandleStepsByTerminalCs(startCountersignStep, workflow.Steps, workflow.Traces, ref updateSteps, ref updateTraces);
+                HandleStepsByTerminalCs(startCountersignStep, workflow.Steps, workflow.Traces, ref updateSteps,
+                    ref updateTraces);
                 if (updateSteps.Any())
                     await _workflowStepRepository.RemoveRangeAsync(updateSteps, cancellationToken);
                 //await _workflowStepRepository.RemoveNav(updateSteps)
@@ -2387,7 +2432,8 @@ namespace Hotline.FlowEngine.Workflows
 
                 //cp会签发起节点变为待办节点
                 //1. create terminal trace 2. 撤回至startStep
-                var newStep = await DuplicateStepWithTraceAsync(workflow, startCountersignStep, EWorkflowTraceType.Normal,
+                var newStep = await DuplicateStepWithTraceAsync(workflow, startCountersignStep,
+                    EWorkflowTraceType.Normal,
                     cancellationToken);
 
                 //当topcsStep结束cs时,实际办理节点应该更新为newStep

+ 18 - 7
src/Hotline/Orders/Order.cs

@@ -316,6 +316,7 @@ namespace Hotline.Orders
         /// <summary>
         /// 交办意见
         /// </summary>
+        [SugarColumn(Length = 8000)]
         public string? CenterToOrgOpinion { get; set; }
 
         /// <summary>
@@ -466,7 +467,7 @@ namespace Hotline.Orders
         /// <summary>
         /// 实际办理意见(办理中...or 最终办理意见)
         /// </summary>
-        [SugarColumn(Length = 2000)]
+        [SugarColumn(Length = 8000)]
         public string ActualOpinion { get; set; } = "办理中...";
 
         /// <summary>
@@ -689,7 +690,7 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDataType = "varchar(8000)")]
         public string? FileOpinion { get; set; }
 
-        
+
 
         #endregion
 
@@ -1039,8 +1040,14 @@ namespace Hotline.Orders
         /// </summary>
         public void SetCreationTimeHandleDurationWorkday()
         {
-            if (!ActualHandleTime.HasValue) return;
-            FileDuration = Math.Round((ActualHandleTime - CreationTime).Value.TotalSeconds);
+            if (!ActualHandleTime.HasValue)
+                CreationTimeHandleDuration = 0;
+            else
+            {
+                var count = Math.Round((ActualHandleTime - CreationTime).Value.TotalSeconds);
+                CreationTimeHandleDuration = count <= 0 ? 1 : count;
+            }
+
         }
 
         /// <summary>
@@ -1048,9 +1055,13 @@ namespace Hotline.Orders
         /// </summary>
         public void SetCenterToOrgHandleDurationWorkday()
         {
-            if (!ActualHandleTime.HasValue) return;
-            if (!CenterToOrgTime.HasValue) return;
-            FileDuration = Math.Round((ActualHandleTime - CenterToOrgTime).Value.TotalSeconds);
+            if (ActualHandleTime.HasValue && CenterToOrgTime.HasValue)
+            {
+                var count = Math.Round((ActualHandleTime - CenterToOrgTime).Value.TotalSeconds);
+                CenterToOrgHandleDuration = count <= 0 ? 1 : count;
+            }
+            else
+                CenterToOrgHandleDuration = 0;
         }
 
         /// <summary>