Browse Source

Merge branch 'feature/get_next_step_new_options' into dev

# Conflicts:
#	src/Hotline.Application/Orders/OrderApplication.cs
xf 6 months ago
parent
commit
754213990c
26 changed files with 694 additions and 441 deletions
  1. 8 2
      src/Hotline.Api/Controllers/KnowledgeController.cs
  2. 256 180
      src/Hotline.Api/Controllers/OrderController.cs
  3. 5 1
      src/Hotline.Api/Controllers/WebPortalController.cs
  4. 10 0
      src/Hotline.Api/Hotline.Api.csproj
  5. 1 1
      src/Hotline.Api/StartupExtensions.cs
  6. 12 3
      src/Hotline.Api/StartupHelper.cs
  7. 1 1
      src/Hotline.Api/config/appsettings.Development.json
  8. 16 12
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  9. 1 1
      src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs
  10. 4 2
      src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs
  11. 7 6
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  12. 1 1
      src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs
  13. 13 4
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  14. 1 1
      src/Hotline.Share/Dtos/FlowEngine/Definition/StepDefineBasic.cs
  15. 13 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  16. 1 1
      src/Hotline.Share/Dtos/FlowEngine/Workflow/StepBasicDto.cs
  17. 2 0
      src/Hotline.Share/Dtos/Knowledge/KnowledgeDto.cs
  18. 55 20
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  19. 68 0
      src/Hotline.Share/Enums/FlowEngine/ECountersignPolicy.cs
  20. 0 68
      src/Hotline.Share/Enums/FlowEngine/EDynamicPolicyCountersign.cs
  21. 3 0
      src/Hotline.Share/Enums/Settings/ETimeType.cs
  22. 10 5
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  23. 1 1
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  24. 3 4
      src/Hotline/FlowEngine/Workflows/Workflow.cs
  25. 194 119
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  26. 8 8
      src/Hotline/Orders/OrderDomainService.cs

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

@@ -491,8 +491,14 @@ namespace Hotline.Api.Controllers
             if (knowledgeWords.Any())
                 knowledgeShowInfoDto.KeywordsDto = _mapper.Map<List<KnowledgeWordDto>>(knowledgeWords);
 
-            var files = await _fileRepository.Queryable().Where(x => x.Key == knowledge.Id).ToListAsync();
-            if (files.Any()) knowledgeShowInfoDto.Files = _mapper.Map<List<FileDto>>(files);
+            if (knowledgeShowInfoDto.FileJson != null && knowledgeShowInfoDto.FileJson.Any())
+            {
+	            var ids = knowledgeShowInfoDto.FileJson.Select(x => x.Id).ToList();
+	            knowledgeShowInfoDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+            }
+
+			//var files = await _fileRepository.Queryable().Where(x => x.Key == knowledge.Id).ToListAsync();
+   //         if (files.Any()) knowledgeShowInfoDto.Files = _mapper.Map<List<FileDto>>(files);
 
             if (IsAddPv == true)
                 _mediator.Publish(new GetKnowledgeInfoNotify(knowledge));

+ 256 - 180
src/Hotline.Api/Controllers/OrderController.cs

@@ -302,11 +302,11 @@ public class OrderController : BaseController
             .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName == dto.CenterToOrgHandlerName!) //派单人
             .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
             .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
-            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType)//受理类型
+            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码
-                                                                                              //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
-                                                                                              //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
+            //.WhereIF(!string.IsNullOrEmpty(dto.PubMan),
+            //    d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!))
             .WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState)
             .WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState)
             .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.Source == ESource.ProvinceStraight)
@@ -396,6 +396,7 @@ public class OrderController : BaseController
                     {
                         orderVisit.EmployeeId = string.Empty;
                     }
+
                     if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null } && !order.IsProvince)
                     {
                         orderVisit.VisitState = EVisitState.Visited;
@@ -549,6 +550,7 @@ public class OrderController : BaseController
         {
             orderVisit.EmployeeId = _sessionContext.RequiredUserId;
         }
+
         if (_appOptions.Value.IsZiGong)
         {
             orderVisit.EmployeeId = string.Empty;
@@ -694,15 +696,17 @@ public class OrderController : BaseController
             .WhereIF(dto.CreationTimeStart.HasValue, d => d.Order.CreationTime >= dto.CreationTimeStart)
             .WhereIF(dto.CreationTimeEnd.HasValue, d => d.Order.CreationTime <= dto.CreationTimeEnd)
             .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.Order.FromPhone == dto.FromPhone) //来电号码
-            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
-            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType)//受理类型
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName),
+                d => d.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊)
+            .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.PublishName), d => d.CreatorName.Contains(dto.PublishName!))
-            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Order.AcceptorName == dto.NameOrNo! || d.Order.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo),
+                d => d.Order.AcceptorName == dto.NameOrNo! || d.Order.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席
             .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime)
             .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime)
             .WhereIF(dto.Resolve.HasValue, x => x.Resolve == dto.Resolve)
-             .WhereIF(dto.IsOverTime == true,
+            .WhereIF(dto.IsOverTime == true,
                 d => (d.Order.ExpiredTime < DateTime.Now && d.Order.Status < EOrderStatus.Filed) ||
                      (d.Order.ExpiredTime < d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //是 超期
             .WhereIF(dto.IsOverTime == false,
@@ -904,7 +908,7 @@ public class OrderController : BaseController
                 d => d.OrderVisitDetails.Any(m => dto.OrgProcessingResults.Contains(SqlFunc.JsonField(m.OrgProcessingResults, "Key"))))
             .WhereIF(dto.OrgHandledAttitude.Any(),
                 d => d.OrderVisitDetails.Any(q => dto.OrgHandledAttitude.Contains(SqlFunc.JsonField(q.OrgHandledAttitude, "Key"))))
-             .WhereIF(dto.IsOverTime == true,
+            .WhereIF(dto.IsOverTime == true,
                 d => (d.Order.ExpiredTime < DateTime.Now && d.Order.Status < EOrderStatus.Filed) ||
                      (d.Order.ExpiredTime < d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //是 超期
             .WhereIF(dto.IsOverTime == false,
@@ -1964,7 +1968,7 @@ public class OrderController : BaseController
     {
         if (_appOptions.Value.IsYiBin) dto.ScreenType = EOrderScreenType.Org;
 
-		dto.CreationTimeEnd = DateTime.Now;
+        dto.CreationTimeEnd = DateTime.Now;
         dto.CreationTimeStart = DateTime.Now;
         if (dto.IsHomePage != null && dto.IsHomePage == true)
         {
@@ -1978,12 +1982,16 @@ public class OrderController : BaseController
             .Includes(x => x.OrderVisit, y => y.Employee)
             //.LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && s.IsDeleted == false)
             .Includes(x => x.OrderScreens)
-            .Where(x => x.OrderScreens.Any(s => s.Status == EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply == true) || x.OrderScreens.Any() == false
-            //|| x.OrderScreens.Any(s => (s.Status != EScreenStatus.SendBack && s.SendBackApply != true)) == false
+            .Where(x => x.OrderScreens.Any(s => s.Status == EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply == true) ||
+                        x.OrderScreens.Any() == false
+                //|| x.OrderScreens.Any(s => (s.Status != EScreenStatus.SendBack && s.SendBackApply != true)) == false
             )
             .WhereIF(dto.ScreenType == EOrderScreenType.Seat, x => x.OrderVisit.Order.IsProvince == false)
-            .WhereIF(dto.ScreenSendBack is 1, x => x.OrderScreens.Any(s => s.Status == EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply == true))
-            .WhereIF(dto.ScreenSendBack is 2, x => x.OrderScreens.Any(s => (s.Status != EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply != true)) == false)
+            .WhereIF(dto.ScreenSendBack is 1,
+                x => x.OrderScreens.Any(s => s.Status == EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply == true))
+            .WhereIF(dto.ScreenSendBack is 2,
+                x => x.OrderScreens.Any(s => (s.Status != EScreenStatus.SendBack && s.ScreenType == dto.ScreenType && s.SendBackApply != true)) ==
+                     false)
             .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order!.No!.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order!.Title!.Contains(dto.Title!))
             .WhereIF(dto.IsProvince.HasValue, x => x.OrderVisit.Order!.IsProvince == dto.IsProvince)
@@ -2037,7 +2045,9 @@ public class OrderController : BaseController
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
                     SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
                 ))
-                .WhereIF(dto.ScreenType == EOrderScreenType.Seat, x => x.VisitTarget == EVisitTarget.Seat && (x.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied || x.SeatEvaluate == ESeatEvaluate.NoSatisfied))
+                .WhereIF(dto.ScreenType == EOrderScreenType.Seat,
+                    x => x.VisitTarget == EVisitTarget.Seat &&
+                         (x.SeatEvaluate == ESeatEvaluate.VeryNoSatisfied || x.SeatEvaluate == ESeatEvaluate.NoSatisfied))
                 ;
         }
 
@@ -2118,13 +2128,15 @@ public class OrderController : BaseController
         if (screenAny)
             throw UserFriendlyException.SameMessage("该工单已提起甄别申请,正在审批过程中,不能申请");
 
-        var isNoPass = await _orderScreenRepository.AnyAsync(x => x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId);
+        var isNoPass = await _orderScreenRepository.AnyAsync(x =>
+            x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId);
         if (isNoPass)
             throw UserFriendlyException.SameMessage("该工单已被拒绝过甄别申请,不能再次申请");
 
         var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyNum);
         int count = await _orderScreenRepository.CountAsync(x =>
-            x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId);
+            x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType &&
+            x.VisitDetailId == dto.Data.VisitDetailId);
         if (count > int.Parse(setting?.SettingValue[0]) && int.Parse(setting?.SettingValue[0]) > -1)
             throw UserFriendlyException.SameMessage("甄别申请已超过系统预定设置,不能申请");
 
@@ -2453,10 +2465,12 @@ public class OrderController : BaseController
                 {
                 }
             }
+
             var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
             CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
             //推省上
-            if (!string.IsNullOrEmpty(model.Id) && (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
+            if (!string.IsNullOrEmpty(model.Id) &&
+                (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
             {
                 var orderDto = _mapper.Map<OrderDto>(order);
                 var supervise = await _orderSuperviseRepository.GetAsync(x => x.Id == model.Id);
@@ -2699,10 +2713,12 @@ public class OrderController : BaseController
                 {
                 }
             }
+
             var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
             CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
             //推省上
-            if (!string.IsNullOrEmpty(model.Id) && (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
+            if (!string.IsNullOrEmpty(model.Id) &&
+                (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId)))
             {
                 var orderDto = _mapper.Map<OrderDto>(order);
                 var urge = await _orderUrgeRepository.GetAsync(x => x.Id == model.Id);
@@ -2819,7 +2835,7 @@ public class OrderController : BaseController
     public async Task<IReadOnlyList<OrderDto>> QueryFixed([FromQuery] QueryOrderFixedDto dto)
     {
         var hasSetting = Int32.TryParse(
-         _systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0], out var queryCount);
+            _systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0], out var queryCount);
         var query = _orderApplication.QueryOrders(dto);
         var orders = await query.ToFixedListAsync(dto.QueryIndex, hasSetting ? queryCount : null, HttpContext.RequestAborted);
         return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
@@ -2932,7 +2948,7 @@ public class OrderController : BaseController
             .Includes(d => d.OrderDelays)
             .Includes(d => d.OrderPublish)
             .Includes(d => d.OrderPushTypes)
-            .Includes(d=>d.OrderComplements)
+            .Includes(d => d.OrderComplements)
             //.Includes(d => d.OrderScreens)
             .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.OrderVisitDetails)
             .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.Employee)
@@ -2961,16 +2977,10 @@ public class OrderController : BaseController
                 var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
                 var settingStr = setting?.SettingValue;
                 var roles = _sessionContext.Roles;
-                foreach (var item in settingStr)
+                if ((settingStr?.Any() ?? false) && roles.Any())
                 {
-                    if (roles != null && roles.Contains(item))
-                    {
-                        canInsteadHandle = true;
-                    }
-                    else
-                    {
-                        canInsteadHandle = false;
-                    }
+                    var intersectRoles = settingStr.Intersect(roles);
+                    canInsteadHandle = intersectRoles.Any();
                 }
 
                 if (canInsteadHandle)
@@ -3015,16 +3025,31 @@ public class OrderController : BaseController
                 }
             }
 
-            order.CurrentStepAcceptTime = DateTime.Now;
-            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-
-            result.Workflow.UpdateCurrentStepAcceptTime(order.CurrentStepAcceptTime.Value);
-            await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
-                _sessionContext.RequiredUserId, _sessionContext.UserName,
-                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-                _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
+            //
+            // order.CurrentStepAcceptTime = DateTime.Now;
+            // await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+            //
+            // result.Workflow.UpdateCurrentStepAcceptTime(order.CurrentStepAcceptTime.Value);
+            // await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
+            //     _sessionContext.RequiredUserId, _sessionContext.UserName,
+            //     _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+            //     _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
+            if (result.CanHandle)
+            {
+                var acceptTime = await _workflowDomainService.AcceptAsync(result.Workflow,
+                    _sessionContext.RequiredUserId, _sessionContext.UserName,
+                    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+                    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
+                    HttpContext.RequestAborted);
+                if (acceptTime != null)
+                {
+                    order.ActualHandleStepAcceptTime = acceptTime;
+                    await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+                }
+            }
         }
 
+        dto.IsRed = string.IsNullOrEmpty(dto.SignerId) || !order.ActualHandleStepAcceptTime.HasValue;
 
         //var dto = _mapper.Map<OrderDto>(order!);
         //dto.CountersignId = countersignId;
@@ -3122,7 +3147,7 @@ public class OrderController : BaseController
                 cancellationToken: HttpContext.RequestAborted);
 
             List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto
-            { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
+                { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
             dto.OrderRemarks = remarks;
             if (order.Status == EOrderStatus.SendBack || order.Status == EOrderStatus.SendBackAudit || order.Status == EOrderStatus.BackToUnAccept)
             {
@@ -3171,10 +3196,12 @@ public class OrderController : BaseController
         {
             dto.ProvinceRevokeString = "该工单已由省平台发送撤单!请直接归档办理!";
         }
+
         //终止
         var orderTerminateList = await _orderTerminateRepository.Queryable().Where(x => x.OrderId == order.Id).ToListAsync();
-        dto.OrderTerminateStatus = orderTerminateList.Any(x => x.Status == ETerminateStatus.End) ? "同意" : orderTerminateList.Any(x => x.Status == ETerminateStatus.Refuse) ?
-            "不同意" : orderTerminateList.Any(x => x.Status == ETerminateStatus.Approval || x.Status == ETerminateStatus.SendBack) ? "审批中" : null;
+        dto.OrderTerminateStatus = orderTerminateList.Any(x => x.Status == ETerminateStatus.End) ? "同意" :
+            orderTerminateList.Any(x => x.Status == ETerminateStatus.Refuse) ? "不同意" :
+            orderTerminateList.Any(x => x.Status == ETerminateStatus.Approval || x.Status == ETerminateStatus.SendBack) ? "审批中" : null;
 
 
         return _sessionContext.OrgIsCenter ? dto : dto.DataMask();
@@ -3485,7 +3512,7 @@ public class OrderController : BaseController
         //敏感分词
         await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
 
-        return new { Id = order.Id, No = order.No, Password = order.Password , CallId = order.CallId};
+        return new { Id = order.Id, No = order.No, Password = order.Password, CallId = order.CallId };
     }
 
     /// <summary>
@@ -3531,6 +3558,7 @@ public class OrderController : BaseController
                 expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, EFlowDirection.CenterToOrg, order.Adapt<OrderTimeClacInfo>());
             }
         }
