Browse Source

合并冲突

Dun.Jason 10 tháng trước cách đây
mục cha
commit
67f60733a8
25 tập tin đã thay đổi với 865 bổ sung169 xóa
  1. 34 0
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  2. 84 13
      src/Hotline.Api/Controllers/OrderController.cs
  3. 140 0
      src/Hotline.Api/Controllers/OrderProvinceZmhdController.cs
  4. 45 6
      src/Hotline.Api/Controllers/TestController.cs
  5. 2 2
      src/Hotline.Api/config/appsettings.json
  6. 5 0
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  7. 29 4
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  8. 1 0
      src/Hotline.Application/Hotline.Application.csproj
  9. 1 1
      src/Hotline.Application/Orders/IOrderApplication.cs
  10. 37 21
      src/Hotline.Application/Orders/OrderApplication.cs
  11. 139 102
      src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs
  12. 11 2
      src/Hotline.Repository.SqlSugar/Ts/BaseRepositoryTextSearch.cs
  13. 8 0
      src/Hotline.Repository.SqlSugar/Ts/IRepositoryTextSearch.cs
  14. 5 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  15. 5 0
      src/Hotline.Share/Dtos/FlowEngine/NextWorkflowDto.cs
  16. 27 2
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  17. 135 0
      src/Hotline.Share/Dtos/Order/OrderProvinceZmhdDto.cs
  18. 1 1
      src/Hotline.Share/Hotline.Share.csproj
  19. 7 2
      src/Hotline.Share/Mq/EventNames.Order.cs
  20. 6 0
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  21. 11 0
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  22. 14 0
      src/Hotline/Orders/IOrderRepository.cs
  23. 40 6
      src/Hotline/Orders/Order.cs
  24. 72 6
      src/Hotline/Orders/OrderProvinceZmhd.cs
  25. 6 1
      src/Hotline/Settings/SettingConstants.cs

+ 34 - 0
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -2964,6 +2964,40 @@ namespace Hotline.Api.Controllers.Bi
             return ExcelStreamResult(stream, "受理类型分时统计数据");
         }
 
+        /// <summary>
+        /// 信件来源分时统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("order_source_time")]
+        public async Task<object> OrderSourceTime([FromQuery] TimeSharingPagedKeywordRequest dto)
+        {
+            var item = await _orderRepository.OrderSourceTime(dto);
+
+            var titleData = await _systemDicDataRepository.Queryable()
+                .Where(p => p.DicTypeCode == "SourceChannel")
+                .Select(p => new
+                {
+                    Key = p.DicDataValue,
+                    Value = p.DicDataName
+                }).ToListAsync();
+
+            return new { Item = item, TitleData = titleData };
+        }
+
+        /// <summary>
+        /// 信件来源分时统计-导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("order_source_time_export")]
+        public async Task<FileStreamResult> OrderSourceTimeExport([FromBody] TimeSharingPagedKeywordRequest dto)
+        {
+            var dataTable = await _orderRepository.OrderSourceTimeExport(dto);
+            var stream = ExcelHelper.CreateStream(dataTable);
+            return ExcelStreamResult(stream, "信件来源分时统计数据");
+        }
+
         /// <summary>
         /// 部门满意度明细
         /// </summary>

+ 84 - 13
src/Hotline.Api/Controllers/OrderController.cs

@@ -2418,6 +2418,41 @@ public class OrderController : BaseController
         //}
 		if (!string.IsNullOrEmpty(order.WorkflowId))
         {
+            bool canInsteadHandle = false;
+			//班长代办
+			var settingEnable = _systemSettingCacheManager.GetSetting(SettingConstants.ChargeDAffaires);
+            var isEnable = settingEnable != null && settingEnable.SettingValue.Any() ? int.Parse(settingEnable?.SettingValue[0]) : 0;
+			if (isEnable > 0)
+			{
+				var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor);
+				var settingStr = setting?.SettingValue;
+				var roles = _sessionContext.Roles;
+				foreach (var item in settingStr)
+				{
+                    if (roles != null && roles.Contains(item))
+                    { 
+                        canInsteadHandle = true; 
+                    }else {
+                        canInsteadHandle = false;
+                    };
+				}
+				if (canInsteadHandle)
+				{
+					var unhandleSteps =
+						await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted);
+					// 会签多节点 不允许班长代办
+					if (unhandleSteps.Count > 1)
+						canInsteadHandle = false;
+					if (isEnable < 3 && unhandleSteps.Count == 1)
+                    {
+                        var type = isEnable - 1;
+						var step = unhandleSteps.FirstOrDefault(d => d.BusinessType == (EBusinessType)type);
+						canInsteadHandle = step != null && !string.IsNullOrEmpty(step.Id);
+						if (canInsteadHandle && step.IsInCountersign())
+							canInsteadHandle = false;
+					}
+				}
+			}
             var result = await _workflowDomainService.GetWorkflowHandlePermissionAsync(
                 order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles,
                 cancellationToken: HttpContext.RequestAborted);
@@ -2425,12 +2460,14 @@ public class OrderController : BaseController
             dto.CountersignId = result.CountersignId;
             dto.CanHandle = result.CanHandle;
             dto.CanPrevious = result.CanPrevious;
+            dto.CanInsteadHandle = !dto.CanHandle && canInsteadHandle;
 
-            await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
+			await _mediator.Publish(new GetOrderDetailNotify(result.Workflow,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName));
         }
+       
 
         //var dto = _mapper.Map<OrderDto>(order!);
         //dto.CountersignId = countersignId;
@@ -2500,16 +2537,16 @@ public class OrderController : BaseController
         dto.RepeatableEventDetails = repeatables;
         if (!string.IsNullOrEmpty(dto.WorkflowId))
         {
-			var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
-				cancellationToken: HttpContext.RequestAborted);
-            var centerOpinion = workflow.Steps.Where(x => x.HandlerOrgId == OrgSeedData.CenterId).OrderByDescending(x=>x.CreationTime).Select(x=>x.Opinion).First();
-            dto.CenterOpinion = string.IsNullOrEmpty(centerOpinion)? string.Empty: centerOpinion;
-            var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x=>x.CreationTime).FirstAsync();
+            var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true,
+                cancellationToken: HttpContext.RequestAborted);
+            var centerOpinion = workflow.Steps.Where(x => x.HandlerOrgId == OrgSeedData.CenterId).OrderByDescending(x => x.CreationTime).Select(x => x.Opinion).First();
+            dto.CenterOpinion = string.IsNullOrEmpty(centerOpinion) ? string.Empty : centerOpinion;
+            var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x => x.CreationTime).FirstAsync();
             dto.SendBackOpinion = sendBack is { Id: not null } && !string.IsNullOrEmpty(sendBack.AuditContent) ? sendBack.AuditContent : string.Empty;
