田爽 3 weeks ago
parent
commit
43ed95e007

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

@@ -601,7 +601,7 @@ namespace Hotline.Api.Controllers
                             }
                             catch (Exception e)
                             {
-                                _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                                _logger.LogError($"写入智能质检异常2!, \r\n{e.Message}");
                             }
 
                         }

+ 39 - 28
src/Hotline.Api/Controllers/OrderController.cs

@@ -72,8 +72,10 @@ using MiniExcelLibs;
 using SqlSugar;
 using System.Text;
 using System.Text.Json;
+using System.Threading;
 using XF.Domain.Authentications;
 using XF.Domain.Cache;
+using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
@@ -2455,7 +2457,7 @@ public class OrderController : BaseController
 
     [HttpPost("delay/batch_audit")]
     [LogFilter("批量审批延期")]
-    [LogFilterAlpha("延期审核")]
+    //[LogFilterAlpha("延期审核")]
     public async Task<string> BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto)
     {
         var result = new StringBuilder();
@@ -2471,15 +2473,18 @@ public class OrderController : BaseController
             .Where(x => dto.DelayId.Contains(x.Id))
             .ToListAsync(HttpContext.RequestAborted);
 
+        if (!delays.Any())
+            return string.Empty;
+
+        var currentStep = delays.First().Workflow.Steps.FirstOrDefault(d =>
+            d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
+
         var updateDelays = new List<OrderDelay>();
         var updateOrders = new List<Order>();
         foreach (var delay in delays)
         {
             try
             {
-                var currentStep = delay.Workflow.Steps.FirstOrDefault(d =>
-                    d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle);
-
                 NextStepsWithOpinionDto<NextStepOption> next = null;
 
                 try
@@ -2522,6 +2527,17 @@ public class OrderController : BaseController
 
                 if (dto.IsPass)
                 {
+                    var step = next.Steps.FirstOrDefault(x => x.Value == workflowDto.NextStepName);
+                    if (step is null)
+                    {
+                        result.Append("无权审核:" + delay.No);
+                        fail++;
+                        continue;
+                    }
+
+                    workflowDto.NextStepCode = step.Key;
+                    workflowDto.NextStepName = step.Value;
+
                     //处理工单延期
                     var order = delay.Order;
                     var expiredTimeBase = DateTime.Now;
@@ -2550,21 +2566,12 @@ public class OrderController : BaseController
 
                     updateOrders.Add(order);
 
-                    var step = next.Steps.FirstOrDefault(x => x.Value == workflowDto.NextStepName);
-                    if (step is null)
-                    {
-                        result.Append("无权审核:" + delay.No);
-                        fail++;
-                        continue;
-                    }
-
-                    workflowDto.NextStepCode = step.Key;
-                    workflowDto.NextStepName = step.Value;
-
                     await _workflowDomainService.NextAsync(delay.Workflow, workflowDto,
                         expiredTime: order.ExpiredTime,
                         cancellationToken: HttpContext.RequestAborted);
 
+                    await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, order.ExpiredTime, HttpContext.RequestAborted);
+
                     var orderDto = _mapper.Map<OrderDto>(order);
                     await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto,
                         cancellationToken: HttpContext.RequestAborted);
@@ -2579,19 +2586,6 @@ public class OrderController : BaseController
                 delay.DelayState = dto.IsPass ? EDelayState.Pass : EDelayState.NoPass;
                 updateDelays.Add(delay);
 
-                await _orderDelayRepository.Updateable(updateDelays)
-                    .UpdateColumns(d => d.DelayState)
-                    .ExecuteCommandAsync(HttpContext.RequestAborted);
-
-                await _orderRepository.Updateable(updateOrders)
-                    .UpdateColumns(d => new
-                    {
-                        d.ExpiredTime,
-                        d.NearlyExpiredTime,
-                        d.NearlyExpiredTimeOne,
-                        d.ExpiredTimeProvince
-                    })
-                    .ExecuteCommandAsync(HttpContext.RequestAborted);
                 success++;
             }
             catch (UserFriendlyException e)
@@ -2601,9 +2595,26 @@ public class OrderController : BaseController
             }
         }
 