+
         order.IsForwarded = dto.Workflow.IsForwarded;
         _mapper.Map(expiredTimeConfig, order);
 
@@ -3557,9 +3585,9 @@ public class OrderController : BaseController
             var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
             startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle;
             startDto.Title = order.Title;
-            var startStep = await _workflowDomainService.StartAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
+            var (workflow,startStep) = await _workflowDomainService.StartAsync(startDto, order.Id, order.ExpiredTime, HttpContext.RequestAborted);
 
-            await HandleOrderAsync(order, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);
+            await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);
         }
         catch (Exception e)
         {
@@ -3588,6 +3616,7 @@ public class OrderController : BaseController
         {
             outDto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted);
         }
+
         return outDto;
     }
 
@@ -3606,43 +3635,10 @@ public class OrderController : BaseController
 
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.Workflow.WorkflowId, withSteps: true, withTraces: true,
             cancellationToken: HttpContext.RequestAborted);
-        //1.是否是判断节点  2.是否存在历史派单节点  3.存在获取上个派单节点  4.不存在走平均派单
-        if (dto.Data.OrderAssignMode is EOrderAssignMode.AdjoinLevel && dto.Workflow.BusinessType == EBusinessType.Send)
-        {
-            var sendOrderTraces = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send);
-            if (sendOrderTraces.Any())
-            {
-                var sendOrderTrace = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send)
-                    .OrderByDescending(x => x.CreationTime)
-                    .FirstOrDefault();
-                dto.Workflow.NextHandlers = new List<FlowStepHandler>
-                {
-                    new FlowStepHandler()
-                    {
-                        Key = sendOrderTrace.HandlerId, Value = sendOrderTrace.HandlerName,
-                        UserId = sendOrderTrace.HandlerId, Username = sendOrderTrace.HandlerName,
-                        OrgId = sendOrderTrace.HandlerOrgId, OrgName = sendOrderTrace.HandlerOrgName
-                    }
-                };
-            }
-            else
-            {
-                // 平均派单
-                var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
-                if (averageSendOrder)
-                {
-                    if (!dto.Workflow.NextHandlers.Any())
-                    {
-                        var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
-                        dto.Workflow.NextHandlers = new List<FlowStepHandler> { handler };
-                    }
-                }
-            }
-        }
 
         //await _workflowApplication.NextAsync(dto.WorkflowDto, order.ExpiredTime, HttpContext.RequestAborted);
         var startStep = workflow.Steps.First(d => d.Id == dto.Workflow.StepId);
-        await HandleOrderAsync(order, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);
+        await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted);
 
         if (_appOptions.Value.IsZiGong && dto.Data.Transpond.HasValue && dto.Data.Transpond.Value)
         {
@@ -3655,7 +3651,9 @@ public class OrderController : BaseController
         }
     }
 
-    private async Task HandleOrderAsync(Order order, WorkflowStep startStep, OrderHandleFlowDto orderHandleFlowDto, BasicWorkflowDto workflowDto, CancellationToken cancellationToken)
+    private async Task HandleOrderAsync(Order order, Workflow workflow, WorkflowStep startStep, OrderHandleFlowDto orderHandleFlowDto,
+        BasicWorkflowDto workflowDto,
+        CancellationToken cancellationToken)
     {
         switch (orderHandleFlowDto.OrderAssignMode)
         {
@@ -3664,15 +3662,53 @@ public class OrderController : BaseController
                 nextDto.WorkflowId = startStep.WorkflowId;
                 nextDto.StepId = startStep.Id;
 
-                // 平均派单
-                var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder)
-                    .SettingValue[0]);
-                if (workflowDto.BusinessType == EBusinessType.Send && averageSendOrder)
+                // 宜宾需求: 1.是否是判断节点  2.是否存在历史派单节点  3.存在获取上个派单节点  4.不存在走平均派单
+                if (workflowDto.BusinessType == EBusinessType.Send)
                 {
-                    if (!nextDto.NextHandlers.Any())
+                    if (_appOptions.Value.IsYiBin)
                     {
-                        var handler = await _orderDomainService.AverageOrder(cancellationToken);
-                        nextDto.NextHandlers = new List<FlowStepHandler> { handler };
+                        var sendOrderTraces = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send);
+                        if (sendOrderTraces.Any())
+                        {
+                            var sendOrderTrace = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send)
+                                .OrderByDescending(x => x.CreationTime)
+                                .FirstOrDefault();
+                            nextDto.NextHandlers = new List<FlowStepHandler>
+                            {
+                                new FlowStepHandler()
+                                {
+                                    Key = sendOrderTrace.HandlerId, Value = sendOrderTrace.HandlerName,
+                                    UserId = sendOrderTrace.HandlerId, Username = sendOrderTrace.HandlerName,
+                                    OrgId = sendOrderTrace.HandlerOrgId, OrgName = sendOrderTrace.HandlerOrgName
+                                }
+                            };
+                        }
+                        else
+                        {
+                            // 平均派单
+                            var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                            if (averageSendOrder)
+                            {
+                                if (!nextDto.NextHandlers.Any())
+                                {
+                                    var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted);
+                                    nextDto.NextHandlers = new List<FlowStepHandler> { handler };
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // 平均派单
+                        var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
+                        if (averageSendOrder)
+                        {
+                            if (!nextDto.NextHandlers.Any())
+                            {
+                                var handler = await _orderDomainService.AverageOrder(cancellationToken);
+                                nextDto.NextHandlers = new List<FlowStepHandler> { handler };
+                            }
+                        }
                     }
                 }
 
@@ -3685,7 +3721,7 @@ public class OrderController : BaseController
                 orderHandleFlowDto.CrossSteps = orderHandleFlowDto.CrossSteps.OrderBy(d => d.Sort).ToList();
                 var stepCount = orderHandleFlowDto.CrossSteps.Count;
                 var unhandleSteps = new List<WorkflowStep> { startStep };
-                for (int i = 0;i < stepCount;i++)
+                for (int i = 0; i < stepCount; i++)
                 {
                     var crossStep = orderHandleFlowDto.CrossSteps[i];
                     var tempSteps = new List<WorkflowStep>();
@@ -3709,6 +3745,7 @@ public class OrderController : BaseController
                         var nextSteps = await _workflowDomainService.NextAsync(operater, nextflowDto, order.ExpiredTime, cancellationToken);
                         tempSteps.AddRange(nextSteps);
                     }
+
                     unhandleSteps = tempSteps;
                 }
 
@@ -3773,7 +3810,8 @@ public class OrderController : BaseController
     [HttpPost("steps/temp")]
     public async Task TempSaveAsync([FromBody] StepTempInDto dto)
     {
-        await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(3), HttpContext.RequestAborted);
+        await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(3),
+            HttpContext.RequestAborted);
     }
 
     /// <summary>
@@ -3996,7 +4034,8 @@ public class OrderController : BaseController
         {
             query.WhereIF(dto.QueryType is 1, d => d.IsForwarded == false)
                 .WhereIF(dto.QueryType is 2, d => d.IsForwarded == true)
-                .Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.SpecialType == ESpecialType.ReTransact).NotAny());
+                .Where(d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.SpecialType == ESpecialType.ReTransact)
+                    .NotAny());
         }
 
         var (total, items) = await query
@@ -4004,7 +4043,8 @@ public class OrderController : BaseController
                         d.Status != EOrderStatus.BackToUnAccept &&
                         d.Status != EOrderStatus.SpecialToUnAccept &&
                         d.Status != EOrderStatus.HandOverToUnAccept)
-            .WhereIF(dto.QueryType is 3, d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.SpecialType == ESpecialType.ReTransact).Any())
+            .WhereIF(dto.QueryType is 3,
+                d => SqlFunc.Subqueryable<OrderSpecial>().Where(os => os.OrderId == d.Id && os.SpecialType == ESpecialType.ReTransact).Any())
             .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)
@@ -4827,22 +4867,31 @@ public class OrderController : BaseController
             //{
             // var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
 
-            ExpiredTimeWithConfig? expiredTime = null;
-            if (_appOptions.Value.IsZiGong)
-            {
-                if (dto.FlowDirection != null)
-                {
-                    expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, dto.FlowDirection.Value, order.Adapt<OrderTimeClacInfo>());
-                }
-                else
-                {
-                    expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-                }
-            }
-            else
+            ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig();
+
+            if (dto.FlowDirection is EFlowDirection.OrgToOrg)
             {
-                expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            }
+	            expiredTime.ExpiredTime = order.ExpiredTime.Value;
+	            expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
+	            expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
+			}
+            else {
+				if (_appOptions.Value.IsZiGong)
+				{
+					if (dto.FlowDirection != null)
+					{
+						expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, dto.FlowDirection.Value, order.Adapt<OrderTimeClacInfo>());
+					}
+					else
+					{
+						expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+					}
+				}
+				else
+				{
+					expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+				}
+			}
 
             var processType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                 ? EProcessType.Zhiban
