xf hai 3 semanas
pai
achega
f69fbc4773

+ 27 - 0
src/Hotline.Api/Controllers/OrderApi/OrderDelayController.cs

@@ -0,0 +1,27 @@
+using Hotline.Application.OrderApp.OrderDelayApp;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Order.OrderDelay;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Hotline.Api.Controllers.OrderApi;
+
+public class OrderDelayController
+{
+    private readonly IOrderDelayApplication _orderDelayApplication;
+    public OrderDelayController(IOrderDelayApplication orderDelayApplication)
+    {
+        _orderDelayApplication = orderDelayApplication;
+    }
+    [HttpGet("delay/list")]
+    public async Task<IActionResult> GetDelayList([FromQuery] DelayListDto dto)
+    {
+        var result = await _orderDelayApplication.QueryWaited(dto);
+        return Ok(result);
+    }
+    [HttpPost("delay/review")]
+    public async Task<IActionResult> Review([FromBody] OrderDelayReviewRequest request, CancellationToken cancellation)
+    {
+        await _orderDelayApplication.ReviewAsync(request, cancellation);
+        return Ok();
+    }
+}

+ 0 - 17
src/Hotline.Api/Controllers/OrderController.cs

@@ -2392,23 +2392,6 @@ public class OrderController : BaseController
                 //    }
                 //}
 
-                /*
-                 * 查询delay
-                 * 查询workflow
-                 * 查询当前节点(待受理or待办理)
-                 * 查询nextStep(_workflowApplication.GetNextStepsAsync)
-                 * 非省工单删除省审批节点
-                 *!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审"删除中心终审
-                 * 从nextStep中查找与dto传入的nextStepName相同的节点,workflow.NextStepCode = step.Key;workflow.NextStepName = step.Value;
-                 * 通过:nextAsync,不同意:rejectAsync
-                 * endhandler:
-                 *  1.更新orderDelay.DelayState
-                 *  2.审批通过:
-                 *      a.更新工单办理期满时间(_orderApplication.DelayOrderExpiredTimeAsync)
-                 *      b.更新未办理节点的期满时间
-                 *      c.cap publish EventNames.HotlineOrderExpiredTimeUpdate
-                 */
-
                 var delay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == item)
                     .FirstAsync(HttpContext.RequestAborted);
                 workflow.WorkflowId = delay.WorkflowId;

+ 11 - 2
src/Hotline.Application/OrderApp/OrderDelayApp/IOrderDelayApplication.cs

@@ -1,14 +1,23 @@
-using Hotline.Share.Dtos.Order.OrderDelay;
+using Hotline.Orders;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Order.OrderDelay;
+using SqlSugar;
 
 namespace Hotline.Application.OrderApp.OrderDelayApp;
 
 public interface IOrderDelayApplication
 {
+    /// <summary>
+    /// 延期列表
+    /// </summary>
+    /// <returns></returns>
+    ISugarQueryable<OrderDelay> QueryWaited(DelayListDto dto);
+
     /// <summary>
     /// 延期审核
     /// </summary>
     /// <param name="request"></param>
     /// <param name="cancellation"></param>
     /// <returns></returns>
-    Task AuditAsync(OrderDelayAuditRequest request, CancellationToken cancellation);
+    Task ReviewAsync(OrderDelayReviewRequest request, CancellationToken cancellation);
 }

+ 185 - 3
src/Hotline.Application/OrderApp/OrderDelayApp/OrderDelayApplication.cs