+
+        await _orderDelayRepository.Updateable(updateDelays)
+            .UpdateColumns(d => d.DelayState)
+            .ExecuteCommandAsync(HttpContext.RequestAborted);
+
+        await _orderRepository.Updateable(updateOrders)
+            .UpdateColumns(d => new
+            {
+                d.ExpiredTime,
+                d.NearlyExpiredTime,
+                d.NearlyExpiredTimeOne,
+                d.ExpiredTimeProvince
+            })
+            .ExecuteCommandAsync(HttpContext.RequestAborted);
+
         return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result}";
     }
 
+
+
     /// <summary>
     ///  延期查询流程办理下一步可选节点
     /// </summary>

+ 258 - 251
src/Hotline.Api/Controllers/OrderTerminateController.cs

@@ -28,285 +28,292 @@ using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Requests;
 using Hotline.Tools;
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
 
 namespace Hotline.Api.Controllers
 {
-	/// <summary>
-	/// 终止管理
-	/// </summary>
-	public class OrderTerminateController : BaseController
-	{
-		private readonly ISessionContext _sessionContext;
-		private readonly IMapper _mapper;
-		private readonly IFileRepository _fileRepository;
-		private readonly IWorkflowApplication _workflowApplication;
-		private readonly IRepository<Workflow> _workflowRepository;
-		private readonly IWorkflowDomainService _workflowDomainService;
-		private readonly IOrderRepository _orderRepository;
-		private readonly IOrderDomainService _orderDomainService;
-		private readonly IOrderTerminateRepository _orderTerminateRepository;
-		private readonly IOrderApplication _orderApplication;
+    /// <summary>
+    /// 终止管理
+    /// </summary>
+    public class OrderTerminateController : BaseController
+    {
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+        private readonly IFileRepository _fileRepository;
+        private readonly IWorkflowApplication _workflowApplication;
+        private readonly IRepository<Workflow> _workflowRepository;
+        private readonly IWorkflowDomainService _workflowDomainService;
+        private readonly IOrderRepository _orderRepository;
+        private readonly IOrderDomainService _orderDomainService;
+        private readonly IOrderTerminateRepository _orderTerminateRepository;
+        private readonly IOrderApplication _orderApplication;
+        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
 
-		public OrderTerminateController(
-			ISessionContext sessionContext,
-			IMapper mapper,
-			IFileRepository fileRepository,
-			IWorkflowApplication workflowApplication,
-			IRepository<Workflow> workflowRepository,
-			IWorkflowDomainService workflowDomainService,
-			IOrderRepository orderRepository,
-			IOrderDomainService orderDomainService,
-			IOrderTerminateRepository orderTerminateRepository,
-			IOrderApplication orderApplication
-			) 
-		{ 
-			_sessionContext = sessionContext;
-			_mapper = mapper;
-			_fileRepository = fileRepository;
-			_workflowApplication = workflowApplication;
-			_workflowRepository = workflowRepository;
-			_workflowDomainService = workflowDomainService;
-			_orderRepository = orderRepository;
-			_orderDomainService = orderDomainService;
-			_orderTerminateRepository = orderTerminateRepository;
-			_orderApplication= orderApplication;
-		}
+        public OrderTerminateController(
+            ISessionContext sessionContext,
+            IMapper mapper,
+            IFileRepository fileRepository,
+            IWorkflowApplication workflowApplication,
+            IRepository<Workflow> workflowRepository,
+            IWorkflowDomainService workflowDomainService,
+            IOrderRepository orderRepository,
+            IOrderDomainService orderDomainService,
+            IOrderTerminateRepository orderTerminateRepository,
+            IOrderApplication orderApplication,
+             IOptionsSnapshot<AppConfiguration> appOptions
+            )
+        {
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+            _fileRepository = fileRepository;
+            _workflowApplication = workflowApplication;
+            _workflowRepository = workflowRepository;
+            _workflowDomainService = workflowDomainService;
+            _orderRepository = orderRepository;
+            _orderDomainService = orderDomainService;
+            _orderTerminateRepository = orderTerminateRepository;
+            _orderApplication = orderApplication;
+            _appOptions = appOptions;
 
-		/// <summary>
-		/// 工单终止待申请列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet("may-terminate")]
-		public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
-		{
-			var isAdmin = _orderDomainService.IsCheckAdmin();
-			var (total, items) =await _orderRepository.Queryable(isAdmin:isAdmin)
-				.Includes(d=>d.OrderTerminates)
-				.Where(d=> SqlFunc.Subqueryable<OrderTerminate>().Where(t=> t.OrderId  == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
-				.Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
-				.WhereIF(!string.IsNullOrEmpty(dto.No),d=>d.No!.Contains(dto.No!))
-				.WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
-				.WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
-					d => d.OrderTerminates.Any(t=>t.CreationTime >= dto.ApplyStartTime && t.CreationTime<= dto.ApplyEndTime))
-				.WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue,d=>d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
-				.OrderByDescending(d => d.StartTime)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
-		}
+        }
 
+        /// <summary>
+        /// 工单终止待申请列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("may-terminate")]
+        public async Task<PagedDto<OrderDto>> MayOrderTerminateList([FromQuery] OrderTerminateListDto dto)
+        {
+            var isAdmin = _orderDomainService.IsCheckAdmin();
+            var (total, items) = await _orderRepository.Queryable(isAdmin: isAdmin)
+                .Includes(d => d.OrderTerminates)
+                .WhereIF(_appOptions.Value.IsZiGong, d => d.Source != ESource.ProvinceStraight)//自贡任务  495 终止申请页面只显示市工单
+                .Where(d => SqlFunc.Subqueryable<OrderTerminate>().Where(t => t.OrderId == d.Id && t.Status != ETerminateStatus.SendBackStart).NotAny())
+                .Where(d => d.Status >= EOrderStatus.Filed && d.ActualHandleOrgCode.StartsWith(_sessionContext.OrgId))
+                .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No!.Contains(dto.No!))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title!.Contains(dto.Title!))
+                .WhereIF(dto.ApplyStartTime.HasValue && dto.ApplyEndTime.HasValue,
+                    d => d.OrderTerminates.Any(t => t.CreationTime >= dto.ApplyStartTime && t.CreationTime <= dto.ApplyEndTime))
+                .WhereIF(dto.StartTime.HasValue && dto.EndTime.HasValue, d => d.StartTime >= dto.StartTime && d.StartTime <= dto.EndTime)
+                .OrderByDescending(d => d.StartTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+        }
 
-		/// <summary>
-		/// 工单终止列表
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpGet]
-		public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
-		{
-			var (total, items) = await _orderApplication.OrderTerminateList(dto)
-				.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-			return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
-		}
 
-		/// <summary>
-		/// 工单终止列表导出
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
+        /// <summary>
+        /// 工单终止列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet]
+        public async Task<PagedDto<OrderTerminateEntityDto>> OrderTerminateList([FromQuery] OrderTerminateListDto dto)
+        {
+            var (total, items) = await _orderApplication.OrderTerminateList(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<OrderTerminateEntityDto>(total, _mapper.Map<IReadOnlyList<OrderTerminateEntityDto>>(items));
+        }
 
-		[HttpPost("export")]
-		public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
-		{
-			var query = _orderApplication.OrderTerminateList(dto.QueryDto);
-			List<OrderTerminate> data;
-			if (dto.IsExportAll)
-			{
-				data = await query.ToListAsync(HttpContext.RequestAborted);
-			}
-			else
-			{
-				var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
-				data = items;
-			}
+        /// <summary>
+        /// 工单终止列表导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
 
-			var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);
+        [HttpPost("export")]
+        public async Task<FileStreamResult> OrderTerminateListExport([FromBody] ExportExcelDto<OrderTerminateListDto> dto)
+        {
+            var query = _orderApplication.OrderTerminateList(dto.QueryDto);
+            List<OrderTerminate> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
 
-			dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);
+            var dataDtos = _mapper.Map<ICollection<OrderTerminateEntityDto>>(data);
 
-			var dtos = dataDtos
-				.Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
-				.Cast<object>()
-				.ToList();
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<OrderTerminateEntityDto>(dto.ColumnInfos);
 
-			var stream = ExcelHelper.CreateStream(dtos);
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(OrderTerminateEntityDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
 
-			return ExcelStreamResult(stream, "工单终止列表");
-		}
+            var stream = ExcelHelper.CreateStream(dtos);
 
+            return ExcelStreamResult(stream, "工单终止列表");
+        }
 
-		/// <summary>
-		/// 开始工单终止流程
-		/// </summary>
-		[HttpPost("startflow")]
-		[LogFilter("开始工单终止流程")]
-		public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
-		{
-			var screenAny = await _orderTerminateRepository.AnyAsync(x =>
-				x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
-			if (screenAny)
-				throw UserFriendlyException.SameMessage("该工单已提起终止申请,正在审批过程中,不能申请");
 
-			var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status ==  ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
-			if (isNoPass)
-				throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请,不能再次申请");
+        /// <summary>
+        /// 开始工单终止流程
+        /// </summary>
+        [HttpPost("startflow")]
+        [LogFilter("开始工单终止流程")]
+        public async Task StartFlow([FromBody] StartWorkflowDto<OrderTerminateDto> dto)
+        {
+            var screenAny = await _orderTerminateRepository.AnyAsync(x =>
+                x.OrderId == dto.Data.OrderId && x.Status == ETerminateStatus.Approval);
+            if (screenAny)
+                throw UserFriendlyException.SameMessage("该工单已提起终止申请,正在审批过程中,不能申请");
 
-			var model = _mapper.Map<OrderTerminate>(dto.Data);
-			model.Status = ETerminateStatus.Approval ;
-			model.InitId();
-			if (dto.Data.Files.Any())
-				model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
-			else
-				model.FileJson = new List<Share.Dtos.File.FileJson>();
-			await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
-			try
-			{
-				var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
-				startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
-				startDto.Opinion = dto.Data.Content;
-				startDto.Title = "申请终止流程";
-				// await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-				// await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-				await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
-			}
-			catch (Exception e)
-			{
-				await _orderTerminateRepository.RemoveAsync(model.Id);
-				model.Id = string.Empty;
-				throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
-			}
-		}
+            var isNoPass = await _orderTerminateRepository.AnyAsync(x => x.Status == ETerminateStatus.Refuse && x.OrderId == dto.Data.OrderId);
+            if (isNoPass)
+                throw UserFriendlyException.SameMessage("该工单已被拒绝过终止申请,不能再次申请");
 
+            var model = _mapper.Map<OrderTerminate>(dto.Data);
+            model.Status = ETerminateStatus.Approval;
+            model.InitId();
+            if (dto.Data.Files.Any())
+                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
+            else
+                model.FileJson = new List<Share.Dtos.File.FileJson>();
+            await _orderTerminateRepository.AddAsync(model, HttpContext.RequestAborted);
+            try
+            {
+                var startDto = _mapper.Map<StartWorkflowDto>(dto.Workflow);
+                startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderTerminate;
+                startDto.Opinion = dto.Data.Content;
+                startDto.Title = "申请终止流程";
+                // await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+                // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+                await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted);
+            }
+            catch (Exception e)
+            {
+                await _orderTerminateRepository.RemoveAsync(model.Id);
+                model.Id = string.Empty;
+                throw new UserFriendlyException($"工单开启终止流程失败!, {e.Message}", "工单开启终止流程失败");
+            }
+        }
 
-		/// <summary>
-		/// 工单终止修改后下一步流程
-		/// </summary>
-		[HttpPost("initial_nextFlow")]
-		[LogFilter("办理工单终止流程")]
-		public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
-		{
-			var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);
 
-			if (dto.Data.Files.Any())
-				model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
-			else
-				model.FileJson = new List<Share.Dtos.File.FileJson>();
+        /// <summary>
+        /// 工单终止修改后下一步流程
+        /// </summary>
+        [HttpPost("initial_nextFlow")]
+        [LogFilter("办理工单终止流程")]
+        public async Task InitialNextFlow([FromBody] TerminateNextFlowDto dto)
+        {
+            var model = await _orderTerminateRepository.GetAsync(dto.Data.Id);
 
-			model.Status = ETerminateStatus.Approval;
-			model.Content = dto.Data.Content;
-			model.IsRecommit = true;
-			await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
-			try
-			{
-				dto.NextWorkflow.WorkflowId = model.WorkflowId;
-				await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
-			}
-			catch (Exception e)
-			{
-				throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
-			}
-		}
+            if (dto.Data.Files.Any())
+                model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted);
+            else
+                model.FileJson = new List<Share.Dtos.File.FileJson>();
 
-		/// <summary>
-		/// 查询工单终止流程开启参数
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("screen/startflow")]
-		public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
-		{
-			return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
-				HttpContext.RequestAborted);
-		}
+            model.Status = ETerminateStatus.Approval;
+            model.Content = dto.Data.Content;
+            model.IsRecommit = true;
+            await _orderTerminateRepository.UpdateAsync(model, HttpContext.RequestAborted);
+            try
+            {
+                dto.NextWorkflow.WorkflowId = model.WorkflowId;
+                await _workflowDomainService.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted);
+            }
+            catch (Exception e)
+            {
+                throw new UserFriendlyException($"工单终止下一步流程失败!, {e.Message}", "工单终止下一步流程失败");
+            }
+        }
 