@@ -4858,13 +4907,13 @@ public class OrderController : BaseController
             //	ETimeType.WorkDay,
             //	dto.TimeLimit.Value, order.AcceptTypeCode);
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-            {
-                ExpiredTime = expiredTime.ExpiredTime,
-                NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                ProcessType = processType,
-                Status = EOrderStatus.Special
-            })
+                {
+                    ExpiredTime = expiredTime.ExpiredTime,
+                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                    ProcessType = processType,
+                    Status = EOrderStatus.Special
+                })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5020,11 +5069,11 @@ public class OrderController : BaseController
 
                 endTime = expiredTime.EndTime;
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-                {
-                    ExpiredTime = expiredTime.EndTime,
-                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne
-                })
+                    {
+                        ExpiredTime = expiredTime.EndTime,
+                        NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                        NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne
+                    })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5116,26 +5165,50 @@ public class OrderController : BaseController
                 HandlerType = special.HandlerType.Value,
                 BusinessType = special.BusinessType.Value
             };
-            //if (dto.AlterTime)
-            //    recall.External = new External { TimeLimit = dto.TimeLimit, TimeLimitUnit = dto.TimeLimitUnit };
-            //if (dto.Files.Any()) recall.Files = dto.Files;
-            // 计算期满时间
-            //if (dto.AlterTime)
-            //{
-            //var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            var expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-            //var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-            var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
+			ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig();
+
+			if (dto.FlowDirection is EFlowDirection.OrgToOrg)
+			{
+				expiredTime.ExpiredTime = order.ExpiredTime.Value;
+				expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
+				expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
+			}
+			else
+			{
+				if (_appOptions.Value.IsZiGong)
+				{
+					if (dto.FlowDirection != null)
+					{
+						expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, dto.FlowDirection.Value, order.Adapt<OrderTimeClacInfo>());
+					}
+					else
+					{
+						expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+					}
+				}
+				else
+				{
+					expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+				}
+			}
+			if (expiredTime.ExpiredTime < order.ExpiredTime)
+			{
+				expiredTime.ExpiredTime = order.ExpiredTime.Value;
+				expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
+				expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
+			}
+
+			var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                 ? EProcessType.Zhiban
                 : EProcessType.Jiaoban;
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-            {
-                ExpiredTime = expiredTime.ExpiredTime,
-                NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                ProcessType = processType,
-                Status = EOrderStatus.Special
-            })
+                {
+                    ExpiredTime = expiredTime.ExpiredTime,
+                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                    ProcessType = processType,
+                    Status = EOrderStatus.Special
+                })
                 .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
             var orderDto = _mapper.Map<OrderDto>(order);
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5180,18 +5253,6 @@ public class OrderController : BaseController
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
                     new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                     cancellationToken: HttpContext.RequestAborted);
-
-                //try
-                //{
-                //    await _provinceService.RevokeOrder(
-                //        new PublishSpecialDto
-                //        { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
-                //        HttpContext.RequestAborted);
-                //}
-                //catch (Exception e)
-                //{
-                //    _logger.LogError("_provinceService.RevokeOrder throw exception: {ex}", e.Message);
-                //}
             }
         }
         else
@@ -5239,26 +5300,49 @@ public class OrderController : BaseController
                     HandlerType = special.HandlerType.Value,
                     BusinessType = special.BusinessType.Value
                 };
-                //if (dto.AlterTime)
-                //    recall.External = new External { TimeLimit = dto.TimeLimit, TimeLimitUnit = dto.TimeLimitUnit };
-                //if (dto.Files.Any()) recall.Files = dto.Files;
-                // 计算期满时间
-                //if (dto.AlterTime)
-                //{
-                // var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-                var expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
-                //var processType = dto.FlowDirection == EFlowDirection.OrgToCenter || dto.FlowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban;
-                var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
+				ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig();
+
+				if (dto.FlowDirection is EFlowDirection.OrgToOrg)
+				{
+					expiredTime.ExpiredTime = order.ExpiredTime.Value;
+					expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
+					expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
+				}
+				else
+				{
+					if (_appOptions.Value.IsZiGong)
+					{
+						if (dto.FlowDirection != null)
+						{
+							expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, dto.FlowDirection.Value, order.Adapt<OrderTimeClacInfo>());
+						}
+						else
+						{
+							expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+						}
+					}
+					else
+					{
+						expiredTime = await _expireTime.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+					}
+				}
+				if (expiredTime.ExpiredTime < order.ExpiredTime)
+				{
+					expiredTime.ExpiredTime = order.ExpiredTime.Value;
+					expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value;
+					expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value;
+				}
+				var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter
                     ? EProcessType.Zhiban
                     : EProcessType.Jiaoban;
                 await _orderRepository.Updateable().SetColumns(o => new Orders.Order()
-                {
-                    ExpiredTime = expiredTime.ExpiredTime,
-                    NearlyExpiredTime = expiredTime.NearlyExpiredTime,
-                    NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
-                    ProcessType = processType,
-                    Status = EOrderStatus.Special
-                })
+                    {
+                        ExpiredTime = expiredTime.ExpiredTime,
+                        NearlyExpiredTime = expiredTime.NearlyExpiredTime,
+                        NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne,
+                        ProcessType = processType,
+                        Status = EOrderStatus.Special
+                    })
                     .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted);
                 var orderDto = _mapper.Map<OrderDto>(order);
                 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
@@ -5293,27 +5377,17 @@ public class OrderController : BaseController
                         await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted);
                     }
                 }
+
                 var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0];
                 CityBaseConfiguration cityBase = JsonSerializer.Deserialize<CityBaseConfiguration>(setting);
                 if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) ||
-                                      cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) || cityBase.CityEnterprise.OrgId.Equals(special.OrgId) ||
+                                      cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) ||
+                                      cityBase.CityEnterprise.OrgId.Equals(special.OrgId) ||
                                       cityBase.PublicSecurity.OrgId.Equals(special.OrgId)))
                 {
                     await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled,
                         new PublishSpecialDto { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
                         cancellationToken: HttpContext.RequestAborted);
-
-                    //try
-                    //{
-                    //    await _provinceService.RevokeOrder(
-                    //        new PublishSpecialDto
-                    //        { Order = _mapper.Map<OrderDto>(order), Special = _mapper.Map<OrderSpecialDto>(special) },
-                    //        HttpContext.RequestAborted);
-                    //}
-                    //catch (Exception e)
-                    //{
-                    //    _logger.LogError("_provinceService.RevokeOrder throw exception: {ex}", e.Message);
-                    //}
                 }
             }
             else
@@ -5411,7 +5485,7 @@ public class OrderController : BaseController
                 d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型
-                                                                                                     //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
+            //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
             .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel) //来源渠道
             .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot))
             .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!))
@@ -5505,7 +5579,8 @@ public class OrderController : BaseController
             SpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
             InstaShotSpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason),
             Step = step,
-            IsTerminate = await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
+            IsTerminate =
+                await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
             BaseTypeId = baseTypeId
         };
         return rsp;
@@ -5534,7 +5609,8 @@ public class OrderController : BaseController
                 ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason)
                 : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
             ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType),
-            IsTerminate = await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
+            IsTerminate =
+                await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(),
             Step = step,
             Orgs = orgs,
         };
@@ -7015,7 +7091,7 @@ public class OrderController : BaseController
 
         foreach (var item in dto.Ids)
         {
-            var orderData = await _orderRepository.GetAsync(p => p.Id == item, HttpContext.RequestAborted);
+            var orderData = await _orderRepository.GetAsync(p => p.Id == item || p.ProvinceNo == item, HttpContext.RequestAborted);
 
             if (orderData != null)
             {
@@ -7146,7 +7222,7 @@ public class OrderController : BaseController
         {
             await _orderRepository.Updateable()
                 .SetColumns(o => new Orders.Order()
-                { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept })
+                    { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept })
                 .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted);
         }
         else

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

@@ -660,7 +660,7 @@ namespace Hotline.Api.Controllers
         public async Task<OpenResponse> GetOrderByListAllOpen([FromBody] QueryOrderListDto dto)
         {
             var queryNew = _orderRepository.Queryable()
-                .LeftJoin<OrderPublish>((p,op)=>p.Id==op.OrderId)
+                .LeftJoin<OrderPublish>((p, op) => p.Id == op.OrderId)
                 .Where(p => p.IsPublicity == true)
                 .WhereIF(!string.IsNullOrEmpty(dto.FlowCode), (p, op) => p.No == dto.FlowCode)
                 .WhereIF(!string.IsNullOrEmpty(dto.FlowName), (p, op) => p.Title.Contains(dto.FlowName))
@@ -850,6 +850,10 @@ namespace Hotline.Api.Controllers
         [HttpPost("orderacceptance")]
         public async Task<OpenResponse> OrderAcceptance([FromBody] WebFlowAccept dto)
         {
+            //电话号码去空格
+            if (!string.IsNullOrEmpty(dto.Mobile))
+                dto.Mobile = dto.Mobile.Trim();
+
             var data = _mapper.Map<Hotline.Share.Dtos.Order.AddOrderDto>(dto);
             if (string.IsNullOrEmpty(data.SourceChannelCode))
             {

+ 10 - 0
src/Hotline.Api/Hotline.Api.csproj

@@ -32,6 +32,7 @@
     <None Update="Template\AssignmentForm.doc">
       <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </None>
+    <None Remove="logs\**" />
   </ItemGroup>
 
   <ItemGroup>
@@ -40,6 +41,15 @@
 
   <ItemGroup>
     <Compile Remove="Controllers\Order\OrderComplementController.cs" />
+    <Compile Remove="logs\**" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <EmbeddedResource Remove="logs\**" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Content Remove="logs\**" />
   </ItemGroup>
 
 </Project>

+ 1 - 1
src/Hotline.Api/StartupExtensions.cs

@@ -235,7 +235,7 @@ internal static class StartupExtensions
         //app.MapSubscribeHandler();
 
         // 记录交互日志
-        app.UseRequestResponseLogging(app.Configuration);
+        //app.UseRequestResponseLogging(app.Configuration);
         return app;
     }
 }

+ 12 - 3
src/Hotline.Api/StartupHelper.cs

@@ -268,7 +268,8 @@ namespace Hotline.Api
                     .StartNow()
                     .WithCronSchedule("0 30 09,14 * * ?"));
 
-                switch (appConfiguration.AppScope)
+                var autoSendOrderKey = new JobKey(nameof(SendOrderJob), "send order task");
+				switch (appConfiguration.AppScope)
                 {
                     //智能化任务
                     case AppDefaults.AppScope.YiBin:
@@ -280,7 +281,6 @@ namespace Hotline.Api
                         .StartNow()
                         .WithCronSchedule("0 0/5 * * * ? *"));
 
-                        var autoSendOrderKey = new JobKey(nameof(SendOrderJob), "send order task");
                         d.AddJob<SendOrderJob>(autoSendOrderKey);
                         d.AddTrigger(t => t
                             .WithIdentity("task-send-order-trigger")
@@ -289,7 +289,16 @@ namespace Hotline.Api
                             .WithCronSchedule("0 10 9 * * ?")
                         );
                         break;
-                    default:
+                    case AppDefaults.AppScope.ZiGong:
+	                    d.AddJob<SendOrderJob>(autoSendOrderKey);
+	                    d.AddTrigger(t => t
+		                    .WithIdentity("task-send-order-trigger")
+		                    .ForJob(autoSendOrderKey)
+		                    .StartNow()
+		                    .WithCronSchedule("0 10 9 * * ?")
+	                    );
+						break;
+					default:
                         break;
                 }
 

+ 1 - 1
src/Hotline.Api/config/appsettings.Development.json

@@ -71,7 +71,7 @@
     "Database": 5 //release:3, dev:5
   },
   "Swagger": true,
-  "AccLog":  true,
+  "AccLog":  false,
   "Cors": {
     "Origins": [ "http://localhost:8888", "http://admin.hotline.fw.com", "http://localhost:80", "http://localhost:8113" ]
   },

+ 16 - 12
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -36,6 +36,7 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.Options;
 using Newtonsoft.Json;
 using NPOI.SS.Formula.Functions;
+using DocumentFormat.OpenXml.Drawing;
 
 namespace Hotline.Application.FlowEngine;
 
@@ -156,7 +157,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var flowAssignInfo =
             await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
 
-        var counterSignType = _workflowDomainService.GetCounterSignType(dto.IsStartCountersign);
+        var counterSignType = _workflowDomainService.GetCounterSignType(dto.IsStartCountersign, startStep.BusinessType);
 
         //办理开始节点
         await _workflowDomainService.HandleStepAsync(startStep, workflow, dto, counterSignType, expiredTime, cancellationToken);
@@ -493,7 +494,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
         //结束会签
         var counstersigns = await _workflowCountersignRepository.Queryable()