-            List<OrderRemarksDto> remarks = workflow.Steps.Where(x=> !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
+            List<OrderRemarksDto> remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.CreationTime, RemarkUser = x.CreatorName }).ToList();
             dto.OrderRemarks = remarks;
-		}
-		return dto;
+        }
+        return dto;
     }
 
     /// <summary>
@@ -2563,7 +2600,7 @@ public class OrderController : BaseController
         }
 
         //内容分词
-        await _orderApplication.OrderParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
+        await _orderApplication.OrderParticiple(dto.Content, order.Id,order.CreationTime, HttpContext.RequestAborted);
         //敏感分词
         await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted);
         //sms
@@ -2688,7 +2725,7 @@ public class OrderController : BaseController
             throw UserFriendlyException.SameMessage("工单已发起流程,不可编辑");
 
         if (order.Content != dto.Content)
-            await _orderApplication.OrderParticiple(dto.Content, dto.Id, HttpContext.RequestAborted);
+            await _orderApplication.OrderParticiple(dto.Content, dto.Id, order.CreationTime, HttpContext.RequestAborted);
         if (dto.RepeatableEventDetails?.Any() ?? false)
         {
             var reAdds = dto.RepeatableEventDetails.Where(x => string.IsNullOrEmpty(x.OrderId) && !x.IsDeleted)
@@ -2919,9 +2956,43 @@ public class OrderController : BaseController
     }
 
     /// <summary>
-    /// 结束会签
+    /// 查询工单办理下一步可选节点(带推荐部门)
     /// </summary>
-    [HttpPost("endcs")]
+    [HttpGet("nextsteps_commission/{orderId}")]
+    public async Task<NextStepsWithOpinionDto<RecommendStepOption>> GetNextStepsWithRecommendCommission(string orderId)
+    {
+	    var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted);
+	    if (string.IsNullOrEmpty(order.WorkflowId))
+		    throw UserFriendlyException.SameMessage("该工单未开启流程");
+	    var unhandleSteps =
+		    await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted);
+	    if (unhandleSteps.Count > 1)
+		    throw UserFriendlyException.SameMessage("会签工单不允许班长代办");
+	    if (unhandleSteps.Count < 1)
+		    throw UserFriendlyException.SameMessage("未查询到流程信息");
+        var stepOne = unhandleSteps.First();
+        if (stepOne.IsInCountersign())
+	        throw UserFriendlyException.SameMessage("会签工单不允许班长代办");
+		var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, stepOne.Id, HttpContext.RequestAborted);
+	    dto.ExpiredTime = order.ExpiredTime;
+	    var rsp = _mapper.Map<NextStepsWithOpinionDto<RecommendStepOption>>(dto);
+	    foreach (var step in rsp.Steps)
+	    {
+		    if (dto.CurrentStepBusinessType is not EBusinessType.Send ||
+		        step.BusinessType is not EBusinessType.Department) continue;
+		    var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted);
+		    if (org is null) continue;
+		    step.RecommendOrgId = org.Id;
+		    step.RecommendOrgName = org.Name;
+	    }
+
+	    return rsp;
+    }
+
+	/// <summary>
+	/// 结束会签
+	/// </summary>
+	[HttpPost("endcs")]
     public async Task EndCountersign([FromBody] EndCountersignDto dto)
     {
         var workflow = await _workflowDomainService.TerminalCountersignAsync(dto.CountersignId, HttpContext.RequestAborted);

+ 140 - 0
src/Hotline.Api/Controllers/OrderProvinceZmhdController.cs

@@ -0,0 +1,140 @@
+using DotNetCore.CAP;
+using Hotline.Orders;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Order;
+using MapsterMapper;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using StackExchange.Redis;
+using System.Reflection;
+using XF.Domain.Authentications;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Api.Controllers
+{
+    public class OrderProvinceZmhdController : BaseController
+    {
+        private readonly ILogger<OrderProvinceZmhdController> _logger;
+        private readonly ISessionContext _sessionContext;
+        private readonly IMapper _mapper;
+        private readonly ICapPublisher _capPublisher;
+        private readonly IOrderRepository _orderRepository;
+        private readonly IRepository<OrderProvinceZmhd> _orderProvinceZmhdRepository;
+
+        public OrderProvinceZmhdController(ILogger<OrderProvinceZmhdController> logger,
+            ISessionContext sessionContext,
+            IMapper mapper,
+            ICapPublisher capPublisher,
+            IOrderRepository orderRepository,
+            IRepository<OrderProvinceZmhd> orderProvinceZmhdRepository)
+        {
+            _logger = logger;
+            _sessionContext = sessionContext;
+            _mapper = mapper;
+            _capPublisher = capPublisher;
+            _orderRepository = orderRepository;
+            _orderProvinceZmhdRepository = orderProvinceZmhdRepository;
+        }
+
+        /// <summary>
+        /// 查询列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("getorderlist")]
+        public async Task<PagedDto<OrderDto>> GetOrderList([FromQuery] OrderProvinceZmhdDto dto)
+        {
+            RefAsync<int> total = 0;
+            var items = await _orderRepository.Queryable()
+                .Where(p => p.SourceChannelCode == "SZMHD" && p.IsProvince == false && p.Status > EOrderStatus.Filed)
+                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo == dto.ProvinceNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.StartsWith(dto.Title!))
+                .WhereIF(!string.IsNullOrEmpty(dto.AnswerOu), p => p.ActualHandleOrgName == dto.AnswerOu)
+                .WhereIF(!string.IsNullOrEmpty(dto.AuditFirstName), p => p.AuditFirstName == dto.AuditFirstName)
+                .WhereIF(dto.IsProvinceZmhd.HasValue, p => p.IsProvinceZmhd == dto.IsProvinceZmhd)
+                .WhereIF(dto.StartTime.HasValue, d => d.AuditFirstTime >= dto.StartTime) //初审时间开始
+                .WhereIF(dto.EndTime.HasValue, d => d.AuditFirstTime <= dto.EndTime) //初审时间结束
+                .OrderByDescending(d => d.CreationTime)
+                .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);
+
+            return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
+        }
+
+        /// <summary>
+        /// 查询政民互动发布详情
+        /// </summary>
+        /// <param name="Id"></param>
+        /// <returns></returns>
+        [HttpGet("getorderprovincezmhdinfo")]
+        public async Task<PublicOrderProvinceZmhdDto> GetOrderProvinceZmhdInfo(string Id)
+        {
+            var info = await _orderProvinceZmhdRepository.GetAsync(p => p.Id == Id, HttpContext.RequestAborted);
+            if (info == null)
+                throw UserFriendlyException.SameMessage("查询失败");
+
+            return _mapper.Map<PublicOrderProvinceZmhdDto>(info);
+        }
+
+        /// <summary>
+        /// 政民互动发布
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("add")]
+        public async Task AddOrderProvinceZmhd([FromBody] AddOrderProvinceZmhdDto dto)
+        {
+            if (string.IsNullOrEmpty(dto.AnswerContent))
+                throw UserFriendlyException.SameMessage("整理结果不能为空!");
+
+            if (string.IsNullOrEmpty(dto.PublicOpinion))
+                throw UserFriendlyException.SameMessage("公开意见不能为空!");
+
+            if (dto.PublicOpinion.Length > 300)
+                throw UserFriendlyException.SameMessage("公开意见不能超过300字符!");
+
+            var order = await _orderRepository.GetAsync(p => p.Id == dto.OrderId, HttpContext.RequestAborted);
+            if (order == null)
+                throw UserFriendlyException.SameMessage("工单查询失败!");
+
+            OrderProvinceZmhd orderProvinceZmhd = new()
+            {
+                No = order.No,
+                ProvinceNo = order.ProvinceNo,
+                OrderId = order.Id,
+                Title = order.Title,
+                AnswerTime = order.ActualHandleTime,
+                AnswerOu = order.ActualHandleOrgName,
+                AnswerContent = dto.AnswerContent,
+                AuditFirstName = _sessionContext.UserName,
+                AuditFirstTime = DateTime.Now,
+                AuditSecondName = _sessionContext.UserName,
+                PublishDate = DateTime.Now,
+                PublicOpinion = dto.PublicOpinion
+            };
+            //查询是否已经发布过
+            var info = await _orderProvinceZmhdRepository.GetAsync(p => p.OrderId == order.Id, HttpContext.RequestAborted);
+            if (info != null)
+                throw UserFriendlyException.SameMessage("此工单已公开!");
+
+            //发布
+            var id = await _orderProvinceZmhdRepository.AddAsync(orderProvinceZmhd, HttpContext.RequestAborted);
+            if (string.IsNullOrEmpty(id))
+                throw UserFriendlyException.SameMessage("公开失败!");
+
+            //修改工单发布数据
+            order.IsProvinceZmhd = true;
+            order.AuditFirstName = _sessionContext.UserName;
+            order.AuditFirstTime = orderProvinceZmhd.AuditFirstTime;
+            order.OrderProvinceZmhdId = orderProvinceZmhd.Id;
+            await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
+
+            //推送数据
+            var publishPublishOrder = _mapper.Map<PublicOrderProvinceZmhdDto>(orderProvinceZmhd);
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderProvinceZmhd, publishPublishOrder);
+        }
+
+    }
+}