-		/// <summary>
-		/// 查询工单终止流程参数
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("workflow/{id}")]
-		public async Task<string> GetTerminateWorkFlowAsync(string id)
-		{
-			var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
-			return workflow.Id;
-		}
+        /// <summary>
+        /// 查询工单终止流程开启参数
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("screen/startflow")]
+        public async Task<NextStepsDto> GetTerminateFlowStartOptionsAsync()
+        {
+            return await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderTerminate,
+                HttpContext.RequestAborted);
+        }
 
-		/// <summary>
-		///  甄别查询流程办理下一步可选节点
-		/// </summary>
-		/// <param name="workflowId"></param>
-		/// <returns></returns>
-		[HttpGet("{workflowId}/nextsteps")]
-		public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
-		{
-			return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
-		}
+        /// <summary>
+        /// 查询工单终止流程参数
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("workflow/{id}")]
+        public async Task<string> GetTerminateWorkFlowAsync(string id)
+        {
+            var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id);
+            return workflow.Id;
+        }
 
-		/// <summary>
-		/// 终止详情
-		/// </summary>
-		/// <param name="id"></param>
-		/// <returns></returns>
-		[HttpGet("{id}")]
-		public async Task<OrderTerminateEntityDto> Entity(string id)
-		{
-			var model = await _orderTerminateRepository.Queryable()
-				.Includes(x => x.Order) 
-				.Includes(x => x.Workflow, d => d.Steps)
-				.FirstAsync(x => x.Id == id);
-			var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
-			rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
-				_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
-			if (model.Status ==  ETerminateStatus.SendBackStart)
-				rspModel.IsCanHandle = false;
-			rspModel.Handle = false;
-			if (!string.IsNullOrEmpty(rspModel.WorkflowId))
-			{
-				rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
-					_sessionContext.RequiredOrgId, HttpContext.RequestAborted);
-			}
+        /// <summary>
+        ///  甄别查询流程办理下一步可选节点
+        /// </summary>
+        /// <param name="workflowId"></param>
+        /// <returns></returns>
+        [HttpGet("{workflowId}/nextsteps")]
+        public async Task<NextStepsDto> OrderTerminateNextsteps(string workflowId)
+        {
+            return await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted);
+        }
 