-            .Where(d => !d.IsCompleted())
+            .Where(d => !d.EndTime.HasValue)
             .ToListAsync(cancellationToken);
         foreach (var counstersign in counstersigns)
         {
@@ -507,14 +508,14 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         await _workflowCountersignRepository.UpdateRangeAsync(counstersigns, cancellationToken);
 
 
-        //更新实际办理节点信息
-        workflow.UpdateActualStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-
-        workflow.UpdateCurrentStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+        // //更新实际办理节点信息
+        // workflow.UpdateActualStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+        //
+        // workflow.UpdateCurrentStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
 
         if (workflow.Steps.All(d => d.StepType != EStepType.End))
         {
-            await _workflowDomainService.EndAsync(workflow, dto,
+            await _workflowDomainService.EndAsync(current, workflow, dto,
                 endStepDefine, currentStep, expiredTime, cancellationToken);
         }
     }
@@ -552,6 +553,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
 
         return new NextStepsDto<NextStepOption>
         {
+            TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             Steps = await GetConfigStepsAsync(definition.FlowType, startStepDefine.StepType, startStepDefine.BusinessType,
                 firstStepDefines, cancellationToken)
         };
@@ -663,6 +665,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             //ExpiredTime = workflow.ExpiredTime,
             CanStartCountersign = currentStep.CanStartCountersign,
             CurrentStepBusinessType = currentStep.BusinessType,
+            CurrentStepType = currentStep.StepType,
+            CurrentHandlerType = currentStep.HandlerType,
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
             StepId = currentStep.Id,
@@ -1544,7 +1548,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// </summary>
     /// <returns></returns>
     private async Task<NextStepOption> GetDynamicStepAsync(
-        EDynamicPolicyCountersign policy, EStepType stepType,
+        ECountersignPolicy policy, EStepType stepType,
         EBusinessType currentBusinessType, CancellationToken cancellationToken)
     {
         int orgLevel;
@@ -1554,7 +1558,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         EFlowDirection? flowDirection = null;
         switch (policy)
         {
-            case EDynamicPolicyCountersign.OrgUpCenterTop:
+            case ECountersignPolicy.OrgUpCenterTop:
                 orgLevel = _sessionContextProvider.SessionContext.OrgLevel - 1;
                 if (orgLevel < 0) orgLevel = 0;
 
@@ -1594,7 +1598,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 }
 
                 break;
-            case EDynamicPolicyCountersign.OrgUp:
+            case ECountersignPolicy.OrgUp:
                 businessType = _sessionContextProvider.SessionContext.OrgIsCenter
                     ? EBusinessType.Send
                     : _sessionContextProvider.SessionContext.RequiredOrgId.CalcOrgLevel() == 1
@@ -1615,7 +1619,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                     })
                     .ToListAsync(cancellationToken);
                 break;
-            case EDynamicPolicyCountersign.OrgDownCenterTop:
+            case ECountersignPolicy.OrgDownCenterTop:
                 businessType = EBusinessType.Department;
                 if (_sessionContextProvider.SessionContext.OrgIsCenter)
                 {
@@ -1648,7 +1652,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 }
 
                 break;
-            case EDynamicPolicyCountersign.OrgDown:
+            case ECountersignPolicy.OrgDown:
                 businessType = EBusinessType.Department;
                 orgLevel = _sessionContextProvider.SessionContext.OrgLevel + 1;
                 items = await _organizeRepository.Queryable()

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

@@ -141,7 +141,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
 
                     if (data.FlowDirection is EFlowDirection.CenterToOrg)
                         order.SendBackAuditEndTime = await _expireTime.GetWorkDay(DateTime.Now);
-                    await _orderRepository.UpdateAsync(order, cancellationToken);
+                    await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
 
                     //司法行政监督管理-推诿工单
                     //如果没开启则不处理

+ 4 - 2
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -53,8 +53,9 @@ namespace Hotline.Application.Jobs
         {
             var xingtangCalls = await _db.Queryable<XingtangCall>()
                 .Where(d => !string.IsNullOrEmpty(d.CallGuid) &&
-                                (d.IsSync == null || !d.IsSync) &&
-                                (d.Tries == null || d.Tries <= 50))
+                            !string.IsNullOrEmpty(d.Caller) &&
+                            (d.IsSync == null || !d.IsSync) &&
+                            (d.Tries == null || d.Tries <= 50))
                 .OrderBy(d => d.Id)
                 .Take(10)
                 .ToListAsync(context.CancellationToken);
@@ -106,6 +107,7 @@ namespace Hotline.Application.Jobs
                             }
                         }
                     }
+
                     if (call.GroupId == "0" && call.CallState != ECallState.IVRNoAccept)
                     {
                         call.CallState = ECallState.Invalid;

+ 7 - 6
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -15,12 +15,13 @@ public class OrderMapperConfigs : IRegister
         config.ForType<Order, OrderDto>()
             .IgnoreIf((s, d) => s.OrderExtension == null, d => d.OrderExtension)
             .IgnoreIf((s, d) => s.Hotspot == null, d => d.Hotspot)
+            .Map(d => d.IsRed, s => string.IsNullOrEmpty(s.SignerId) || !s.ActualHandleStepAcceptTime.HasValue)
             ;
 
         config.ForType<OrderCopy, OrderDto>()
-          .Map(d => d.Id, s => s.OrderId)
-          .Map(d => d.CopyId, s => s.Id)
-           ;
+            .Map(d => d.Id, s => s.OrderId)
+            .Map(d => d.CopyId, s => s.Id)
+            ;
 
         config.ForType<AiOrderVisitDetail, AiOrderVisitDetailDto>()
             .IgnoreIf((s, d) => s.Order == null, d => d.No)
@@ -110,6 +111,7 @@ public class OrderMapperConfigs : IRegister
             .Ignore(d => d.AcceptorName)
             .Ignore(d => d.AcceptorStaffNo)
             .Ignore(d => d.ExternalId)
+            .Ignore(d=>d.CreationTime)
             //.AfterMapping((s, d) =>
             //{
             //    //d.UpdateHandlingStatus(s.IsInCountersign);
@@ -130,7 +132,6 @@ public class OrderMapperConfigs : IRegister
 
 
         config.ForType<OrderPublish, PublishedDto>()
-
             .Map(d => d.PublishState, s => s.PublishState)
             .Map(d => d.ArrangeContent, s => s.ArrangeContent)
             .Map(d => d.PublishTime, s => s.CreationTime)
@@ -167,7 +168,7 @@ public class OrderMapperConfigs : IRegister
         config.ForType<OrderScreen, OrderScreenListDto>()
             .IgnoreIf((s, d) => s.VisitDetail == null, d => d.VisitDetail)
             ;
-        
+
         config.ForType<OrderHandleFlowDto, Workflow>()
             .Map(d => d.RealHandlerPhone, s => s.RealHandlerPhone)
             .Map(d => d.RealHandlerName, s => s.RealHandlerName)
@@ -181,7 +182,7 @@ public class OrderMapperConfigs : IRegister
         config.ForType<OrderHandleFlowDto, Order>()
             .Map(src => src.RealCommunicationAddress, dest => dest.RealCommunicationAddress)
             .IgnoreIf((src, dest) => string.IsNullOrEmpty(src.RealCommunicationAddress), dest => dest.RealCommunicationAddress)
-            .Map(src => src.RealHandlerPhone , dest => dest.RealHandlerPhone)
+            .Map(src => src.RealHandlerPhone, dest => dest.RealHandlerPhone)
             .IgnoreIf((src, dest) => string.IsNullOrEmpty(src.RealHandlerPhone), dest => dest.RealHandlerPhone)
             .Map(src => src.RealHandlerName, dest => dest.RealHandlerName)
             .IgnoreIf((src, dest) => string.IsNullOrEmpty(src.RealHandlerName), dest => dest.RealHandlerName)

+ 1 - 1
src/Hotline.Application/StatisticalReport/CallReport/CallReportApplicationBase.cs

@@ -212,7 +212,7 @@ public abstract class CallReportApplicationBase : ICallReportApplication
         int connectByeTimes = _systemSettingCacheManager.ConnectByeTimes;
         var query = _callNativeRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((c, o) => c.Id == o.CallId)
-            .Where(m => m.CallState != ECallState.Invalid)
+            .Where((c, o) => c.CallState != ECallState.Invalid)
             .WhereIF(dto.OrderNo.NotNullOrEmpty(), (c, o) => o.No == dto.OrderNo)
             .WhereIF(dto.FromNo.NotNullOrEmpty(), (c, o) => c.FromNo == dto.FromNo)
             .WhereIF(dto.ToNo.NotNullOrEmpty(), (c, o) => c.ToNo == dto.ToNo)

+ 13 - 4
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -557,7 +557,7 @@ namespace Hotline.Application.Subscribers
                 .Includes(x => x.Order)
                 .Includes(x => x.OrderVisitDetails)
                 .Where(x => x.Order.ReceiveProvinceNo == dto.ProvinceNo &&
-                            x.VisitState != Share.Enums.Order.EVisitState.None).FirstAsync(cancellationToken);
+                            x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit).FirstAsync(cancellationToken);
 
             if (orderVisit != null)
             {
@@ -811,8 +811,17 @@ namespace Hotline.Application.Subscribers
                     break;
                 case "1":
                     //办结:归档
-                    await _workflowApplication.HandleToEndAsync(order.WorkflowId, dto.Opinion, dto.Files,
-                        cancellationToken: cancellationToken);
+                    if (order.Status >= EOrderStatus.Filed)
+                    {
+                        order.ActualOpinion += dto.Opinion;
+                        await _orderRepository.Updateable().UpdateColumns(d => d.ActualOpinion).ExecuteCommandAsync(cancellationToken);
+                        await _workflowDomainService.AppendFileOpinionAsync(order.WorkflowId, dto.Opinion, dto.Files, cancellationToken);
+                    }
+                    else
+                    {
+                        await _workflowApplication.HandleToEndAsync(order.WorkflowId, dto.Opinion, dto.Files, cancellationToken: cancellationToken);
+                    }
+
                     break;
             }
 
@@ -1151,7 +1160,7 @@ namespace Hotline.Application.Subscribers
                         .ToListAsync(cancellationToken);
                     if (!query.Any()) return;
                     var orderCalls = query