@@ -1,18 +1,200 @@
-using Hotline.Share.Dtos.Order.OrderDelay;
+using Hotline.FlowEngine.Workflows;
+using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
+using Hotline.Share.Dtos.Order.OrderDelay;
+using Hotline.Share.Enums.FlowEngine;
+using MapsterMapper;
+using Microsoft.AspNetCore.Http;
+using System.Threading;
+using Hotline.BatchTask;
+using Hotline.Orders;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.BatchTask;
+using Hotline.Share.Enums.Order;
+using SqlSugar;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
+using XF.Domain.Entities;
 
 namespace Hotline.Application.OrderApp.OrderDelayApp;
 
 public class OrderDelayApplication : IOrderDelayApplication, IScopeDependency
 {
+    private readonly IOrderDomainService _orderDomainService;
+    private readonly IOrderDelayRepository _orderDelayRepository;
+    private readonly IWorkflowDomainService _workflowDomainService;
+    private readonly ISessionContext _sessionContext;
+    private readonly IMapper _mapper;
+
+    public OrderDelayApplication(
+        IOrderDomainService orderDomainService,
+        IOrderDelayRepository orderDelayRepository,
+        IWorkflowDomainService workflowDomainService,
+        ISessionContext sessionContext,
+        IMapper mapper)
+    {
+        _orderDomainService = orderDomainService;
+        _orderDelayRepository = orderDelayRepository;
+        _workflowDomainService = workflowDomainService;
+        _sessionContext = sessionContext;
+        _mapper = mapper;
+    }
+
+    /// <summary>
+    /// 延期列表
+    /// </summary>
+    /// <returns></returns>
+    public ISugarQueryable<OrderDelay> QueryWaited(DelayListDto dto)
+    {
+        var isAdmin = _orderDomainService.IsCheckAdmin();
+        var hasHandled = dto.IsApply.HasValue && dto.IsApply.Value;
+        var query = _orderDelayRepository.Queryable()
+                .Includes(d => d.WorkflowSteps.Where(step =>
+                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
+                          step.HandlerId == _sessionContext.RequiredUserId) ||
+                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
+                          step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)) ||
+                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)
+                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId)))
+                    .OrderByDescending(step => step.CreationTime)
+                    .Take(1)
+                    .ToList()
+                );
+
+        if (!isAdmin)
+        {
+            if (hasHandled)
+            {
+                query.Where(d => d.WorkflowSteps
+                    .Any(step =>
+                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
+                          step.HandlerId == _sessionContext.RequiredUserId) ||
+                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
+                          step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)) ||
+                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)
+                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
+                        && step.Status == EWorkflowStepStatus.Handled));
+            }
+            else
+            {
+                query.Where(d => d.WorkflowSteps
+                    .Any(step =>
+                        ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
+                          step.HandlerId == _sessionContext.RequiredUserId) ||
+                         (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) &&
+                          step.HandlerOrgId == _sessionContext.RequiredOrgId) ||
+                         (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)) ||
+                         (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) &&
+                          _sessionContext.Roles.Contains(step.RoleId)
+                          && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId))
+                        && step.Status < EWorkflowStepStatus.Handled));
+            }
+        }
+
+
+        query.Includes(d => d.Order)
+          .Includes(d => d.Workflow)
+          .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
+          .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining)
+          .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Order.No.Contains(dto.No))                                   //工单编号
+          .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == true, d => d.Order.IsProvince == true)      //是否省工单
+          .WhereIF(dto.IsProvince.HasValue && dto.IsProvince == false, d => d.Order.IsProvince == false)
+          .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Order.Title.Contains(dto.Title))                          //工单标题
+          .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.Order.SourceChannelCode == dto.Channel)                 //来源渠道
+          .WhereIF(dto.CreationTimeStart.HasValue, d => d.Order.CreationTime >= dto.CreationTimeStart)                //受理时间Start
+          .WhereIF(dto.CreationTimeEnd.HasValue, d => d.Order.CreationTime <= dto.CreationTimeEnd)                    //受理时间End
+          .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.Order.AcceptorName == dto.AcceptorName!)           //受理人
+          .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot)) //热点
+          .WhereIF(!string.IsNullOrEmpty(dto.AcceptTypeCode), d => d.Order.AcceptTypeCode == dto.AcceptTypeCode)      //受理类型
+          .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.Order.OrgLevelOneName.Contains(dto.OrgLevelOneName)) //一级部门
+          .WhereIF(!string.IsNullOrEmpty(dto.CurrentHandleOrgName), d => d.Order.CurrentHandleOrgName.Contains(dto.CurrentHandleOrgName)) //接办部门
+          .WhereIF(dto.CurrentHandleTimeStart.HasValue, d => d.Order.CurrentHandleTime >= dto.CurrentHandleTimeStart) //接办时间Start
+          .WhereIF(dto.CurrentHandleTimeEnd.HasValue, d => d.Order.CurrentHandleTime <= dto.CurrentHandleTimeEnd)     //接办时间End
+          .WhereIF(dto.ApplyTimeStart.HasValue, d => d.CreationTime >= dto.ApplyTimeStart)                            //延期申请时间Start
+          .WhereIF(dto.ApplyTimeEnd.HasValue, d => d.CreationTime <= dto.ApplyTimeEnd)                                //延期申请时间End
+          .WhereIF(!string.IsNullOrEmpty(dto.ApplyName), d => d.CreatorName.Contains(dto.ApplyName))                  //延期申请人
+          .WhereIF(!string.IsNullOrEmpty(dto.ApplyOrgName), d => d.CreatorOrgName.Contains(dto.ApplyOrgName))         //延期申请部门
+          .WhereIF(dto.DelayNum.HasValue, d => d.DelayNum == dto.DelayNum)                                            //延期申请时限
+          .WhereIF(dto.DelayUnit.HasValue, d => d.DelayUnit == dto.DelayUnit)                                         //延期申请单位
+          .WhereIF(!string.IsNullOrEmpty(dto.DelayReason), d => d.DelayReason.Contains(dto.DelayReason))              //申请理由
+          .WhereIF(dto.BeforeDelayStart.HasValue, d => d.BeforeDelay >= dto.BeforeDelayStart)                         //申请前期满时间Start
+          .WhereIF(dto.BeforeDelayEnd.HasValue, d => d.BeforeDelay <= dto.BeforeDelayEnd)                             //申请前期满时间End
+          .OrderByDescending(d => d.ApplyDelayTime)
+      ;
+
+        return query;
+    }
+
     /// <summary>
     /// 延期审核
     /// </summary>
     /// <param name="request"></param>
     /// <param name="cancellation"></param>
     /// <returns></returns>