-			if (rspModel.FileJson != null && rspModel.FileJson.Any())
-			{
-				var ids = rspModel.FileJson.Select(x => x.Id).ToList();
-				rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
-			}
-			return rspModel;
-		}
+        /// <summary>
+        /// 终止详情
+        /// </summary>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        [HttpGet("{id}")]
+        public async Task<OrderTerminateEntityDto> Entity(string id)
+        {
+            var model = await _orderTerminateRepository.Queryable()
+                .Includes(x => x.Order)
+                .Includes(x => x.Workflow, d => d.Steps)
+                .FirstAsync(x => x.Id == id);
+            var rspModel = _mapper.Map<OrderTerminateEntityDto>(model);
+            rspModel.IsCanHandle = model.Workflow?.IsCanHandle(
+                _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false;
+            if (model.Status == ETerminateStatus.SendBackStart)
+                rspModel.IsCanHandle = false;
+            rspModel.Handle = false;
+            if (!string.IsNullOrEmpty(rspModel.WorkflowId))
+            {
+                rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId,
+                    _sessionContext.RequiredOrgId, HttpContext.RequestAborted);
+            }
 
-		/// <summary>
-		/// 列表页面基础数据
-		/// </summary>
-		/// <returns></returns>
-		[HttpGet("base")]
-		public async Task<object> BaseData()
-		{
-			var rsp = new
-			{
-				Status = EnumExts.GetDescriptions<ETerminateStatus>(),
-			};
-			return rsp;
-		}
+            if (rspModel.FileJson != null && rspModel.FileJson.Any())
+            {
+                var ids = rspModel.FileJson.Select(x => x.Id).ToList();
+                rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+            }
+            return rspModel;
+        }
 