-                        .Where(d=>!string.IsNullOrEmpty(d.Call.Id))
+                        .Where(d => !string.IsNullOrEmpty(d.Call.Id))
                         .Select(d => new PublishCallRecrodDto
                         {
                             Order = _mapper.Map<OrderDto>(d.Order),

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/Definition/StepDefineBasic.cs

@@ -63,7 +63,7 @@ namespace Hotline.Share.Dtos.FlowEngine.Definition
         /// <summary>
         /// 会签策略
         /// </summary>
-        public EDynamicPolicyCountersign? CountersignPolicy { get; set; }
+        public ECountersignPolicy? CountersignPolicy { get; set; }
 
         #endregion
         

+ 13 - 0
src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs

@@ -34,11 +34,24 @@ public class NextStepsDto
     /// </summary>
     public EBusinessType CurrentStepBusinessType { get; set; }
 
+    /// <summary>
+    /// 模板配置节点类型
+    /// </summary>
+    public EStepType CurrentStepType { get; set; }
+
+    /// <summary>
+    /// 办理对象类型
+    /// </summary>
+    public EHandlerType CurrentHandlerType { get; set; }
+    
     /// <summary>
     /// 当前办理节点部门等级(非部门等级办理时无效)
     /// </summary>
     public int? CurrentOrgLevel { get; set; }
 
+    /// <summary>
+    /// 时间类型
+    /// </summary>
     public IReadOnlyList<KeyValuePair<int, string>> TimeTypeOptions { get; set; }
 
     /// <summary>

+ 1 - 1
src/Hotline.Share/Dtos/FlowEngine/Workflow/StepBasicDto.cs

@@ -136,7 +136,7 @@ namespace Hotline.Share.Dtos.FlowEngine.Workflow
         /// <summary>
         /// 会签策略
         /// </summary>
-        public EDynamicPolicyCountersign? CountersignPolicy { get; set; }
+        public ECountersignPolicy? CountersignPolicy { get; set; }
 
         #endregion
 

+ 2 - 0
src/Hotline.Share/Dtos/Knowledge/KnowledgeDto.cs

@@ -240,6 +240,8 @@ namespace Hotline.Share.Dtos.Knowledge
 
         public List<FileDto> Files { get; set; }
 
+        public List<FileJson>? FileJson { get; set; }
+
 	}
 
     public class KnowledgeBaseDto {

+ 55 - 20
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -19,17 +19,21 @@ namespace Hotline.Share.Dtos.Order
         /// 是否甄别
         /// </summary>
         public bool IsScreen { get; set; }
+
         public string No { get; set; }
 
         /// <summary>
         /// 当前节点名称
         /// </summary>
         public string CurrentStepName { get; set; }
+
         public DateTime CreationTime { get; set; }
+
         /// <summary>
         /// 工单状态
         /// </summary>
         public EOrderStatus Status { get; set; }
+
         public string StatusText => Status.GetDescription();
     }
 
@@ -41,6 +45,7 @@ namespace Hotline.Share.Dtos.Order
         /// 工单状态
         /// </summary>
         public EOrderStatus Status { get; set; }
+
         public string StatusText => Status.GetDescription();
 
         /// <summary>
@@ -74,9 +79,9 @@ namespace Hotline.Share.Dtos.Order
         public string No { get; set; }
 
         /// <summary>
-		/// 是否110来的工单
-		/// </summary>
-		public bool IsNo110 { get; set; }
+        /// 是否110来的工单
+        /// </summary>
+        public bool IsNo110 { get; set; }
 
         public string? TagNames { get; set; }
 
@@ -133,11 +138,11 @@ namespace Hotline.Share.Dtos.Order
 
         public string GetAllDurationHour()
         {
-
             if (Status >= EOrderStatus.Filed)
             {
                 return Math.Round(Math.Round((FiledTime - CreationTime).Value.TotalSeconds) / 60 / 60, 2).ToString() + "小时";
             }
+
             return "-";
         }
 
@@ -182,6 +187,8 @@ namespace Hotline.Share.Dtos.Order
         /// 实际办理节点签收时间
         /// </summary>
         public DateTime? ActualHandleStepAcceptTime { get; set; }
+        
+        public string ActualStepAcceptText => ActualHandleStepAcceptTime.HasValue ? "已签收" : "未签收";
 
         /// <summary>
         /// 实际办理时间
@@ -223,6 +230,7 @@ namespace Hotline.Share.Dtos.Order
         /// 办理时选择的办理对象,可能是部门也可能是用户
         /// </summary>
         public string? ActualHandlerValue { get; set; }
+
         public string? ActualHandlerKey { get; set; }
         public EHandlerType? ActualHandlerType { get; set; }
 
@@ -383,6 +391,7 @@ namespace Hotline.Share.Dtos.Order
         /// 会签类型
         /// </summary>
         public ECounterSignType? CounterSignType { get; set; }
+
         public string? CounterSignTypeText => CounterSignType?.GetDescription() ?? "未会签";
 
         #region 签收
@@ -401,7 +410,6 @@ namespace Hotline.Share.Dtos.Order
 
         #endregion
 
-
         #endregion
 
         public DateTime CreationTime { get; set; }
@@ -457,13 +465,19 @@ namespace Hotline.Share.Dtos.Order
         /// 是否可编辑
         /// </summary>
         public bool CanEdit => !string.IsNullOrEmpty(SignerId) &&
-                               (Status is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept or EOrderStatus.HandOverToUnAccept);
+                               (Status is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept
+                                   or EOrderStatus.HandOverToUnAccept);
 
         /// <summary>
         /// 是否可签收
         /// </summary>
         public bool CanSign => string.IsNullOrEmpty(SignerId);
 
+        /// <summary>
+        /// 是否显示为红色
+        /// </summary>
+        public bool IsRed { get; set; }
+
         /// <summary>
         /// 待结束会签编号
         /// </summary>
@@ -562,11 +576,13 @@ namespace Hotline.Share.Dtos.Order
                 var days = (FiledTime.Value - ExpiredTime.Value).TotalDays;
                 return $"超期{days:N1}天";
             }
+
             if (ExpiredTime.HasValue)
             {
                 var days = (dateTime.Value - ExpiredTime.Value).TotalDays;
                 return $"超期{days:N1}天";
             }
+
             return string.Empty;
         }
 
@@ -582,6 +598,7 @@ namespace Hotline.Share.Dtos.Order
             {
                 dateTime = FiledTime;
             }
+
             //ExpiredStatus
             if (ExpiredTime.HasValue)
             {
@@ -606,6 +623,7 @@ namespace Hotline.Share.Dtos.Order
                     return EExpiredStatus.Expired;
                 }
             }
+
             return null;
         }
 
@@ -633,6 +651,7 @@ namespace Hotline.Share.Dtos.Order
         /// 可直接访问的通话录音地址
         /// </summary>
         public string? RecordingBaseAddress { get; set; }
+
         public string? RecordingAbsolutePath { get; set; }
 
         public int ReTransactNum { get; set; }
@@ -650,6 +669,7 @@ namespace Hotline.Share.Dtos.Order
         /// 部门是否解决
         /// </summary>
         public bool IsResolved { get; set; }
+
         public string IsResolvedText => IsResolved ? "已解决" : "未解决";
 
         #region 副本工单
@@ -658,6 +678,7 @@ namespace Hotline.Share.Dtos.Order
         /// 修改人	
         /// </summary>
         public string AuditUserName { get; set; }
+
         public string AuditUserId { get; set; }
 
         /// <summary>
@@ -669,6 +690,7 @@ namespace Hotline.Share.Dtos.Order
         /// 副本工单id
         /// </summary>
         public string CopyId { get; set; }
+
         #endregion
 
         public string OverDays => GetOverDays();
@@ -688,6 +710,7 @@ namespace Hotline.Share.Dtos.Order
                     overDays = (DateTime.Now - ExpiredTime).Value.Days + "天";
                 }
             }
+
             return overDays;
         }
 
@@ -788,8 +811,8 @@ namespace Hotline.Share.Dtos.Order
             {
                 if (this.OrderVisits == null) return null;
                 var visitEntity = this.OrderVisits
-                            .OrderByDescending(m => m.CreationTime)
-                            .FirstOrDefault();
+                    .OrderByDescending(m => m.CreationTime)
+                    .FirstOrDefault();
                 if (visitEntity == null) return null;
                 return visitEntity.NowEvaluate;
             }
@@ -805,8 +828,8 @@ namespace Hotline.Share.Dtos.Order
             {
                 if (this.OrderVisits == null) return null;
                 var visitEntity = this.OrderVisits
-                           .OrderByDescending(m => m.CreationTime)
-                           .FirstOrDefault();
+                    .OrderByDescending(m => m.CreationTime)
+                    .FirstOrDefault();
                 if (visitEntity == null) return null;
                 var now = visitEntity.NowEvaluate;
                 if (now == null) return null;
@@ -823,8 +846,8 @@ namespace Hotline.Share.Dtos.Order
             {
                 if (this.OrderVisits == null) return null;
                 var visitEntity = this.OrderVisits
-                          .OrderByDescending(m => m.CreationTime)
-                          .FirstOrDefault();
+                    .OrderByDescending(m => m.CreationTime)
+                    .FirstOrDefault();
                 if (visitEntity == null) return null;
                 return visitEntity.OrderVisitDetails.Where(m => m.VisitTarget == EVisitTarget.Seat)
                     .FirstOrDefault()?.SeatEvaluate;
@@ -832,8 +855,9 @@ namespace Hotline.Share.Dtos.Order
         }
 
         public string? SeatEvaluateTxt => SeatEvaluate?.GetDescription();
+
         #endregion
-        
+
         /// <summary>
         /// 工单补充
         /// </summary>
@@ -848,6 +872,7 @@ namespace Hotline.Share.Dtos.Order
         /// 中心意见
         /// </summary>
         public string CenterOpinion { get; set; }
+
         /// <summary>
         /// 归档意见
         /// </summary>
@@ -857,7 +882,6 @@ namespace Hotline.Share.Dtos.Order
         /// 能否编辑,true:任何节点可以编辑;false:未发起流程可以编辑
         /// </summary>
         public bool IsEdit { get; set; }
-
     }
 
     public class AddOrderDto : Position
@@ -868,6 +892,7 @@ namespace Hotline.Share.Dtos.Order
         /// 来源渠道
         /// </summary>
         public string? SourceChannel { get; set; }
+
         public string? SourceChannelCode { get; set; }
 
         /// <summary>
@@ -957,6 +982,7 @@ namespace Hotline.Share.Dtos.Order
         /// 受理类型
         /// </summary>
         public string? AcceptType { get; set; }
+
         public string? AcceptTypeCode { get; set; }
 
         public string Title { get; set; }
@@ -965,6 +991,7 @@ namespace Hotline.Share.Dtos.Order
         /// 工单标签(自贡)
         /// </summary>
         public string? OrderTag { get; set; }
+
         public string? OrderTagCode { get; set; }
 
         #region 热点
@@ -973,6 +1000,7 @@ namespace Hotline.Share.Dtos.Order
         /// 热点
         /// </summary>
         public string? HotspotId { get; set; }
+
         //public string? HotspotCode { get; set; }
         public string? HotspotName { get; set; }
         public string? HotspotSpliceName { get; set; }
@@ -1056,6 +1084,7 @@ namespace Hotline.Share.Dtos.Order
         /// 企业Code
         /// </summary>
         public string? EnterpriseCode { get; set; }
+
         /// <summary>
         /// 专班名称
         /// </summary>
@@ -1066,8 +1095,10 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? ZhuanBanCode { get; set; }
 
-        #region  重复性事件
+        #region 重复性事件
+
         public List<RepeatableEventDetailOpDto> RepeatableEventDetails { get; set; } = new();
+
         #endregion
 
         /// <summary>
@@ -1124,6 +1155,7 @@ namespace Hotline.Share.Dtos.Order
         #endregion
 
         #region 市州工单互转
+
         /// <summary>
         /// 是否转发
         /// </summary>
@@ -1143,6 +1175,7 @@ namespace Hotline.Share.Dtos.Order
         /// 转发市州Value
         /// </summary>
         public string? TranspondCityValue { get; set; }
+
         #endregion
 
         /// <summary>
@@ -1208,7 +1241,6 @@ namespace Hotline.Share.Dtos.Order
 
     public record CanLinkCallRecordOrderDto : PagedKeywordRequest
     {
-
     }
 
     /// <summary>
@@ -1234,7 +1266,6 @@ namespace Hotline.Share.Dtos.Order
 
     public class UnsignedOrderDto
     {
-
         public OrderDto Order { get; set; }
 
         public WorkflowStepDto WorkflowStep { get; set; }
@@ -1258,7 +1289,6 @@ namespace Hotline.Share.Dtos.Order
         /// 备注时间
         /// </summary>
         public DateTime RemarkTime { get; set; }
-
     }
 
     public class PublishNearlyExpiredTimeSmsDto
@@ -1274,6 +1304,7 @@ namespace Hotline.Share.Dtos.Order
 
         public int ExpiredTimeOrderCount { get; set; }
     }
+
     public class PublishAutomaticDelayDto
     {
         public string OrderId { get; set; }
@@ -1327,6 +1358,7 @@ namespace Hotline.Share.Dtos.Order
             {
                 dateTime = FiledTime;
             }
+
             //ExpiredStatus
             if (ExpiredTime.HasValue)
             {
@@ -1351,6 +1383,7 @@ namespace Hotline.Share.Dtos.Order
                     return EExpiredStatus.Expired;
                 }
             }
+
             return null;
         }
 
@@ -1482,6 +1515,7 @@ namespace Hotline.Share.Dtos.Order
         /// 受理类型
         /// </summary>
         public string AcceptType { get; set; }
+
         public string AcceptTypeCode { get; set; }
 
         /// <summary>
@@ -1515,6 +1549,7 @@ namespace Hotline.Share.Dtos.Order
         /// 是否可编辑
         /// </summary>
         public bool CanEdit => !string.IsNullOrEmpty(SignerId) &&
-                               (Status is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept or EOrderStatus.HandOverToUnAccept);
+                               (Status is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept
+                                   or EOrderStatus.HandOverToUnAccept);
     }
-}
+}

+ 68 - 0
src/Hotline.Share/Enums/FlowEngine/ECountersignPolicy.cs