-    public async Task AuditAsync(OrderDelayAuditRequest request, CancellationToken cancellation)
+    public async Task ReviewAsync(OrderDelayReviewRequest request, CancellationToken cancellation)
     {
-        throw new NotImplementedException();
+        /*
+         * 查询delay
+         * 查询workflow
+         * 查询当前节点(待受理or待办理)
+         * 查询nextStep(_workflowApplication.GetNextStepsAsync)
+         * 非省工单删除省审批节点
+         *!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审"删除中心终审
+         * 从nextStep中查找与dto传入的nextStepName相同的节点,workflow.NextStepCode = step.Key;workflow.NextStepName = step.Value;
+         * 通过:nextAsync,不同意:rejectAsync
+         * endhandler:
+         *  1.更新orderDelay.DelayState
+         *  2.审批通过:
+         *      a.更新工单办理期满时间(_orderApplication.DelayOrderExpiredTimeAsync)
+         *      b.更新工单未办理节点的期满时间(_workflowDomainService.UpdateUnhandleExpiredTimeAsync)
+         *      c.cap publish EventNames.HotlineOrderExpiredTimeUpdate
+         */
+
+        request.NextWorkflow.ReviewResult = request.IsPass ? EReviewResult.Approval : EReviewResult.Failed;
+        if (request.IsPass)
+        {
+            await _workflowDomainService.NextAsync(request.NextWorkflow, cancellationToken: cancellation);
+        }
+        else
+        {
+            var reject = _mapper.Map<RejectDto>(request.NextWorkflow);
+            await _workflowDomainService.RejectAsync(reject, cancellation);
+        }
+    }
+
+    /// <summary>
+    /// 批量审核
+    /// </summary>
+    /// <returns></returns>
+    public async Task BatchReviewAsync(BatchOrderDelayReviewRequest request, CancellationToken cancellation)
+    {
+        var delays = await _orderDelayRepository.Queryable()
+            .Where(d => request.DelayIds.Contains(d.Id))
+            .ToListAsync(cancellation);
+
+        var apptaskItems = new List<ApptaskItem>();
+        foreach (var delay in delays)
+        {
+            request.NextWorkflow.StepId = delay
+        }
+
+        var taskparams = System.Text.Json.JsonSerializer.Serialize(request.NextWorkflow);
+        var apptask = new Apptask
+        {
+            TaskType = ETaskType.Delay,
+            ApptaskItems = request.DelayIds.Select(d => new ApptaskItem
+            {
+                BusinessId = d,
+                TaskType = ETaskType.Delay,
+                TaskParams =
+            })
+        }
     }
 }

+ 13 - 1
src/Hotline.Share/Dtos/Order/OrderDelay/OrderDelayAuditRequest.cs → src/Hotline.Share/Dtos/Order/OrderDelay/OrderDelayReviewRequest.cs

@@ -2,7 +2,7 @@
 
 namespace Hotline.Share.Dtos.Order.OrderDelay;
 
-public class OrderDelayAuditRequest
+public class OrderDelayReviewRequest
 {
     public string DelayId { get; set; }
 
@@ -11,5 +11,17 @@ public class OrderDelayAuditRequest
     /// </summary>
     public bool IsPass { get; set; }
     
+    public NextWorkflowDto NextWorkflow { get; set; }
+}
+
+public class BatchOrderDelayReviewRequest
+{
+    public List<string> DelayIds { get; set; }
+
+    /// <summary>
+    /// 是否通过
+    /// </summary>
+    public bool IsPass { get; set; }
+
     public NextWorkflowDto NextWorkflow { get; set; }
 }

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