+ 45 - 6
src/Hotline.Api/Controllers/TestController.cs

@@ -202,10 +202,49 @@ public class TestController : BaseController
     }
     [HttpGet("testo111")]
     [AllowAnonymous]
-    public async Task Test111(DateTime StartTime, DateTime EndTime)
+    public async Task Test111(DateTime StartTime, DateTime? EndTime)
     {
 
-     
+        var list = await _orderRepository.Queryable()
+           .Where(p => p.CreationTime >= StartTime && p.CreationTime <= EndTime && p.Status >= EOrderStatus.Filed)
+           .Where(p => p.CreationTimeHandleDuration == null || p.CenterToOrgHandleDuration == null)
+           .ToListAsync();
+
+        if (list.Any())
+        {
+            foreach (var item in list)
+            {
+                var creationTimeHandleDurationWorkday = item.ActualHandleTime.HasValue
+                  ? _timeLimitDomainService.CalcWorkTime(item.CreationTime, item.ActualHandleTime.Value,
+                  item.ProcessType is EProcessType.Zhiban)
+                  : 0;
+                var centerToOrgHandleDurationWorkday = item.ActualHandleTime.HasValue && item.CenterToOrgTime.HasValue
+                    ? _timeLimitDomainService.CalcWorkTime(item.CenterToOrgTime.Value, item.ActualHandleTime.Value,
+                    item.ProcessType is EProcessType.Zhiban)
+                    : 0;
+
+                item.CreationTimeHandleDurationWorkday = creationTimeHandleDurationWorkday;
+                item.CenterToOrgHandleDurationWorkday = centerToOrgHandleDurationWorkday;
+
+                if (item.ActualHandleTime.HasValue)
+                {
+                    var count = Math.Round((item.ActualHandleTime - item.CreationTime).Value.TotalSeconds);
+                    item.CreationTimeHandleDuration = count <= 0 ? 1 : count;
+                }
+                else
+                    item.CreationTimeHandleDuration = 0;
+
+                if (item.ActualHandleTime.HasValue && item.CenterToOrgTime.HasValue)
+                {
+                    var count = Math.Round((item.ActualHandleTime - item.CenterToOrgTime).Value.TotalSeconds);
+                    item.CenterToOrgHandleDuration = count <= 0 ? 1 : count;
+                }
+                else
+                    item.CenterToOrgHandleDuration = 0;
+
+                await _orderRepository.UpdateAsync(item, HttpContext.RequestAborted);
+            }
+        }
     }
 
     [HttpGet("testo")]
@@ -542,10 +581,10 @@ public class TestController : BaseController
 
         var orderIds = orders.Select(d => d.Id).ToList();
         var steps = await _workflowStepRepository.Queryable()
-            .Where(d => orderIds.Contains(d.ExternalId) && 
+            .Where(d => orderIds.Contains(d.ExternalId) &&
                         d.BusinessType == EBusinessType.Send &&
                         d.Status == EWorkflowStepStatus.Handled)
-            .OrderBy(d=>d.CreationTime)
+            .OrderBy(d => d.CreationTime)
             .ToListAsync(HttpContext.RequestAborted);
 
         var updateOrders = new List<Order>();
@@ -554,7 +593,7 @@ public class TestController : BaseController
             var step = steps.Where(d => d.ExternalId == order.Id)
                 .OrderBy(d => d.CreationTime)
                 .FirstOrDefault();
-            if(step is null) continue;
+            if (step is null) continue;
 
             order.CenterToOrgTime = step.HandleTime;
             order.CenterToOrgHandlerId = step.HandlerId;
@@ -581,7 +620,7 @@ public class TestController : BaseController
 
             updateOrders.Add(order);
         }
-        
+
         await _orderRepository.UpdateRangeAsync(updateOrders, HttpContext.RequestAborted);
     }
 

+ 2 - 2
src/Hotline.Api/config/appsettings.json

@@ -16,7 +16,7 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;",
+    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
     //"Redis": "110.188.24.182:50179,password=fengwo22@@",
     //"MongoDB": "mongodb://192.168.100.121:27017",
     //"Wex": "server=222.212.82.225;Port=4509;Database=fs_kft;Uid=root;Pwd=Wex@12345;"
@@ -25,7 +25,7 @@
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 3
+    "Database": 5
   },
   "Swagger": true,
   "Cors": {

+ 5 - 0
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -67,6 +67,11 @@ namespace Hotline.Application.FlowEngine
         /// </summary>
         Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// 查询指定节点的下一步待选节点
+        /// </summary>
+        Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, string stepId, CancellationToken cancellationToken);
+
         /// <summary>
         /// 查询撤回可选节点
         /// </summary>