@@ -0,0 +1,68 @@
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.FlowEngine;
+
+/// <summary>
+/// 动态实例化策略
+/// </summary>
+public enum ECountersignPolicy
+{
+    /// <summary>
+    /// 直属上级部门(中心作为顶级部门)
+    /// </summary>
+    [Description("直属上级(中心作为顶级部门)")]
+    OrgUpCenterTop = 0,
+
+    /// <summary>
+    /// 直属上级(中心作为一级部门)
+    /// </summary>
+    [Description("直属上级(中心作为一级部门)")]
+    OrgUp = 1,
+
+    /// <summary>
+    /// 直属下级部门(中心作为顶级部门)
+    /// </summary>
+    [Description("直属下级(中心作为顶级部门)")]
+    OrgDownCenterTop = 2,
+
+    /// <summary>
+    /// 直属下级(中心作为一级部门)
+    /// </summary>
+    [Description("直属下级(中心作为一级部门)")]
+    OrgDown = 3,
+    // /// <summary>
+    // /// 直属上级部门(中心作为顶级部门)经办人
+    // /// </summary>
+    // [Description("直属上级(中心作为顶级部门) 经办人")]
+    // OrgUpHandleCenterTop = 4,
+    //
+    // /// <summary>
+    // /// 直属上级(中心作为一级部门)
+    // /// </summary>
+    // [Description("直属上级(中心作为一级部门)经办人")]
+    // OrgUpHandle = 5,
+    //
+    // /// <summary>
+    // /// 直属上级部门(中心作为顶级部门) 经办人与领导
+    // /// </summary>
+    // [Description("直属上级(中心作为顶级部门)经办人与领导")]
+    // OrgUpLeadCenterTop = 6,
+    //
+    // /// <summary>
+    // /// 直属上级(中心作为一级部门)经办人与领导
+    // /// </summary>
+    // [Description("直属上级(中心作为一级部门)经办人与领导")]
+    // OrgUpLead = 7,
+    //
+    // /// <summary>
+    // /// 直达中心
+    // /// </summary>
+    // [Description("直达中心")]
+    // ArriveCenter = 8,
+    //
+    // /// <summary>
+    // /// 直达一级部门
+    // /// </summary>
+    // [Description("直达一级部门")]
+    // ArriveOneOrg = 9,
+}

+ 0 - 68
src/Hotline.Share/Enums/FlowEngine/EDynamicPolicyCountersign.cs

@@ -1,68 +0,0 @@
-using System.ComponentModel;
-
-namespace Hotline.Share.Enums.FlowEngine;
-
-/// <summary>
-/// 动态实例化策略
-/// </summary>
-public enum EDynamicPolicyCountersign
-{
-    /// <summary>
-    /// 直属上级部门(中心作为顶级部门)
-    /// </summary>
-    [Description("直属上级(中心作为顶级部门)")]
-    OrgUpCenterTop = 0,
-
-    /// <summary>
-    /// 直属上级(中心作为一级部门)
-    /// </summary>
-    [Description("直属上级(中心作为一级部门)")]
-    OrgUp = 1,
-
-    /// <summary>
-    /// 直属下级部门(中心作为顶级部门)
-    /// </summary>
-    [Description("直属下级(中心作为顶级部门)")]
-    OrgDownCenterTop = 2,
-
-    /// <summary>
-    /// 直属下级(中心作为一级部门)
-    /// </summary>
-    [Description("直属下级(中心作为一级部门)")]
-    OrgDown = 3,
-    /// <summary>
-    /// 直属上级部门(中心作为顶级部门)经办人
-    /// </summary>
-    [Description("直属上级(中心作为顶级部门) 经办人")]
-    OrgUpHandleCenterTop = 4,
-
-    /// <summary>
-    /// 直属上级(中心作为一级部门)
-    /// </summary>
-    [Description("直属上级(中心作为一级部门)经办人")]
-    OrgUpHandle = 5,
-
-    /// <summary>
-    /// 直属上级部门(中心作为顶级部门) 经办人与领导
-    /// </summary>
-    [Description("直属上级(中心作为顶级部门)经办人与领导")]
-    OrgUpLeadCenterTop = 6,
-
-    /// <summary>
-    /// 直属上级(中心作为一级部门)经办人与领导
-    /// </summary>
-    [Description("直属上级(中心作为一级部门)经办人与领导")]
-    OrgUpLead = 7,
-
-    /// <summary>
-    /// 直达中心
-    /// </summary>
-    [Description("直达中心")]
-    ArriveCenter = 8,
-
-    /// <summary>
-    /// 直达一级部门
-    /// </summary>
-    [Description("直达一级部门")]
-    ArriveOneOrg = 9,
-}

+ 3 - 0
src/Hotline.Share/Enums/Settings/ETimeType.cs

@@ -7,6 +7,9 @@ using System.Threading.Tasks;
 
 namespace Hotline.Share.Enums.Settings
 {
+    /// <summary>
+    /// 时间类型
+    /// </summary>
     public enum ETimeType
     {
         [Description("小时")]

+ 10 - 5
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -2,6 +2,7 @@
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.File;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Settings;
@@ -29,7 +30,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// new
         /// </summary>
-        Task<WorkflowStep> StartAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime, CancellationToken cancellationToken = default);
+        Task<(Workflow, WorkflowStep)> StartAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime, CancellationToken cancellationToken = default);
 
         /// <summary>
         /// new
@@ -53,7 +54,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 受理,接办
         /// </summary>
-        Task AcceptAsync(Workflow workflow, string userId, string? userName, string orgId, string? orgName,
+        Task<DateTime?> AcceptAsync(Workflow workflow, string userId, string? userName, string orgId, string? orgName,
             string? orgAreaCode, string? orgAreaName, CancellationToken cancellationToken);
 
         /// <summary>
@@ -130,7 +131,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 结束流程(流程直接流转至结束节点)
         /// </summary>
-        Task<WorkflowTrace> EndAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine endStepDefine,
+        Task<WorkflowTrace> EndAsync(ISessionContext current, Workflow workflow, BasicWorkflowDto dto, StepDefine endStepDefine,
             WorkflowStep currentStep, DateTime? expiredTime, CancellationToken cancellationToken);
 
         StepDefine GetStepDefine(WorkflowDefinition workflowDefinition, string stepCode);
@@ -220,8 +221,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 获取会签类型
         /// </summary>
-        //ECounterSignType? GetCounterSignType(EBusinessType businessType);
-        ECounterSignType? GetCounterSignType(bool isStartCountersign);
+        ECounterSignType? GetCounterSignType(bool isStartCountersign, EBusinessType currentStepBusinessType);
 
         /// <summary>
         /// 查询退回节点信息
@@ -297,5 +297,10 @@ namespace Hotline.FlowEngine.Workflows
         /// 根据汇总对象id找到被汇总节点,生成指派到用户的办理对象
         /// </summary>
         FlowStepHandler GetSummaryTargetFlowStepHandler(Workflow workflow, string summaryTargetStepCode);
+        
+        /// <summary>
+        /// 追加归档信息(接收ds推送12315归档信息)
+        /// </summary>
+        Task AppendFileOpinionAsync(string workflowId, string opinion, List<FileDto> files, CancellationToken cancellationToken);
     }
 }

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

@@ -272,7 +272,7 @@ public abstract class StepBasicEntity : CreationEntity
     /// <summary>
     /// 会签策略
     /// </summary>
-    public EDynamicPolicyCountersign? CountersignPolicy { get; set; }
+    public ECountersignPolicy? CountersignPolicy { get; set; }
 
     #endregion
 

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

@@ -506,6 +506,8 @@ public partial class Workflow
         //实际办理部门为一级部门时记录
         if (ActualHandleOrgLevel.HasValue && ActualHandleOrgLevel == 1)
             UpdateLevelOneOrg(ActualHandleOrgCode, ActualHandleOrgName);
+        
+        
     }
 
     /// <summary>
@@ -517,7 +519,7 @@ public partial class Workflow
         string? handleOrgAreaName,
         int handlerOrgLevel)
     {
-        //ActualHandleStepAcceptTime = step.AcceptTime;
+        //ActualHandleStepAcceptTime = null;
         ActualHandleTime = step.HandleTime;
         ActualHandleOrgAreaCode = handleOrgAreaCode;
         ActualHandleOrgAreaName = handleOrgAreaName;
@@ -556,9 +558,6 @@ public partial class Workflow
         //     UpdateLevelOneOrg(CurrentHandleOrgId, CurrentHandleOrgName);
     }
 
-    public void UpdateCurrentStepAcceptTime(DateTime acceptTime) => CurrentStepAcceptTime = acceptTime;
-    public void UpdateActualStepAcceptTime(DateTime acceptTime) => ActualHandleStepAcceptTime = acceptTime;
-
     /// <summary>
     /// 办理时调用
     /// </summary>

+ 194 - 119
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -20,6 +20,7 @@ using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using System.Diagnostics;
+using Hotline.Share.Dtos.File;
 
 namespace Hotline.FlowEngine.Workflows
 {
@@ -29,7 +30,6 @@ namespace Hotline.FlowEngine.Workflows
         private readonly IRepository<WorkflowStep> _workflowStepRepository;
         private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
         private readonly IRepository<WorkflowCountersign> _workflowCountersignRepository;
-        private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
         private readonly Publisher _publisher;
         private readonly ILogger<WorkflowDomainService> _logger;
@@ -56,7 +56,6 @@ namespace Hotline.FlowEngine.Workflows
             _workflowStepRepository = workflowStepRepository;
             _workflowTraceRepository = workflowTraceRepository;
             _workflowCountersignRepository = workflowCountersignRepository;
-            _sessionContext = sessionContextProvider.SessionContext;
             _mapper = mapper;
             _publisher = publisher;
             _logger = logger;
@@ -109,11 +108,14 @@ namespace Hotline.FlowEngine.Workflows
                     PublishStrategy.ParallelWhenAll, cancellationToken);
 
                 //firstStep是否为end,t: 实际办理节点为startStep, 并且handlerId赋值 f: 实际办理节点为firstStep, handlerId未赋值
-                workflow.UpdateActualStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
+                workflow.UpdateActualStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode,
+                    _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
 
-                workflow.UpdateCurrentStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
+                workflow.UpdateCurrentStepWhenHandle(startStep, _sessionContextProvider.SessionContext.OrgAreaCode,
+                    _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
 
-                var endTrace = await EndAsync(workflow, dto, firstStepDefine, startStep, expiredTime, cancellationToken);
+                var endTrace = await EndAsync(_sessionContextProvider.SessionContext, workflow, dto, firstStepDefine, startStep, expiredTime,
+                    cancellationToken);
                 return;
             }
 
@@ -146,7 +148,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// new(开启流程并停留在开始节点,开始节点为待办节点,指派给当前操作人)
         /// </summary>
-        public async Task<WorkflowStep> StartAsync(StartWorkflowDto dto,
+        public async Task<(Workflow, WorkflowStep)> StartAsync(StartWorkflowDto dto,
             string externalId, DateTime? expiredTime, CancellationToken cancellationToken = default)
         {
             //     var validator = new StartWorkflowDtoValidator();
@@ -167,7 +169,7 @@ namespace Hotline.FlowEngine.Workflows
 
             //下一节点是否为动态节点
             var isNextDynamic = startStepDefine.InstanceMode is EInstanceMode.Dynamic &&
-                                !DynamicShouldTerminal(startStepDefine, _sessionContext.OrgLevel);
+                                !DynamicShouldTerminal(startStepDefine, _sessionContextProvider.SessionContext.OrgLevel);
             var firstStepDefine = isNextDynamic
                 ? startStepDefine
                 : definition.FindStepDefine(dto.NextStepCode);
@@ -192,24 +194,22 @@ namespace Hotline.FlowEngine.Workflows
                     throw new UserFriendlyException("下一节点不允许发起会签");
             }
 
-            var workflow = await CreateWorkflowAsync(wfModule, dto.Title,
-                _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId,
-                externalId, cancellationToken);
+            var workflow = CreateWorkflow(wfModule, dto.Title, externalId);
 
-            //todo 重构为流程开放策略参数,业务决定
             var defineHandler = startStepDefine.HandlerTypeItems.First();
-            var startStep = CreateStartStep(workflow, startStepDefine, dto,
-                new FlowStepHandler
-                {
-                    Key = _sessionContext.RequiredUserId,
-                    Value = _sessionContext.UserName,
-                    UserId = _sessionContext.UserId,
-                    Username = _sessionContext.UserName,
-                    OrgId = _sessionContext.RequiredOrgId,
-                    OrgName = _sessionContext.OrgName,
-                    RoleId = defineHandler.Key,
-                    RoleName = defineHandler.Value,
-                }, expiredTime);
+            //todo 重构为流程开放策略参数,业务决定
+            var handler = new FlowStepHandler
+            {
+                Key = _sessionContextProvider.SessionContext.RequiredUserId,
+                Value = _sessionContextProvider.SessionContext.UserName,
+                UserId = _sessionContextProvider.SessionContext.UserId,
+                Username = _sessionContextProvider.SessionContext.UserName,
+                OrgId = _sessionContextProvider.SessionContext.RequiredOrgId,
+                OrgName = _sessionContextProvider.SessionContext.OrgName,
+                RoleId = defineHandler.Key,
+                RoleName = defineHandler.Value,
+            };
+            var startStep = CreateStartStep(workflow, startStepDefine, dto, handler, expiredTime);
 
             if (dto.Files.Any())
                 startStep.FileJson =
@@ -226,30 +226,27 @@ namespace Hotline.FlowEngine.Workflows
             workflow.Traces.Add(startTrace);
             startStep.WorkflowTrace = startTrace;
 
-            //todo refactor:新增&更新整合
             //更新受理人信息
             workflow.UpdateAcceptor(
-                _sessionContext.RequiredUserId,
-                _sessionContext.UserName,
-                _sessionContext.StaffNo,
-                _sessionContext.RequiredOrgId,
-                _sessionContext.OrgName);
+                _sessionContextProvider.SessionContext.RequiredUserId,
+                _sessionContextProvider.SessionContext.UserName,
+                _sessionContextProvider.SessionContext.StaffNo,
+                _sessionContextProvider.SessionContext.RequiredOrgId,
+                _sessionContextProvider.SessionContext.OrgName);
 