-		/// <summary>
-		/// 终止修改理由
-		/// </summary>
-		/// <param name="dto"></param>
-		/// <returns></returns>
-		[HttpPut("update_content")]
-		[LogFilter("终止修改理由")]
-		public async Task Update([FromBody] OrderTerminateContentDto dto)
-		{
-			await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
-		}
+        /// <summary>
+        /// 列表页面基础数据
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("base")]
+        public async Task<object> BaseData()
+        {
+            var rsp = new
+            {
+                Status = EnumExts.GetDescriptions<ETerminateStatus>(),
+            };
+            return rsp;
+        }
 
-	}
+        /// <summary>
+        /// 终止修改理由
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPut("update_content")]
+        [LogFilter("终止修改理由")]
+        public async Task Update([FromBody] OrderTerminateContentDto dto)
+        {
+            await _orderTerminateRepository.Updateable().SetColumns(x => new OrderTerminate { Content = dto.Content }).Where(x => x.Id == dto.Id).ExecuteCommandAsync();
+        }
+
+    }
 }

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

@@ -757,7 +757,7 @@ namespace Hotline.Api.Controllers
                     }
                     catch (Exception e)
                     {
-                        _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                        _logger.LogError($"写入智能质检异常3!, \r\n{e.Message}");
                     }
                 }
                 await _qualitey.UpdateAsync(quality, HttpContext.RequestAborted);