+ 29 - 4
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -30,6 +30,7 @@ using Hotline.Share.Dtos.File;
 using Microsoft.Extensions.Logging;
 using System.Text;
 using System.Diagnostics;
+using NPOI.SS.Formula.Functions;
 
 namespace Hotline.Application.FlowEngine;
 
@@ -218,8 +219,12 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withDefine: true, withSteps: true,
             withTraces: true, withCountersigns: true, cancellationToken: cancellationToken);
 
-        var currentStep = _workflowDomainService.FindCurrentStepWaitForHandle(workflow,
-            current.RequiredUserId, current.RequiredOrgId, current.Roles);
+        //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("该状态不支持继续办理");
 
@@ -457,6 +462,24 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (currentStep.StepType is EStepType.End)
             throw new UserFriendlyException("结束节点无需办理");
 
+        return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
+    }
+
+    public async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(string workflowId, string stepId, CancellationToken cancellationToken)
+    {
+        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
+            cancellationToken: cancellationToken);
+        var currentStep = workflow.Steps.FirstOrDefault(d => d.Id == stepId);
+        if (currentStep == null)
+            throw new UserFriendlyException($"未查询到选择节点, workflowId: {workflowId}, stepId: {stepId}");
+        if (currentStep.StepType is EStepType.End)
+            throw new UserFriendlyException("结束节点无需办理");
+
+        return await GetNextStepsAsync(workflow, currentStep, cancellationToken);
+    }
+
+    private async Task<NextStepsWithOpinionDto<NextStepOption>> GetNextStepsAsync(Workflow workflow, WorkflowStep currentStep, CancellationToken cancellationToken)
+    {
         var dto = new NextStepsWithOpinionDto<NextStepOption>
         {
             CanReject = workflow.IsReviewType() && currentStep.CanReject,
@@ -465,6 +488,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             CurrentStepBusinessType = currentStep.BusinessType,
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
+            StepId = currentStep.Id
         };
 
         var currentStepDefine = _workflowDomainService.GetStepDefine(workflow.WorkflowDefinition, currentStep.Code);
@@ -485,14 +509,15 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             {
                 // 宜宾需求:会签汇总节点展示会签办理节点办理意见
                 var countersignHandleSteps = workflow.Steps.Where(d =>
-                        d.CountersignId == currentStep.CountersignId &&
-                        d.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single).ToList();
+                    d.CountersignId == currentStep.CountersignId &&
+                    d.CountersignPosition is ECountersignPosition.Multi or ECountersignPosition.Single).ToList();
                 var sb = new StringBuilder();
                 foreach (var countersignHandleStep in countersignHandleSteps)
                 {
                     //sb.AppendLine($"{countersignHandleStep.GetActualHandler()?.GetHandler().Value} : {countersignHandleStep.Opinion}");
                     sb.AppendLine($"{countersignHandleStep.GetHandler().Value} : {countersignHandleStep.Opinion}");
                 }
+
                 dto.Opinion = sb.ToString();
 
                 //当前待办节点为会签汇总节点时:检查是否为顶级会签汇总节点,t:按配置往下走,f:继续往上汇总,不需要重复往下指派

+ 1 - 0
src/Hotline.Application/Hotline.Application.csproj

@@ -7,6 +7,7 @@
   </PropertyGroup>
 
   <ItemGroup>
+    <PackageReference Include="JV.PanGu.Core" Version="1.0.1" />
     <PackageReference Include="NPOI" Version="2.7.0" />
     <PackageReference Include="XC.RSAUtil" Version="1.3.6" />
     <PackageReference Include="Quartz.Jobs" Version="3.8.0" />

+ 1 - 1
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -44,7 +44,7 @@ namespace Hotline.Application.Orders
 		//Task<PagedDto<WorkflowOrderDto>> GetToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken);
 		ISugarQueryable<Order> GetAboutToExpireAsync(AboutToExpireListDto dto);
         //Task<PagedDto<WorkflowOrderDto>> GetAboutToExpireNodeAsync(AboutToExpireListDto dto, CancellationToken cancellationToken);
-        Task OrderParticiple(string inputStr, string orderId, CancellationToken cancellationToken);
+        Task OrderParticiple(string inputStr, string orderId,DateTime time , CancellationToken cancellationToken);
         Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken);
         /// <summary>
         /// 接收外部平台工单

+ 37 - 21
src/Hotline.Application/Orders/OrderApplication.cs

@@ -36,6 +36,9 @@ using Hotline.Repository.SqlSugar.System;
 using Microsoft.AspNetCore.Mvc;
 using Hotline.Share.Dtos.Bi;
 using System.Net;
+using PanGu;
+using Hotline.Users;
+using PanGu.Match;
 
 namespace Hotline.Application.Orders;
 
@@ -288,29 +291,42 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// </summary>
     /// <param name="inputStr"></param>
     /// <returns></returns>
-    public async Task OrderParticiple(string inputStr, string orderId, CancellationToken cancellationToken)
+    public async Task OrderParticiple(string inputStr, string orderId,DateTime time, CancellationToken cancellationToken)
     {
-        var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("普通标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
-        var res = new List<string>();
-        if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
-        var participles = await _orderWrodRepository.Queryable().In(x => x.Tag, res).ToListAsync(cancellationToken);
-        if (participles.Any())
+        var seg = new Segment();
+		ICollection<WordInfo> splitWords = seg.DoSegment(inputStr);
+        var words = new List<string>();
+        for (int i = 0; i < splitWords.Count; i++)
         {
-            //关键词
-            var tags = participles.Select(x => x.Tag).ToList();
-            var tagsStr = string.Join(",", tags);
-            await _orderRepository.Updateable().SetColumns(x => x.TagNames == tagsStr).Where(x => x.Id == orderId).ExecuteCommandAsync(cancellationToken);
-            List<string> synonyms = participles.Select(x => x.Synonym).ToList();
-            if (synonyms.Any())
-            {
-                var synonymsStr = string.Join(",", synonyms);
-                synonyms = synonymsStr.Split(",").Distinct().ToList();
-                tags.AddRange(synonyms);
-            }
-            var vector = await _orderRepository.Queryable().Where(x => x.Id == orderId).ToListAsync(cancellationToken);
-            if (vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, tags, cancellationToken);
-            else await _repositoryts.AddVectorAsync(orderId, DateTime.Now, tags, cancellationToken);
-        }
+            var word = splitWords.ElementAt(i);
+            if (word is { WordType: WordType.SimplifiedChinese, Word.Length: > 1 } )
+	            words.Add(splitWords.ElementAt(i).Word);
+		}
+        var vector = await _repositoryts.SearchAsync(orderId, cancellationToken);
+        if (vector != null && vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, words, cancellationToken);
+        else await _repositoryts.AddVectorAsync(orderId, time, words, cancellationToken);
+
+        //var words = await _orderWrodRepository.Queryable().Where(x => x.IsEnable == 1 && x.Classify.Contains("普通标签")).Select(x => x.Tag).ToListAsync(cancellationToken);
+        //var res = new List<string>();
+        //if (words.Any()) res = ParticipleTool.SegMMDouble(inputStr, ref words);
+        //var participles = await _orderWrodRepository.Queryable().In(x => x.Tag, res).ToListAsync(cancellationToken);
+        //if (participles.Any())
+        //{
+        //    //关键词
+        //    var tags = participles.Select(x => x.Tag).ToList();
+        //    var tagsStr = string.Join(",", tags);
+        //    await _orderRepository.Updateable().SetColumns(x => x.TagNames == tagsStr).Where(x => x.Id == orderId).ExecuteCommandAsync(cancellationToken);
+        //    List<string> synonyms = participles.Select(x => x.Synonym).ToList();
+        //    if (synonyms.Any())
+        //    {
+        //        var synonymsStr = string.Join(",", synonyms);
+        //        synonyms = synonymsStr.Split(",").Distinct().ToList();
+        //        tags.AddRange(synonyms);
+        //    }
+        //    var vector = await _orderRepository.Queryable().Where(x => x.Id == orderId).ToListAsync(cancellationToken);
+        //    if (vector.Any()) await _repositoryts.UpdateVectorAsync(orderId, tags, cancellationToken);
+        //    else await _repositoryts.AddVectorAsync(orderId, DateTime.Now, tags, cancellationToken);
+        //}
     }
 
     public async Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken)