-            //发起会签时记录顶层会签节点(必须在update currentStep之后)
-            var counterSignType = GetCounterSignType(dto.IsStartCountersign);
-            if (dto.IsStartCountersign && !workflow.IsInCountersign)
-                workflow.StartCountersign(startStep.Id, counterSignType);
+            workflow.UpdateActualStepWhenAssign(startStep, handler);
+            workflow.UpdateCurrentStepWhenAssign(startStep, handler);
 
-            await _workflowRepository.UpdateAsync(workflow, cancellationToken);
+            await _workflowRepository.AddAsync(workflow, cancellationToken);
 
             var flowAssignInfo =
                 await GetNextStepFlowAssignInfoAsync(workflow, startStep, dto, firstStepDefine, isNextDynamic, cancellationToken);
-            
+
             //publish
             await _publisher.PublishAsync(new StartWorkflowNotify(workflow, dto, flowAssignInfo.FlowAssignType, startTrace),
                 PublishStrategy.ParallelWhenAll, cancellationToken);
 
-            return startStep;
+            return (workflow, startStep);
         }
 
         /// <summary>
@@ -259,17 +256,16 @@ namespace Hotline.FlowEngine.Workflows
             DateTime? expiredTime = null, CancellationToken cancellationToken = default)
         {
             var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
-            withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
+                withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
             CheckWhetherRunnable(workflow.Status);
 
-            //var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
-            //    current.RequiredUserId, current.RequiredOrgId, current.Roles);
             var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == dto.StepId);
             if (currentStep == null)
                 throw new UserFriendlyException(
                     $"未找到对应节点, workflowId: {dto.WorkflowId}, stepId: {dto.StepId}", "未找到对应节点");
             if (currentStep.Status is EWorkflowStepStatus.Handled)
                 throw new UserFriendlyException("该状态不支持继续办理");
+            //todo 校验currentStep 能否由 current 办理
 
             var currentStepDefine = GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
 
@@ -291,7 +287,7 @@ namespace Hotline.FlowEngine.Workflows
                 nextStepDefine = GetStepDefine(workflow.WorkflowDefinition, dto.NextStepCode);
             }
 
-            //普通节点往汇总节点办理时可以不选,不选的场景主动去查之前的办理对象
+            //普通节点往汇总节点办理时可以不选,不选的场景主动去查之前的办理对象 //todo 按照指派策略生成办理对象
             if (nextStepDefine.StepType is EStepType.Summary && !dto.NextHandlers.Any())
             {
                 var handler = GetSummaryTargetFlowStepHandler(workflow, nextStepDefine.SummaryTargetCode);
@@ -301,19 +297,32 @@ namespace Hotline.FlowEngine.Workflows
             //需求:按角色选择办理人可以不选,表示该角色下所有人都可以办理,同时依据配置:是否本部门人办理显示待选办理人。角色下只要一人办理即可(即:角色下不发起会签)
             if (nextStepDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
                 throw new UserFriendlyException("未指定节点处理者");
+            //todo 加入到重构获取办理对象方法中
+            if (nextStepDefine.StepType != EStepType.End 
+                && nextStepDefine.HandlerType == EHandlerType.Role 
+                && !dto.NextHandlers.Any())
+            {
+                //todo 指派给配置的角色
+                var handler = nextStepDefine.HandlerTypeItems.First();
+                dto.NextHandlers.Add(new FlowStepHandler
+                {
+                    Key = handler.Key,
+                    Value = handler.Value,
+                    RoleId = handler.Key,
+                    RoleName = handler.Value
+                });
+            }
 
             if (dto.IsStartCountersign)
             {
                 if (!currentStepDefine.CanStartCountersign)
-                    throw new UserFriendlyException("当前节点不支持发起会签");
-                //if (currentStepDefine.HandlerType is EHandlerType.Role)
-                //    throw new UserFriendlyException("当前节点不支持发起会签");
+                    throw UserFriendlyException.SameMessage("当前节点不支持发起会签");
                 //即使当前节点支持发起会签,但下一节点为信息汇总节点、结束节点时也不可发起会签
                 if (nextStepDefine.StepType is EStepType.Summary or EStepType.End)
-                    throw new UserFriendlyException("下一节点不允许发起会签");
+                    throw UserFriendlyException.SameMessage("下一汇总节点不允许发起会签");
                 //下一节点是会签汇总节点也不允许发起会签
                 if (dto.BackToCountersignEnd)
-                    throw new UserFriendlyException("下一节点不允许发起会签");
+                    throw UserFriendlyException.SameMessage("下一会签汇总节点不允许发起会签");
             }
 
             var flowAssignInfo =
@@ -323,8 +332,8 @@ namespace Hotline.FlowEngine.Workflows
             #region 办理当前节点
 
             if (dto.Files != null && dto.Files.Any())
-                currentStep.FileJson = await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId,
-                    currentStep.Id, cancellationToken);
+                currentStep.FileJson = await _fileRepository.AddFileAsync(
+                    dto.Files, workflow.ExternalId, currentStep.Id, cancellationToken);
 
             //(currentStep.IsInCountersign() && !dto.BackToCountersignEnd) || dto.IsStartCountersign;
             var isStartCountersign = currentStep.CountersignPosition switch
@@ -336,7 +345,7 @@ namespace Hotline.FlowEngine.Workflows
                 _ => throw new ArgumentOutOfRangeException()
             };
 
-            var counterSignType = GetCounterSignType(dto.IsStartCountersign);
+            var counterSignType = GetCounterSignType(dto.IsStartCountersign, currentStep.BusinessType);
 
             var updateSteps = new List<WorkflowStep> { currentStep };
 
@@ -440,21 +449,21 @@ namespace Hotline.FlowEngine.Workflows
                     workflow.EndCountersign();
             }
 
-            if (workflow.ActualHandleStepId == currentStep.Id)
-            {
-                //更新实际办理节点信息
-                workflow.UpdateActualStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-            }
-
-            if (workflow.CurrentStepId == currentStep.Id)
-            {
-                workflow.UpdateCurrentStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-            }
+            // if (workflow.ActualHandleStepId == currentStep.Id)
+            // {
+            //     //更新实际办理节点信息
+            //     //workflow.UpdateActualStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+            // }
+            //
+            // if (workflow.CurrentStepId == currentStep.Id)
+            // {
+            //     workflow.UpdateCurrentStepWhenHandle(currentStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+            // }
 
             //检查是否流转到流程终点
             if (nextStepDefine.StepType is EStepType.End)
             {
-                var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, expiredTime, cancellationToken);
+                var endTrace = await EndAsync(current, workflow, dto, nextStepDefine, currentStep, expiredTime, cancellationToken);
                 return new List<WorkflowStep>();
             }
 
@@ -560,7 +569,7 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         /// <summary>
-        /// 查询工作流包含当前用户结束会签权限(是否可结束)
+        /// 查询用户对于当前流程权限
         /// </summary>
         public async Task<(Workflow Workflow, string? CountersignId, bool CanHandle, bool CanPrevious, WorkflowTrace? Trace)>
             GetWorkflowHandlePermissionAsync(
@@ -584,7 +593,7 @@ namespace Hotline.FlowEngine.Workflows
             }
 
             var unhandlePreviousTrace = workflow.Traces.FirstOrDefault(d =>
-                    d.Status is not EWorkflowStepStatus.Handled
+                d.Status is not EWorkflowStepStatus.Handled
             );
 
             var unCompletedCountersign = workflow.Countersigns
@@ -602,22 +611,22 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 受理(接办)
         /// </summary>
-        public async Task AcceptAsync(Workflow workflow,
+        public async Task<DateTime?> AcceptAsync(Workflow workflow,
             string userId, string? userName,
             string orgId, string? orgName,
             string? orgAreaCode, string? orgAreaName,
             CancellationToken cancellationToken)
         {
             if (!workflow.IsCanHandle(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId,
-                    _sessionContextProvider.SessionContext.Roles)) return;
+                    _sessionContextProvider.SessionContext.Roles)) return null;
             //工单完成以后查看的场景
-            if (workflow.Status != EWorkflowStatus.Runnable) return;
+            if (workflow.Status != EWorkflowStatus.Runnable) return null;
 
             var currentStep = GetUnHandleStep(workflow.Steps, _sessionContextProvider.SessionContext.RequiredOrgId,
                 _sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.Roles);
-            if (currentStep.Status is not EWorkflowStepStatus.WaitForAccept) return;
+            if (currentStep.Status is not EWorkflowStepStatus.WaitForAccept) return null;
 
-            if (currentStep.Handlers.All(d => d.Key != orgId && d.Key != userId)) return;
+            if (currentStep.Handlers.All(d => d.Key != orgId && d.Key != userId)) return null;
 
             if (currentStep.StepType is EStepType.End)
                 throw new UserFriendlyException("当前流程已流转到最终步骤");
@@ -630,15 +639,14 @@ namespace Hotline.FlowEngine.Workflows
             _mapper.Map(currentStep, trace);
             currentStep.WorkflowTrace = trace;
 
-            //await _workflowStepRepository.UpdateAsync(currentStep, cancellationToken);
             await _workflowStepRepository.UpdateNav(currentStep)
-                .Include(d => d.Workflow)
                 .Include(d => d.WorkflowTrace)
                 .ExecuteCommandAsync();
+            
+            workflow.ActualHandleStepAcceptTime = currentStep.AcceptTime;
+            await _workflowRepository.Updateable(workflow).ExecuteCommandAsync(cancellationToken);
 
-            //await AcceptTraceAsync(workflow, currentStep, cancellationToken);
-
-            //await _mediator.Publish(new AcceptWorkflowNotify(workflow), cancellationToken);
+            return workflow.ActualHandleStepAcceptTime;
         }
 
         /// <summary>
@@ -667,7 +675,7 @@ namespace Hotline.FlowEngine.Workflows
                 _ => throw new ArgumentOutOfRangeException()
             };
 
-            var counterSignType = GetCounterSignType(dto.IsStartCountersign);
+            var counterSignType = GetCounterSignType(dto.IsStartCountersign, currentStep.BusinessType);
 
             var updateSteps = new List<WorkflowStep> { currentStep };
 
@@ -755,7 +763,8 @@ namespace Hotline.FlowEngine.Workflows
                         //throw new UserFriendlyException(
                         //    $"会签数据异常, workflowId: {currentStep.WorkflowId}, countersignId: {currentStep.CountersignId}",
                         //    "会签数据异常");
-                        countersign.MemberHandled(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId);
+                        countersign.MemberHandled(_sessionContextProvider.SessionContext.RequiredUserId,
+                            _sessionContextProvider.SessionContext.RequiredOrgId);
                         //update cs
                         await _workflowCountersignRepository.UpdateNav(countersign)
                             .Include(d => d.Members)