@@ -171,23 +171,12 @@ namespace Hotline.FlowEngine.Workflows
             bool isOrderFiled, DateTime? expiredTime, EHandleMode handleMode, EFlowAssignType? flowAssignType = EFlowAssignType.User,
             CancellationToken cancellationToken = default);
 
-        ///// <summary>
-        ///// 跳转(直接将流程跳转至任意节点)
-        ///// </summary>
-        //Task JumpAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine, FlowAssignInfo flowAssignInfo,
-        //    CancellationToken cancellationToken);
-
-        ///// <summary>
-        ///// 重办
-        ///// </summary>
-        //Task RedoAsync(Workflow workflow, RecallDto dto, StepDefine targetStepDefine, FlowAssignInfo flowAssignInfo,
-        //    CancellationToken cancellationToken);
-
         ///// <summary>
         ///// 否决(审批流程不通过)
         ///// </summary>
         ///// <returns></returns>
         //Task RejectAsync(Workflow workflow, BasicWorkflowDto dto, CancellationToken cancellationToken);
+        Task RejectAsync(RejectDto dto, CancellationToken cancellationToken);
 
         /// <summary>
         /// 补充

+ 40 - 13
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -1317,20 +1317,30 @@ namespace Hotline.FlowEngine.Workflows
         public async Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime? expiredTime,
             CancellationToken cancellation)
         {
-            var steps = await _workflowStepRepository.Queryable()
-                .Includes(d => d.WorkflowTrace)
-                .Where(d => d.WorkflowId == workflowId &&
-                            d.Status < EWorkflowStepStatus.Handled)
-                .ToListAsync(cancellation);
-            foreach (var step in steps)
-            {
-                step.StepExpiredTime = expiredTime;
-                step.WorkflowTrace.StepExpiredTime = expiredTime;
-            }
+            //var steps = await _workflowStepRepository.Queryable()
+            //    .Includes(d => d.WorkflowTrace)
+            //    .Where(d => d.WorkflowId == workflowId &&
+            //                d.Status < EWorkflowStepStatus.Handled)
+            //    .ToListAsync(cancellation);
+            //foreach (var step in steps)
+            //{
+            //    step.StepExpiredTime = expiredTime;
+            //    step.WorkflowTrace.StepExpiredTime = expiredTime;
+            //}
 
-            await _workflowStepRepository.UpdateNav(steps)
-                .Include(d => d.WorkflowTrace)
-                .ExecuteCommandAsync();
+            //await _workflowStepRepository.UpdateNav(steps)
+            //    .Include(d => d.WorkflowTrace)
+            //    .ExecuteCommandAsync();
+
+            await _workflowStepRepository.Updateable()
+                .SetColumns(d => d.StepExpiredTime == expiredTime)
+                .Where(d => d.WorkflowId == workflowId && d.Status < EWorkflowStepStatus.Handled)
+                .ExecuteCommandAsync(cancellation);
+
+            await _workflowTraceRepository.Updateable()
+                .SetColumns(d => d.StepExpiredTime == expiredTime)
+                .Where(d => d.WorkflowId == workflowId && d.Status < EWorkflowStepStatus.Handled)
+                .ExecuteCommandAsync(cancellation);
         }
 
         /// <summary>
@@ -2056,6 +2066,23 @@ namespace Hotline.FlowEngine.Workflows
             return (new(isPaiDan, workflow));
         }
 
+        public async Task RejectAsync(RejectDto dto, CancellationToken cancellationToken)
+        {
+            var workflow = await GetWorkflowAsync(dto.WorkflowId, withDefine: true,
+                cancellationToken: cancellationToken);
+            
+            var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
+            var nextDto = _mapper.Map<NextWorkflowDto>(dto);
+            nextDto.ReviewResult = EReviewResult.Failed;
+            nextDto.NextStepCode = endStepDefine.Code;
+            nextDto.NextStepName = endStepDefine.Name;
+            nextDto.FlowDirection = _sessionContext.OrgIsCenter
+                ? EFlowDirection.CenterToFile
+                : EFlowDirection.OrgToFile;
+
+            await NextAsync(nextDto, cancellationToken: cancellationToken);
+        }
+
         /// <summary>
         /// 补充
         /// </summary>

+ 5 - 1
src/Hotline/Orders/OrderDelay.cs

@@ -148,5 +148,9 @@ namespace Hotline.Orders
 		[SugarColumn(DefaultValue = "0")]
 		public int? AutomaticDelayNum { get; set; }
 
-	}
+
+        [Navigate(NavigateType.OneToMany, nameof(WorkflowStep.ExternalId))]
+        public List<WorkflowStep> WorkflowSteps { get; set; }
+
+    }
 }