+ 139 - 102
src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs

@@ -260,51 +260,7 @@ namespace Hotline.Repository.SqlSugar.Orders
               })
                .ToPivotTableAsync(p => p.AreaName, p => p.Hour, p => p.Sum(x => x.count));
 
-            //修改列名
-            dt.Columns["Hour"].ColumnName = "时间段";
-            dt.Columns.Remove("Column1");
-
-            //增加小计
-            DataColumn totalColumn = new DataColumn("小计", typeof(decimal));
-            dt.Columns.Add(totalColumn);
-            for (int i = 0; i < dt.Rows.Count; i++)
-            {
-                int sumcount = 0;
-                for (int j = 1; j < dt.Columns.Count - 1; j++)
-                {
-                    sumcount += Convert.ToInt32(dt.Rows[i][j].ToString());
-                }
-                dt.Rows[i][dt.Columns.Count - 1] = sumcount;
-            }
-
-            //增加合计
-            DataRow totalRow = dt.NewRow();
-            totalRow["时间段"] = "合计";
-            for (int i = 1; i < dt.Columns.Count; i++)
-            {
-                int sumcount = 0;
-                for (int j = 0; j < dt.Rows.Count; j++)
-                {
-                    sumcount += Convert.ToInt32(dt.Rows[j][i].ToString());
-                }
-                totalRow[i] = sumcount;
-            }
-            dt.Rows.Add(totalRow);
-
-            //移除列
-            if (dto.AddColumnName.Any())
-            {
-                for (int i = 0; i < dt.Columns.Count; i++)
-                {
-                    var name = dt.Columns[i].ColumnName;
-                    if (!dto.AddColumnName.Contains(name))
-                    {
-                        dt.Columns.Remove(name);
-                        i = 0;
-                    }
-                }
-            }
-            return dt;
+            return InitDatatTable(dt, dto.AddColumnName);
         }
 
         /// <summary>
@@ -408,51 +364,7 @@ namespace Hotline.Repository.SqlSugar.Orders
               })
                .ToPivotTableAsync(p => p.HotSpotName, p => p.Hour, p => p.Sum(x => x.count));
 
-            //修改列名
-            dt.Columns["Hour"].ColumnName = "时间段";
-            dt.Columns.Remove("Column1");
-
-            //增加小计
-            DataColumn totalColumn = new DataColumn("小计", typeof(decimal));
-            dt.Columns.Add(totalColumn);
-            for (int i = 0; i < dt.Rows.Count; i++)
-            {
-                int sumcount = 0;
-                for (int j = 1; j < dt.Columns.Count - 1; j++)
-                {
-                    sumcount += Convert.ToInt32(dt.Rows[i][j].ToString());
-                }
-                dt.Rows[i][dt.Columns.Count - 1] = sumcount;
-            }
-
-            //增加合计
-            DataRow totalRow = dt.NewRow();
-            totalRow["时间段"] = "合计";
-            for (int i = 1; i < dt.Columns.Count; i++)
-            {
-                int sumcount = 0;
-                for (int j = 0; j < dt.Rows.Count; j++)
-                {
-                    sumcount += Convert.ToInt32(dt.Rows[j][i].ToString());
-                }
-                totalRow[i] = sumcount;
-            }
-            dt.Rows.Add(totalRow);
-
-            //移除列
-            if (dto.AddColumnName.Any())
-            {
-                for (int i = 0; i < dt.Columns.Count; i++)
-                {
-                    var name = dt.Columns[i].ColumnName;
-                    if (!dto.AddColumnName.Contains(name))
-                    {
-                        dt.Columns.Remove(name);
-                        i = 0;
-                    }
-                }
-            }
-            return dt;
+            return InitDatatTable(dt, dto.AddColumnName);
         }
 
         /// <summary>
@@ -481,7 +393,7 @@ namespace Hotline.Repository.SqlSugar.Orders
 
             var listOrg = Db.Queryable<SystemDicData>()
               .LeftJoin(listOrder, (s, p) => s.DicDataValue == p.AcceptTypeCode)
-              .Where((s, p) => s.DicTypeCode== "AcceptType")
+              .Where((s, p) => s.DicTypeCode == "AcceptType")
               .GroupBy((s, p) => s.DicDataValue).GroupBy((s, p) => s.DicDataName)
               .GroupBy((s, p) => p.Hour)
               .OrderBy((s, p) => s.DicDataValue)
@@ -556,12 +468,130 @@ namespace Hotline.Repository.SqlSugar.Orders
               })
                .ToPivotTableAsync(p => p.DicDataName, p => p.Hour, p => p.Sum(x => x.count));
 