+ 3 - 2
src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs

@@ -281,8 +281,9 @@ public class SnapshotController : BaseController
     /// <returns></returns>
     [HttpGet("wait_accept_count")]
     public async Task<int> GetSnapshotWaitForAcceptCountAsync()
-        => await _orderRepository
-            .CountAsync(m => m.SourceChannelCode == "ZGSSP" && m.Status == Share.Enums.Order.EOrderStatus.WaitForAccept);
+    { return 0; }
+    //=> await _orderRepository
+    //        .CountAsync(m => m.SourceChannelCode == "ZGSSP" && m.Status == Share.Enums.Order.EOrderStatus.WaitForAccept);
 
     /// <summary>
     /// 获取区域

+ 3 - 3
src/Hotline.Application/Quality/QualityApplication.cs

@@ -193,14 +193,14 @@ namespace Hotline.Application.Quality
                     var audioFile = string.Empty;
                     var fromNo = string.Empty;
                     DateTime? callStartTime = null;
-                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun)
+                    if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun && !string.IsNullOrEmpty(order.CallId))
                     {
                         var call = await _callApplication.GetTianrunCallAsync(order.CallId, cancellationToken);
                         audioFile = call.RecordingAbsolutePath;
                         fromNo = call.CPN;
                         callStartTime = call.CreatedTime;
                     }
-                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang)
+                    else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang && !string.IsNullOrEmpty(order.CallId))
                     {
                         var call = await _callApplication.GetCallAsync(order.CallId, cancellationToken);
                         audioFile = call.AudioFile;
@@ -222,7 +222,7 @@ namespace Hotline.Application.Quality
                 }
                 catch (Exception e)
                 {
-                    _logger.LogError($"写入智能质检异常!, \r\n{e.Message}");
+                    _logger.LogError($"写入智能质检异常1!, \r\n{e.Message}");
                 }
             }
 