@@ -798,18 +807,21 @@ namespace Hotline.FlowEngine.Workflows
             if (workflow.ActualHandleStepId == currentStep.Id)
             {
                 //更新实际办理节点信息
-                workflow.UpdateActualStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
+                workflow.UpdateActualStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode,
+                    _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
             }
 
             if (workflow.CurrentStepId == currentStep.Id)
             {
-                workflow.UpdateCurrentStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
+                workflow.UpdateCurrentStepWhenHandle(currentStep, _sessionContextProvider.SessionContext.OrgAreaCode,
+                    _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
             }
 
             //检查是否流转到流程终点
             if (nextStepDefine.StepType is EStepType.End)
             {
-                var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, expiredTime, cancellationToken);
+                var endTrace = await EndAsync(_sessionContextProvider.SessionContext,
+                    workflow, dto, nextStepDefine, currentStep, expiredTime, cancellationToken);
                 return;
             }
 
@@ -849,7 +861,8 @@ namespace Hotline.FlowEngine.Workflows
 
             //更新会签实际办理对象信息
             if (currentStep.IsActualHandled)
-                workflow.AddCsActualHandler(_sessionContextProvider.SessionContext.RequiredUserId, _sessionContextProvider.SessionContext.RequiredOrgId);
+                workflow.AddCsActualHandler(_sessionContextProvider.SessionContext.RequiredUserId,
+                    _sessionContextProvider.SessionContext.RequiredOrgId);
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);
 
@@ -1145,7 +1158,8 @@ namespace Hotline.FlowEngine.Workflows
         /// 批量修改工单办理对象
         /// </summary>
         public async Task ChangeHandlerBatchAsync(
-            IReadOnlyList<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep> steps)> handlers,
+            IReadOnlyList<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection<WorkflowStep>
+                steps)> handlers,
             CancellationToken cancellationToken)
         {
             foreach (var handler in handlers)
@@ -1399,6 +1413,30 @@ namespace Hotline.FlowEngine.Workflows
             return handler;
         }
 
+        /// <summary>
+        /// 追加归档信息(接收ds推送12315归档信息)
+        /// </summary>
+        public async Task AppendFileOpinionAsync(string workflowId, string opinion, List<FileDto> files, CancellationToken cancellationToken)
+        {
+            //归档意见,附件追加在归档节点前一节点上
+            var workflow = await GetWorkflowAsync(workflowId, withSteps: true, withTraces: true, cancellationToken: cancellationToken);
+            var endStep = workflow.Steps.FirstOrDefault(d => d.StepType == EStepType.End);
+            if (endStep is null)
+                throw new UserFriendlyException($"该流程还未归档, workflowId: {workflowId}");
+            var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == endStep.PrevStepId);
+            if (prevStep is null)
+                throw new UserFriendlyException($"未找到归档节点的前一节点, workflowId: {workflowId}, endStepId: {endStep.Id}");
+            prevStep.Opinion += opinion;
+
+            if (files.Any())
+            {
+                var filejsons = await _fileRepository.AddFileAsync(files, workflow.ExternalId, prevStep.Id, cancellationToken);
+                prevStep.FileJson.AddRange(filejsons);
+            }
+
+            await _workflowStepRepository.UpdateAsync(prevStep, cancellationToken);
+        }
+
         /// <summary>
         /// 查找当前会签内所有节点(含start,end)
         /// </summary>
@@ -1615,6 +1653,7 @@ namespace Hotline.FlowEngine.Workflows
                     cancellationToken);
                 isPaiDan = false;
             }
+
             return isPaiDan;
         }
 
@@ -1850,7 +1889,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 流程结束
         /// </summary>
-        public async Task<WorkflowTrace> EndAsync(Workflow workflow, BasicWorkflowDto dto,
+        public async Task<WorkflowTrace> EndAsync(ISessionContext current, Workflow workflow, BasicWorkflowDto dto,
             StepDefine endStepDefine, WorkflowStep currentStep,
             DateTime? expiredTime, CancellationToken cancellationToken)
         {
@@ -1871,11 +1910,11 @@ namespace Hotline.FlowEngine.Workflows
             workflow.Complete(endStep, dto.ReviewResult);
 
             //需求调整:归档时当前节点显示为归档节点
-            workflow.UpdateCurrentStepWhenHandle(endStep, _sessionContextProvider.SessionContext.OrgAreaCode, _sessionContextProvider.SessionContext.OrgAreaName, _sessionContextProvider.SessionContext.OrgLevel);
-            workflow.UpdateCurrentStepAcceptTime(endStep.AcceptTime.Value);
+            workflow.UpdateCurrentStepWhenHandle(endStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+            workflow.CurrentStepAcceptTime = endStep.AcceptTime.Value;
 
-            //workflow.UpdateActualStepWhenHandle(endStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
-            //workflow.UpdateActualStepAcceptTime(endStep.AcceptTime.Value);
+            workflow.UpdateActualStepWhenHandle(endStep, current.OrgAreaCode, current.OrgAreaName, current.OrgLevel);
+            workflow.ActualHandleStepAcceptTime = endStep.AcceptTime.Value;
 
             if (string.IsNullOrEmpty(workflow.OrgLevelOneCode))
                 workflow.UpdateLevelOneOrg(workflow.ActualHandleOrgCode, workflow.ActualHandleOrgName);
@@ -1904,10 +1943,20 @@ namespace Hotline.FlowEngine.Workflows
         //        _ => throw new ArgumentOutOfRangeException(nameof(businessType), businessType, null)
         //    };
 
-        public ECounterSignType? GetCounterSignType(bool isStartCountersign)
+        public ECounterSignType? GetCounterSignType(bool isStartCountersign, EBusinessType currentStepBusinessType)
         {
             if (!isStartCountersign) return null;
-            return _sessionContextProvider.SessionContext.OrgIsCenter ? ECounterSignType.Center : ECounterSignType.Department;
+            return currentStepBusinessType switch
+            {
+                EBusinessType.Seat => ECounterSignType.Center,
+                EBusinessType.Send => ECounterSignType.Center,
+                EBusinessType.Department => ECounterSignType.Department,
+                EBusinessType.DepartmentLeader => ECounterSignType.Department,
+                EBusinessType.File => null,
+                _ => throw new ArgumentOutOfRangeException(nameof(currentStepBusinessType), currentStepBusinessType, null)
+            };
+
+            // return _sessionContextProvider.SessionContext.OrgIsCenter ? ECounterSignType.Center : ECounterSignType.Department;
         }
 
         /// <summary>
@@ -1942,29 +1991,51 @@ namespace Hotline.FlowEngine.Workflows
 
         #region private method
 
+        private Workflow CreateWorkflow(WorkflowModule wfModule, string title, string? externalId = null)
+        {
+            var definition = wfModule.Definition;
+            if (definition is null)
+                throw new UserFriendlyException("无效流程模板");
+            var workflow = new Workflow
+            {
+                Title = title,
+                ModuleId = wfModule.Id,
+                ModuleName = wfModule.Name,
+                ModuleCode = wfModule.Code,
+                DefinitionId = definition.Id,
+                Status = EWorkflowStatus.Runnable,
+                Steps = new(),
+                Traces = new(),
+                WorkflowDefinition = definition,
+                ExternalId = externalId ?? string.Empty,
+                FlowType = definition.FlowType,
+            };
+
+            workflow.InitId();
+
+            return workflow;
+        }
+
         private static void UpdateCurrentStep(Workflow workflow, BasicWorkflowDto dto,
             StepDefine nextStepDefine, List<WorkflowStep> nextSteps)
         {
             if (dto.IsStartCountersign) return;
             if (workflow.IsInCountersign) return;
 
-            if (workflow.FlowType is EFlowType.Handle)
+            if (nextStepDefine.BusinessType is EBusinessType.Seat or EBusinessType.Send)
             {
-                if (nextStepDefine.BusinessType is EBusinessType.Seat or EBusinessType.Send)
-                {
-                    //坐席->派单不选办理对象时
-                    workflow.UpdateCurrentStepWhenAssign(nextSteps.First(),
-                        new FlowStepHandler
-                        {
-                            OrgId = OrgSeedData.CenterId,
-                            OrgName = OrgSeedData.CenterName
-                        });
-                }
-                else
-                {
-                    var nextHandler = dto.NextHandlers.First();
-                    workflow.UpdateCurrentStepWhenAssign(nextSteps.First(), nextHandler);
-                }
+                //坐席->派单不选办理对象时
+                workflow.UpdateCurrentStepWhenAssign(nextSteps.First(),
+                    new FlowStepHandler
+                    {
+                        OrgId = OrgSeedData.CenterId,
+                        OrgName = OrgSeedData.CenterName
+                    });
+            }
+            else
+            {
+                var nextHandler = dto.NextHandlers.First();
+                workflow.UpdateCurrentStepWhenAssign(nextSteps.First(), nextHandler);
             }
         }
 
@@ -1974,27 +2045,31 @@ namespace Hotline.FlowEngine.Workflows
             if (dto.IsStartCountersign) return;
             if (workflow.IsInCountersign) return;
             if (nextStepDefine.StepType is EStepType.Summary or EStepType.End) return;
+            if (nextSteps.Count > 1) return; //多个下级节点不更新workflow的实际办理信息
+            var nextStep = nextSteps.First();
 
-            if (workflow.FlowType is EFlowType.Handle)
+            //todo 重构为办理对象由参数传入,指派给中心?派单员?待确认
+            if (nextStepDefine.BusinessType is EBusinessType.Seat or EBusinessType.Send)
             {
-                if (nextStepDefine.BusinessType is EBusinessType.Seat or EBusinessType.Send)
-                {
-                    //坐席->派单不选办理对象时
-                    workflow.UpdateActualStepWhenAssign(nextSteps.First(),
-                        new FlowStepHandler
-                        {
-                            Key = OrgSeedData.CenterId,
-                            Value = OrgSeedData.CenterName, 
-                            OrgId = OrgSeedData.CenterId,
-                            OrgName = OrgSeedData.CenterName
-                        });
-                }
-                else
-                {
-                    var nextHandler = dto.NextHandlers.First();
-                    workflow.UpdateActualStepWhenAssign(nextSteps.First(), nextHandler);
-                }
+                //坐席->派单不选办理对象时
+                workflow.UpdateActualStepWhenAssign(nextStep,
+                    new FlowStepHandler
+                    {
+                        Key = OrgSeedData.CenterId,
+                        Value = OrgSeedData.CenterName,
+                        OrgId = OrgSeedData.CenterId,
+                        OrgName = OrgSeedData.CenterName
+                    });
+            }
+            else
+            {
+                var nextHandler = dto.NextHandlers.First();
+                workflow.UpdateActualStepWhenAssign(nextStep, nextHandler);
             }
+
+
+            //与实际办理节点的接办状态保持一致
+            workflow.ActualHandleStepAcceptTime = nextStep.AcceptTime;
         }
 
         private async Task<WorkflowStep> CreateStartStepAsync(Workflow workflow, StepDefine startStepDefine,

+ 8 - 8
src/Hotline/Orders/OrderDomainService.cs

@@ -345,8 +345,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                 //投诉举报
                 case "30":
                 case "35":
-                    valid.Validation = dto.Title.Contains("意见") || dto.Title.Contains("建议")  || dto.Title.Contains("咨询");
-                    valid.Validation = dto.Content.Contains("意见") || dto.Content.Contains("建议")  || dto.Content.Contains("咨询");
+                    valid.Validation = dto.Title.Contains("意见") || dto.Title.Contains("建议")  || dto.Title.Contains("咨询") 
+                        || dto.Content.Contains("意见") || dto.Content.Contains("建议") || dto.Content.Contains("咨询");
                     if (dto.Content.Length < 25)
                     {
                         valid.Validation = true;
@@ -355,8 +355,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                     break;
                 // 意见
                 case "1":
-                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报")|| dto.Title.Contains("咨询");
-                    valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
+                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报")|| dto.Title.Contains("咨询") 
+                        || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
                     if (dto.Content.Length < 5)
                     {
                         valid.Validation = true;
@@ -366,8 +366,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                 //建议求助
                 case "15":
                 case "20":
-                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报")  || dto.Title.Contains("咨询");
-                    valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
+                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报")  || dto.Title.Contains("咨询") 
+                        || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("咨询");
                     if (dto.Content.Length < 25)
                     {
                         valid.Validation = true;
@@ -376,8 +376,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
                     break;
                 // 咨询
                 case "10":
-                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("意见") || dto.Title.Contains("建议");
-                    valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("意见") || dto.Content.Contains("建议");
+                    valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("意见") 
+                        || dto.Title.Contains("建议") || dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("意见") || dto.Content.Contains("建议");
                     if (dto.Content.Length < 5)
                     {
                         valid.Validation = true;