+            return InitDatatTable(dt, dto.AddColumnName);
+        }
+
+        /// <summary>
+        /// 信件来源分时统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public async Task<object> OrderSourceTime(TimeSharingPagedKeywordRequest dto)
+        {
+            List<int> dts = new List<int>();
+            for (int i = 0; i < 24; i++)
+            {
+                dts.Add(i);
+            }
+
+            var listHour = Db.Reportable(dts).ToQueryable<int>();
+            var listOrder = Db.Queryable<Order>()
+                 .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime)
+                 .WhereIF(dto.IdentityType != null, p => p.IdentityType == dto.IdentityType)
+                 .Select(p => new
+                 {
+                     SourceChannelCode = p.SourceChannelCode,
+                     Hour = p.CreationTime.Hour.ToString()
+                 })
+               .MergeTable();
+
+            var listOrg = Db.Queryable<SystemDicData>()
+              .LeftJoin(listOrder, (s, p) => s.DicDataValue == p.SourceChannelCode)
+              .Where((s, p) => s.DicTypeCode == "SourceChannel")
+              .GroupBy((s, p) => s.DicDataValue).GroupBy((s, p) => s.DicDataName)
+              .GroupBy((s, p) => p.Hour)
+              .OrderBy((s, p) => s.DicDataValue)
+              .Select((s, p) => new
+              {
+                  count = SqlFunc.AggregateSum(SqlFunc.IIF(p.SourceChannelCode != null && p.SourceChannelCode != "", 1, 0)),
+                  DicDataValue = s.DicDataValue,
+                  Hour = SqlFunc.IIF(p.Hour == null || p.Hour == "", "0", p.Hour),
+                  DicDataName = s.DicDataName
+              })
+              .MergeTable();
+
+            var list = await listHour.LeftJoin(listOrg, (x, p) => x.ColumnName.ToString() == p.Hour)
+                .OrderBy(x => x.ColumnName)
+               .Select((x, p) => new
+               {
+                   Hour = x.ColumnName.ToString() + ":00 - " + x.ColumnName.ToString() + ":59",
+                   p.DicDataValue,
+                   p.count
+               })
+                .ToPivotListAsync(p => p.DicDataValue, p => p.Hour, p => p.Sum(x => x.count));
+            return list;
+
+        }
+
+        /// <summary>
+        /// 信件来源分时统计---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        public async Task<DataTable> OrderSourceTimeExport(TimeSharingPagedKeywordRequest dto)
+        {
+            List<int> dts = new();
+            for (int i = 0; i < 24; i++)
+            {
+                dts.Add(i);
+            }
+
+            var listHour = Db.Reportable(dts).ToQueryable<int>();
+            var listOrder = Db.Queryable<Order>()
+                 .Where(p => p.CreationTime >= dto.StartTime && p.CreationTime <= dto.EndTime)
+                 .WhereIF(dto.IdentityType != null, p => p.IdentityType == dto.IdentityType)
+                 .Select(p => new
+                 {
+                     SourceChannelCode = p.SourceChannelCode,
+                     Hour = p.CreationTime.Hour.ToString()
+                 })
+               .MergeTable();
+
+            var listOrg = Db.Queryable<SystemDicData>()
+              .LeftJoin(listOrder, (s, p) => s.DicDataValue == p.SourceChannelCode)
+              .Where((s, p) => s.DicTypeCode == "SourceChannel")
+              .GroupBy((s, p) => s.DicDataValue).GroupBy((s, p) => s.DicDataName)
+              .GroupBy((s, p) => p.Hour)
+              .OrderBy((s, p) => s.DicDataValue)
+              .Select((s, p) => new
+              {
+                  count = SqlFunc.AggregateSum(SqlFunc.IIF(p.SourceChannelCode != null && p.SourceChannelCode != "", 1, 0)),
+                  DicDataValue = s.DicDataValue,
+                  Hour = SqlFunc.IIF(p.Hour == null || p.Hour == "", "0", p.Hour),
+                  DicDataName = s.DicDataName
+              })
+              .MergeTable();
+
+            var dt = await listHour.LeftJoin(listOrg, (x, p) => x.ColumnName.ToString() == p.Hour)
+               .OrderBy(x => x.ColumnName)
+              .Select((x, p) => new
+              {
+                  Hour = x.ColumnName.ToString() + ":00 - " + x.ColumnName.ToString() + ":59",
+                  p.DicDataName,
+                  p.count
+              })
+               .ToPivotTableAsync(p => p.DicDataName, p => p.Hour, p => p.Sum(x => x.count));
+            return InitDatatTable(dt, dto.AddColumnName);
+        }
+
+        /// <summary>
+        /// 处理导出数据
+        /// </summary>
+        /// <param name="dt"></param>
+        /// <param name="AddColumnName"></param>
+        /// <returns></returns>
+        public DataTable InitDatatTable(DataTable dt, List<string> AddColumnName)
+        {
             //修改列名
-            dt.Columns["Hour"].ColumnName = "时间段";
+            if (dt.Columns.Contains("Hour"))
+                dt.Columns["Hour"].ColumnName = "时间段";
 
             //增加小计
             DataColumn totalColumn = new DataColumn("小计", typeof(decimal));
             dt.Columns.Add(totalColumn);
+            if (dt.Columns.Contains("Column1"))
+                dt.Columns.Remove("Column1");
+            //计算小计
             for (int i = 0; i < dt.Rows.Count; i++)
             {
                 int sumcount = 0;
@@ -586,20 +616,27 @@ namespace Hotline.Repository.SqlSugar.Orders
             }
             dt.Rows.Add(totalRow);
 
-            //移除列
-            if (dto.AddColumnName.Any())
+            //创建新表
+            DataTable dt2 = new DataTable();
+
+            //添加表头
+            foreach (var item in AddColumnName)
             {
-                for (int i = 0; i < dt.Columns.Count; i++)
+                if (dt.Columns.Contains(item))
+                    dt2.Columns.Add(item);
+            }
+
+            //处理数据
+            foreach (DataRow sourceRow in dt.Rows)
+            {
+                DataRow targetRow = dt2.NewRow();
+                foreach (var item in AddColumnName)
                 {
-                    var name = dt.Columns[i].ColumnName;
-                    if (!dto.AddColumnName.Contains(name))
-                    {
-                        dt.Columns.Remove(name);
-                        i = 0;
-                    }
+                    targetRow[item] = sourceRow[item];
                 }
+                dt2.Rows.Add(targetRow);
             }
-            return dt;
+            return dt2;
         }
 
         /// <summary>

+ 11 - 2
src/Hotline.Repository.SqlSugar/Ts/BaseRepositoryTextSearch.cs

@@ -84,9 +84,18 @@ FROM order_ts, to_tsquery('simple', 'bb') query WHERE "Vector" @@ query ORDER BY
          */
     }
 
-    #region private method
+    public async Task<List<TEntity>> SearchAsync(string id, CancellationToken cancellationToken)
+    {
+	    var tableName = typeof(TEntity).Name.ToSnakeCase();
+	    var sql =
+		    $"SELECT * FROM {tableName} WHERE \"id\" ='{id}' ";
+	    return await _db.Ado.SqlQueryAsync<TEntity>(sql, null, cancellationToken);
+
+    }
+
+	#region private method
 