+ 1 - 1
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -366,7 +366,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         var has = await _supplementRecordRepository.Queryable()
             .Where(m => specialRedPackAuditIds.Contains(m.RedPackAuditId))
             .AnyAsync();
-        if (has) throw new UserFriendlyException("该工单已发放红包,不能撤销审批");
+        if (has) throw UserFriendlyException.SameMessage("该工单已发放红包,不能撤销审批");
         await _specialRedPackAuditRepository.Removeable()
             .Where(m => specialRedPackAuditIds.Contains(m.Id))
             .ExecuteCommandAsync();

+ 3 - 3
src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs

@@ -1877,9 +1877,9 @@ namespace Hotline.Repository.SqlSugar.Orders
                     Id = x.Id,
                     SourceChannel = x.OrderVisit.Order.SourceChannel,
                     AcceptType = x.OrderVisit.Order.AcceptType,
-                    OrgNoSatisfiedReason = x.OrgNoSatisfiedReason,
-                    City=x.OrderVisit.Order.City,
-                    County=x.OrderVisit.Order.County,
+                    OrgNoSatisfiedReasonText = SqlFunc.MappingColumn<string>("(SELECT string_agg(elem->> 'Value', ',') FROM jsonb_array_elements(\"OrgNoSatisfiedReason\"::jsonb) elem )"),
+                    City = x.OrderVisit.Order.City,
+                    County = x.OrderVisit.Order.County,
                     OrderId = x.OrderVisit.Order.Id,
                     VisitId = x.OrderVisit.Id,
                     No = x.OrderVisit.No,

+ 2 - 2
src/Hotline.Share/Dtos/Order/OrderBiDto.cs

@@ -558,12 +558,12 @@ namespace Hotline.Share.Dtos.Order
         /// <summary>
         /// 不满意原因
         /// </summary>
-        public List<Kv>? OrgNoSatisfiedReason { get; set; }
+        public string OrgNoSatisfiedReasonText { get; set; }
 
         /// <summary>
         /// 不满意原因字符串
         /// </summary>
-        public string OrgNoSatisfiedReasonText => OrgNoSatisfiedReason != null ? string.Join(',', OrgNoSatisfiedReason.Select(d => d.Value)) : "";
+        //public string OrgNoSatisfiedReasonText => OrgNoSatisfiedReason != null ? string.Join(',', OrgNoSatisfiedReason.Select(d => d.Value)) : "";
 
         /// <summary>
         /// 市

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

@@ -62,6 +62,14 @@ namespace Hotline.FlowEngine.Workflows
             Action<Workflow, WorkflowStep, StepDefine, WorkflowStep>? newStepConfig = null,
             CancellationToken cancellationToken = default);
 
+
+        /// <summary>
+        /// 开启流程直接归档
+        /// </summary>
+        Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
+            CancellationToken cancellationToken = default);
+
+
         /// <summary>
         /// 查询工作流
         /// </summary>
@@ -290,10 +298,7 @@ namespace Hotline.FlowEngine.Workflows
         /// </summary>
         Task<List<WorkflowStep>> GetStepsBelongsToAsync(string userId, CancellationToken cancellationToken);
 
-		/// <summary>
-		/// 查询归属多个用户的所有流程节点
-		/// </summary>
-		Task<List<WorkflowStep>> GetStepsBelongsToAsync(List<string> userIds, CancellationToken cancellationToken);
+
 
 		/// <summary>
 		/// 查询归属多个用户的所有流程节点 当天
@@ -301,12 +306,6 @@ namespace Hotline.FlowEngine.Workflows
 		/// <returns></returns>
 		Task<List<WorkflowStep>> GetStepsBelongsDayToAsync(List<string> userIds, DateTime time, CancellationToken cancellationToken);
 
-		/// <summary>
-		/// 开启流程直接归档
-		/// </summary>
-		Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
-            CancellationToken cancellationToken = default);
-
         /// <summary>
         /// 批量修改工单办理对象
         /// </summary>
@@ -323,7 +322,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 更新未办理节点的期满时间
         /// </summary>