-    private static string CreateVectorSql(ICollection<NpgsqlWeight> weights)
+	private static string CreateVectorSql(ICollection<NpgsqlWeight> weights)
     {
         var setweghtStrings = weights.Select(d => $"setweight(to_tsvector('simple', '{d.Text}'), '{d.Weight}')");
         var vectorString = string.Join(" || ", setweghtStrings);

+ 8 - 0
src/Hotline.Repository.SqlSugar/Ts/IRepositoryTextSearch.cs

@@ -28,4 +28,12 @@ public interface IRepositoryTextSearch<TEntity>
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
     Task<List<TEntity>> SearchAsync(IReadOnlyList<string> texts, CancellationToken cancellationToken);
+
+    /// <summary>
+    /// 根据id获取
+    /// </summary>
+    /// <param name="id"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    Task<List<TEntity>> SearchAsync(string id, CancellationToken cancellationToken);
 }

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

@@ -4,6 +4,11 @@ namespace Hotline.Share.Dtos.FlowEngine;
 
 public class NextStepsDto
 {
+    /// <summary>
+    /// 当前办理节点
+    /// </summary>
+    public string StepId { get; set; }
+
     // public IReadOnlyList<NextStepOption> Steps { get; set; }
     public DateTime? ExpiredTime { get; set; }
 

+ 5 - 0
src/Hotline.Share/Dtos/FlowEngine/NextWorkflowDto.cs

@@ -9,6 +9,11 @@ public class NextWorkflowDto : BasicWorkflowDto
 {
     public string WorkflowId { get; set; }
 
+    /// <summary>
+    /// 当前办理节点id
+    /// </summary>
+    public string StepId { get; set; }
+
     ///// <summary>
     ///// 下一节点到期时间(节点期满时间)
     ///// 需求调整

+ 27 - 2
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -355,9 +355,14 @@ namespace Hotline.Share.Dtos.Order
         public bool CanHandle { get; set; }
 
         /// <summary>
-        /// 延期申请数量
+        /// 是否可代办
         /// </summary>
-        public int DelayingCount => OrderDelays?.Count ?? 0;
+        public bool CanInsteadHandle { get; set; }
+
+		/// <summary>
+		/// 延期申请数量
+		/// </summary>
+		public int DelayingCount => OrderDelays?.Count ?? 0;
 
         /// <summary>
         /// 是否紧急
@@ -812,6 +817,26 @@ namespace Hotline.Share.Dtos.Order
         /// 是否紧急
         /// </summary>
         public bool IsUrgent { get; set; }
+
+        /// <summary>
+        /// 是否政民互动公开
+        /// </summary>
+        public bool IsProvinceZmhd { get; set; }
+
+        /// <summary>
+        /// 初审人姓名
+        /// </summary>
+        public string? AuditFirstName { get; set; }
+
+        /// <summary>
+        /// 初审时间
+        /// </summary>
+        public DateTime? AuditFirstTime { get; set; }
+
+        /// <summary>
+        /// 政民互动公开ID
+        /// </summary>
+        public string? OrderProvinceZmhdId { get; set; }
     }
 
     public record CanLinkCallRecordOrderDto : PagedKeywordRequest

+ 135 - 0
src/Hotline.Share/Dtos/Order/OrderProvinceZmhdDto.cs

@@ -0,0 +1,135 @@
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.Order
+{
+    /// <summary>
+    /// 政民互动查询
+    /// </summary>
+    public record OrderProvinceZmhdDto : PagedRequest
+    {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string? No { get; set; }
+
+        /// <summary>
+        /// 省工单编号
+        /// </summary>
+        public string? ProvinceNo { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string? Title { get; set; }
+
+        /// <summary>
+        /// 答复部门名称
+        /// </summary>
+        public string? AnswerOu { get; set; }
+
+        /// <summary>
+        /// 初审人姓名
+        /// </summary>
+        public string? AuditFirstName { get; set; }
+
+        /// <summary>
+        /// 审核开始时间
+        /// </summary>
+        public DateTime? StartTime { get; set; }
+        /// <summary>
+        /// 审核结束时间
+        /// </summary>
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 是否政民互动公开
+        /// </summary>
+        public bool? IsProvinceZmhd { get; set; }
+    }
+
+    public class AddOrderProvinceZmhdDto
+    {
+        /// <summary>
+        /// 工单Id
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 整理结果
+        /// </summary>
+        public string AnswerContent { get; set; }
+
+        /// <summary>
+        /// 公开意见(长度300)
+        /// </summary>
+        public string? PublicOpinion { get; set; }
+    }
+
+    public class PublicOrderProvinceZmhdDto
+    {
+        /// <summary>
+        /// Id
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 省工单编号
+        /// </summary>
+        public string ProvinceNo { get; set; }
+
+        /// <summary>
+        /// 工单Id
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 部门答复时间
+        /// </summary>
+        public DateTime? AnswerTime { get; set; }
+
+        /// <summary>
+        /// 答复部门名称
+        /// </summary>
+        public string AnswerOu { get; set; }
+
+        /// <summary>
+        /// 答复内容
+        /// </summary>
+        public string AnswerContent { get; set; }
+
+        /// <summary>
+        /// 初审人姓名
+        /// </summary>
+        public string? AuditFirstName { get; set; }
+
+        /// <summary>
+        /// 初审时间
+        /// </summary>
+        public DateTime? AuditFirstTime { get; set; }
+
+        /// <summary>
+        /// 二审人姓名
+        /// </summary>
+        public string? AuditSecondName { get; set; }
+
+        /// <summary>
+        /// 公开时间
+        /// </summary>
+        public DateTime? PublishDate { get; set; }
+
+        /// <summary>
+        /// 公开意见
+        /// </summary>
+        public string? PublicOpinion { get; set; }
+    }
+}

+ 1 - 1
src/Hotline.Share/Hotline.Share.csproj

@@ -7,7 +7,7 @@
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
     <NoWarn>$(NoWarn);1591;8618;</NoWarn>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-    <Version>1.0.79</Version>
+    <Version>1.0.80</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 7 - 2
src/Hotline.Share/Mq/EventNames.Order.cs

@@ -95,6 +95,11 @@ namespace Hotline.Share.Mq
         /// </summary>
         public const string HotlineOrderTranspondCity = "hotline.order.transpond.city";
 
-		#endregion
-	}
+        /// <summary>
+        /// 政民互动公开
+        /// </summary>
+        public const string HotlineOrderProvinceZmhd = "hotline.order.province.zmhd";
+
+        #endregion
+    }
 }

+ 6 - 0
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -262,5 +262,11 @@ namespace Hotline.FlowEngine.Workflows
         /// 流程被签收至某个用户(更新流转对象,办理对象,节点办理对象以及stepHandlers)
         /// </summary>
         Task<Workflow> SignToSomebodyAsync(string workflowId, string userId, string username, string orgId, string orgName, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 非节点办理人员查询待办节点
+        /// </summary>
+        /// <returns></returns>
+        Task<ICollection<WorkflowStep>> GetUnhandleStepsByOthersAsync(string workflowId, CancellationToken cancellationToken);
     }
 }

+ 11 - 0
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -946,6 +946,17 @@ namespace Hotline.FlowEngine.Workflows
             return workflow;
         }
 
+        /// <summary>
+        /// 非节点办理人员查询待办节点
+        /// </summary>
+        /// <returns></returns>
+        public async Task<ICollection<WorkflowStep>> GetUnhandleStepsByOthersAsync(string workflowId, CancellationToken cancellationToken)
+        {
+            return await _workflowStepRepository.Queryable()
+                .Where(d => d.WorkflowId == workflowId && d.Status != EWorkflowStepStatus.Handled)
+                .ToListAsync(cancellationToken);
+        }
+
         /// <summary>
         /// 查找当前会签内所有节点(含start,end)
         /// </summary>

+ 14 - 0
src/Hotline/Orders/IOrderRepository.cs

@@ -68,6 +68,20 @@ namespace Hotline.Orders
         /// <returns></returns>
         Task<DataTable> OrderAcceptanceTimeExport(TimeSharingPagedKeywordRequest dto);
 
+        /// <summary>
+        /// 信件来源分时统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<object> OrderSourceTime(TimeSharingPagedKeywordRequest dto);
+
+        /// <summary>
+        /// 信件来源分时统计---导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<DataTable> OrderSourceTimeExport(TimeSharingPagedKeywordRequest dto);
+
         /// <summary>
         /// 满意度明细
         /// </summary>

+ 40 - 6
src/Hotline/Orders/Order.cs

@@ -689,7 +689,7 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDataType = "varchar(8000)")]
         public string? FileOpinion { get; set; }
 
-        
+
 
         #endregion
 
@@ -800,6 +800,30 @@ namespace Hotline.Orders
         /// 待发布人Id
         /// </summary>
         public string? WaitForPublisherId { get; set; }
+
+        /// <summary>
+        /// 是否政民互动公开
+        /// </summary>
+        [SugarColumn(DefaultValue = "f")]
+        public bool IsProvinceZmhd { get; set; }
+
+        /// <summary>
+        /// 初审人姓名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "初审人姓名")]
+        public string? AuditFirstName { get; set; }
+
+        /// <summary>
+        /// 初审时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "初审时间")]
+        public DateTime? AuditFirstTime { get; set; }
+
+        /// <summary>
+        /// 政民互动公开ID
+        /// </summary>
+        [SugarColumn(ColumnDescription = "政民互动公开ID")]
+        public string? OrderProvinceZmhdId { get; set; }
     }
 
     public partial class Order
@@ -1039,8 +1063,14 @@ namespace Hotline.Orders
         /// </summary>
         public void SetCreationTimeHandleDurationWorkday()
         {
-            if (!ActualHandleTime.HasValue) return;
-            FileDuration = Math.Round((ActualHandleTime - CreationTime).Value.TotalSeconds);
+            if (!ActualHandleTime.HasValue)
+                CreationTimeHandleDuration = 0;
+            else
+            {
+                var count = Math.Round((ActualHandleTime - CreationTime).Value.TotalSeconds);
+                CreationTimeHandleDuration = count <= 0 ? 1 : count;
+            }
+
         }
 
         /// <summary>
@@ -1048,9 +1078,13 @@ namespace Hotline.Orders
         /// </summary>
         public void SetCenterToOrgHandleDurationWorkday()
         {
-            if (!ActualHandleTime.HasValue) return;
-            if (!CenterToOrgTime.HasValue) return;
-            FileDuration = Math.Round((ActualHandleTime - CenterToOrgTime).Value.TotalSeconds);
+            if (ActualHandleTime.HasValue && CenterToOrgTime.HasValue)
+            {
+                var count = Math.Round((ActualHandleTime - CenterToOrgTime).Value.TotalSeconds);
+                CenterToOrgHandleDuration = count <= 0 ? 1 : count;
+            }
+            else
+                CenterToOrgHandleDuration = 0;
         }
 
         /// <summary>

+ 72 - 6
src/Hotline/Orders/OrderProvinceZmhd.cs

@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using SqlSugar;
 using XF.Domain.Repository;
 
 namespace Hotline.Orders
@@ -10,8 +6,78 @@ namespace Hotline.Orders
     /// <summary>
     /// 政民互动公开
     /// </summary>
-    public  class OrderProvinceZmhd: CreationEntity
+    public class OrderProvinceZmhd : CreationEntity
     {
+        /// <summary>
+        /// 工单编号
+        /// </summary>
+        [SugarColumn( ColumnDescription = "工单编号")]
+        public string No { get; set; }
 
+        /// <summary>
+        /// 省工单编号
+        /// </summary>
+        [SugarColumn(ColumnDescription = "省工单编号")]
+        public string ProvinceNo { get; set; }
+
+        /// <summary>
+        /// 工单Id
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单Id")]
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 工单标题
+        /// </summary>
+        [SugarColumn(ColumnDescription = "工单标题")]
+        public string Title { get; set; }
+
+        /// <summary>
+        /// 部门答复时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "部门答复时间")]
+        public DateTime? AnswerTime { get; set; }
+
+        /// <summary>
+        /// 答复部门名称
+        /// </summary>
+        [SugarColumn(ColumnDescription = "答复部门名称")]
+        public string AnswerOu { get; set; }
+
+        /// <summary>
+        /// 答复内容
+        /// </summary>
+        [SugarColumn(ColumnDataType = "text", ColumnDescription = "答复内容")]
+        public string AnswerContent { get; set; }
+
+        /// <summary>
+        /// 初审人姓名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "初审人姓名")]
+        public string? AuditFirstName { get; set; }
+
+        /// <summary>
+        /// 初审时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "初审时间")]
+        public DateTime? AuditFirstTime { get; set; }
+
+        /// <summary>
+        /// 二审人姓名
+        /// </summary>
+        [SugarColumn(ColumnDescription = "二审人姓名")]
+        public string? AuditSecondName { get; set; }
+
+        /// <summary>
+        /// 公开时间
+        /// </summary>
+        [SugarColumn(ColumnDescription = "公开时间")]
+        public DateTime? PublishDate { get; set; }
+
+        /// <summary>
+        /// 公开意见
+        /// </summary>
+        [SugarColumn(Length = 300, ColumnDescription = "公开意见")]
+        public string? PublicOpinion { get; set; }
     }
 }

+ 6 - 1
src/Hotline/Settings/SettingConstants.cs

@@ -354,5 +354,10 @@ namespace Hotline.Settings
         /// 是否开启重复工单
         /// </summary>
         public const string IsOpenRepeatedWorkOrders = "IsOpenRepeatedWorkOrders";
-    }
+
+        /// <summary>
+        /// 班长代办
+        /// </summary>
+        public const string ChargeDAffaires = "ChargeDAffaires";
+	}
 }