-        Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime expiredTime, CancellationToken cancellation);
+        Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime? expiredTime, CancellationToken cancellation);
 
         /// <summary>
         /// 查询该部门最后办理节点

+ 39 - 22
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -23,6 +23,7 @@ using Hotline.Configurations;
 using Hotline.Share.Dtos.File;
 using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Microsoft.Extensions.Options;
+using Hotline.Share.Dtos.Users;
 
 namespace Hotline.FlowEngine.Workflows
 {
@@ -640,6 +641,43 @@ namespace Hotline.FlowEngine.Workflows
             return nextSteps;
         }
 
+
+        /// <summary>
+        /// 开启流程直接归档
+        /// </summary>
+        public async Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
+            CancellationToken cancellationToken = default)
+        {
+            //var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
+            //var definition = wfModule.Definition;
+            //if (definition == null)
+            //    throw new UserFriendlyException("无效模板编码");
+            //if (definition.Status is not EDefinitionStatus.Enable)
+            //    throw new UserFriendlyException("该模板不可用");
+
+            //var endStepDefine = definition.FindEndStepDefine();
+            //dto.NextStepCode = endStepDefine.Code;
+            //dto.NextStepName = endStepDefine.Name;
+            //dto.FlowDirection = EFlowDirection.CenterToFile;
+
+            //await StartAsync(dto, externalId, expiredTime, cancellationToken: cancellationToken);
+
+            var (workflow, startStep) = await StartAsync(dto, externalId, expiredTime, cancellationToken: cancellationToken);
+            var nextDto = _mapper.Map<NextWorkflowDto>(dto);
+            nextDto.WorkflowId = workflow.Id;
+            nextDto.StepId = startStep.Id;
+
+            var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
+            nextDto.NextStepCode = endStepDefine.Code;
+            nextDto.NextStepName = endStepDefine.Name;
+
+            await NextAsync(workflow, nextDto,
+                expiredTime: expiredTime,
+                isAutoFillSummaryOpinion: true,
+                cancellationToken: cancellationToken);
+        }
+
+
         public async Task<Workflow> GetWorkflowAsync(string workflowId,
             bool withDefine = false, bool withSteps = false,
             bool withTraces = false, bool withTracesTree = false,
@@ -1136,27 +1174,6 @@ namespace Hotline.FlowEngine.Workflows
             return (currentStep, prevStep, countersignStartStep);
         }
 
-        /// <summary>
-        /// 开启流程直接归档
-        /// </summary>
-        public async Task StartToEndAsync(StartWorkflowDto dto, string externalId, DateTime? expiredTime = null,
-            CancellationToken cancellationToken = default)
-        {
-            var wfModule = await GetWorkflowModuleAsync(dto.DefinitionModuleCode, cancellationToken);
-            var definition = wfModule.Definition;
-            if (definition == null)
-                throw new UserFriendlyException("无效模板编码");
-            if (definition.Status is not EDefinitionStatus.Enable)
-                throw new UserFriendlyException("该模板不可用");
-
-            var endStepDefine = definition.FindEndStepDefine();
-            dto.NextStepCode = endStepDefine.Code;
-            dto.NextStepName = endStepDefine.Name;
-            dto.FlowDirection = EFlowDirection.CenterToFile;
-
-            await StartAsync(dto, externalId, expiredTime, cancellationToken: cancellationToken);
-        }
-
         /// <summary>
         /// 查询派单池中流程节点id
         /// </summary>
@@ -1289,7 +1306,7 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 更新未办理节点的期满时间
         /// </summary>
-        public async Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime expiredTime,
+        public async Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime? expiredTime,
             CancellationToken cancellation)
         {
             var steps = await _workflowStepRepository.Queryable()

+ 18 - 0
src/Hotline/Validators/Ippbx/TrOnDutyDtoValidator.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FluentValidation;
+using Hotline.Share.Dtos.TrCallCenter;
+
+namespace Hotline.Validators.Ippbx
+{
+    public class TrOnDutyDtoValidator : AbstractValidator<TrOnDutyDto>
+    {
+        public TrOnDutyDtoValidator()
+        {
+            RuleFor(d=>d.TelNo).NotEmpty().WithMessage("分机号不能为空");
+        }
+    }
+}