Эх сурвалжийг харах

Merge branch 'master' into bugfix_timelimit

Dun.Jason 11 сар өмнө
parent
commit
bb87d74525
62 өөрчлөгдсөн 2545 нэмэгдсэн , 728 устгасан
  1. 14 2
      src/Hotline.Api/Controllers/BaseController.cs
  2. 54 47
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  3. 96 1
      src/Hotline.Api/Controllers/IPPbxController.cs
  4. 1 1
      src/Hotline.Api/Controllers/KnowledgeCommonController.cs
  5. 7 7
      src/Hotline.Api/Controllers/KnowledgeController.cs
  6. 463 327
      src/Hotline.Api/Controllers/OrderController.cs
  7. 15 0
      src/Hotline.Api/Controllers/OrgController.cs
  8. 150 5
      src/Hotline.Api/Controllers/TestController.cs
  9. 1 1
      src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs
  10. 24 1
      src/Hotline.Application/CallCenter/Calls/TelsStatusRefreshService.cs
  11. 2 2
      src/Hotline.Application/FlowEngine/IWorkflowApplication.cs
  12. 7 6
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  13. 1 1
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  14. 58 58
      src/Hotline.Application/Handlers/Order/DelayProvinceResultNotifyHandler.cs
  15. 39 39
      src/Hotline.Application/Handlers/Order/OrderResultNotifyHandler.cs
  16. 59 60
      src/Hotline.Application/Handlers/Order/ScreenProvinceResultNotifyHandler.cs
  17. 14 13
      src/Hotline.Application/Identity/IdentityAppService.cs
  18. 3 0
      src/Hotline.Application/JudicialManagement/EnforcementApplication.cs
  19. 1 0
      src/Hotline.Application/Mappers/IdentityMapperConfigs.cs
  20. 7 0
      src/Hotline.Application/Orders/IOrderApplication.cs
  21. 22 0
      src/Hotline.Application/Orders/IOrderSecondaryHandlingApplication.cs
  22. 74 23
      src/Hotline.Application/Orders/OrderApplication.cs
  23. 291 0
      src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs
  24. 80 28
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  25. 36 1
      src/Hotline.Application/Tels/TelApplication.cs
  26. 1 1
      src/Hotline.Repository.SqlSugar/Orders/OrderRepository.cs
  27. 12 0
      src/Hotline.Repository.SqlSugar/System/SystemOrganizeRepository.cs
  28. 1 1
      src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/CancelOrderDto.cs
  29. 5 0
      src/Hotline.Share/Dtos/FlowEngine/Workflow/WorkflowDto.cs
  30. 44 0
      src/Hotline.Share/Dtos/Order/ExportExcelDto.cs
  31. 26 22
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  32. 12 1
      src/Hotline.Share/Dtos/Order/OrderScreenDto.cs
  33. 201 0
      src/Hotline.Share/Dtos/Order/OrderSecondaryHandlingDto.cs
  34. 5 0
      src/Hotline.Share/Dtos/Order/OrderSpecialDto.cs
  35. 2 0
      src/Hotline.Share/Dtos/Order/OrderVisitDto.cs
  36. 4 0
      src/Hotline.Share/Dtos/Order/SendBackDto.cs
  37. 65 0
      src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs
  38. 13 0
      src/Hotline.Share/Dtos/Users/UserDto.cs
  39. 14 0
      src/Hotline.Share/Enums/CallCenter/EActionType.cs
  40. 6 0
      src/Hotline.Share/Enums/FlowEngine/EWorkflowStepStatus.cs
  41. 43 0
      src/Hotline.Share/Enums/Order/ESecondaryHandlingState.cs
  42. 1 1
      src/Hotline.Share/Hotline.Share.csproj
  43. 2 2
      src/Hotline.Share/Requests/DepartmentalProcessingStatisticsDto.cs
  44. 71 0
      src/Hotline/CallCenter/Calls/TelActionRecord.cs
  45. 7 1
      src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs
  46. 18 1
      src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs
  47. 38 19
      src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs
  48. 35 36
      src/Hotline/FlowEngine/Workflows/WorkflowStep.cs
  49. 1 1
      src/Hotline/FlowEngine/Workflows/WorkflowStepHandler.cs
  50. 1 1
      src/Hotline/KnowledgeBase/KnowledgeDomainService.cs
  51. 7 0
      src/Hotline/Orders/IOrderDomainService.cs
  52. 6 2
      src/Hotline/Orders/OrderDefaults.cs
  53. 99 8
      src/Hotline/Orders/OrderDomainService.cs
  54. 8 1
      src/Hotline/Orders/OrderScreen.cs
  55. 118 0
      src/Hotline/Orders/OrderSecondaryHandling.cs
  56. 8 2
      src/Hotline/Orders/OrderVisitDetail.cs
  57. 40 4
      src/Hotline/README.md
  58. 5 1
      src/Hotline/Settings/ISystemOrganizeRepository.cs
  59. 54 0
      src/Hotline/Tools/DynamicClassHelper.cs
  60. 21 0
      src/Hotline/Tools/ExcelHelper.cs
  61. 4 0
      src/Hotline/Users/User.cs
  62. 28 0
      src/XF.Domain/Extensions/StringExtensions.cs

+ 14 - 2
src/Hotline.Api/Controllers/BaseController.cs

@@ -1,6 +1,7 @@
 using Hotline.Api.Filter;
 using Microsoft.AspNetCore.Mvc;
 using MiniExcelLibs;
+using System.IO;
 
 namespace Hotline.Api.Controllers;
 
@@ -10,12 +11,23 @@ namespace Hotline.Api.Controllers;
 [LogFilter]
 public class BaseController : ControllerBase
 {
-    
+    protected FileStreamResult ExcelStreamResult(Stream stream, string fileName = null)
+    {
+        var tail = DateTime.Now.ToString("yyyyMMddhhmmss") + ".xlsx";
+        fileName = string.IsNullOrEmpty(fileName)
+            ? tail
+            : $"{fileName}_{tail}";
+        HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition");
+        return new FileStreamResult(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
+        {
+            FileDownloadName = fileName
+        };
+    }
 }
 
 [ApiController]
 [Route("api/v1/[controller]")]
 public class OriginController : ControllerBase
 {
-    
+
 }

+ 54 - 47
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -19,6 +19,7 @@ using Hotline.Share.Enums.Order;
 using Hotline.Share.Requests;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
+using NPOI.SS.Formula.Functions;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Constants;
@@ -1550,16 +1551,16 @@ namespace Hotline.Api.Controllers.Bi
                          .Select(it => new DepartmentalProcessingStatisticsDataDto
                          {
                              OrgCode = it.OrgCode,
-                             OrderCountNum = SqlFunc.AggregateCount(it.OrgCode),//总量
-                             YBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已办
-                             ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed, 1, 0)),//在办
+                             // OrderCountNum = SqlFunc.AggregateCount(it.OrgCode),//总量
+                             YBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已办// SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已办
+                             ZBOrderCountNum = 0, //ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed, 1, 0)),//在办
                              Archived = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已归档
                              ToBeArchived = 0,
                              WaitPublished = 0,
                              PublishedOpen = 0,
                              PublishedNoOpen = 0,
                              YBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ActualHandleTime > it.ExpiredTime, 1, 0)),//已办超期
-                             ZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed && it.ExpiredTime < SqlFunc.GetDate(), 1, 0)),//待办超期
+                             ZBOverdue = 0,// SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed && it.ExpiredTime < SqlFunc.GetDate(), 1, 0)),//待办超期
                              CompleteOnTime = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ActualHandleTime <= it.ExpiredTime, 1, 0)),//按时办结
                              HQYBOverdue = 0,
                              HQZBOverdue = 0,
@@ -1594,7 +1595,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(it => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = it.OrgCode,
-                    OrderCountNum = 0,//总量
+                    //  OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -1624,13 +1625,14 @@ namespace Hotline.Api.Controllers.Bi
             //会签(已办超期、待办超期)
             var queryCountersign = _workflowStepHandleRepository.Queryable()
              .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
-             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CountersignPosition == ECountersignPosition.Multi && o.CountersignPosition == ECountersignPosition.Single && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
+             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
              .Select((x, o) => new
              {
                  OrgCode = IsCenter == true ? x.OrgId.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) : x.OrgId.Substring(0, _sessionContext.RequiredOrgId.Length + 3),// d.OrgId,
                  HandleTime = o.HandleTime,
                  StepExpiredTime = o.StepExpiredTime,
-                 Status = o.Status
+                 Status = o.Status,
+                 CountersignPosition = o.CountersignPosition
              })
               .MergeTable()
               .WhereIF(IsCenter == false, it => it.OrgCode.StartsWith(_sessionContext.RequiredOrgId))
@@ -1638,21 +1640,21 @@ namespace Hotline.Api.Controllers.Bi
              .Select(d => new DepartmentalProcessingStatisticsDataDto
              {
                  OrgCode = d.OrgCode,
-                 OrderCountNum = 0,//总量
+                 //OrderCountNum = 0,//总量
                  YBOrderCountNum = 0,//已办
-                 ZBOrderCountNum = 0,//在办
+                 ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EWorkflowStepStatus.Handled, 1, 0)),// 0,//在办
                  Archived = 0,
                  ToBeArchived = 0,
                  WaitPublished = 0,
                  PublishedOpen = 0,
                  PublishedNoOpen = 0,
                  YBOverdue = 0,
-                 ZBOverdue = 0,
+                 ZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),// 0,
                  CompleteOnTime = 0,
-                 HQYBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status == EWorkflowStepStatus.Handled && d.HandleTime > d.StepExpiredTime, 1, 0)),
-                 HQZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status != EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),
-                 DelayEnd = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status == EWorkflowStepStatus.Handled, 1, 0)),
-                 DelayWait = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status != EWorkflowStepStatus.Handled, 1, 0)),
+                 HQYBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status >= EWorkflowStepStatus.Handled && d.HandleTime > d.StepExpiredTime, 1, 0)),
+                 HQZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status < EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),
+                 DelayEnd = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status >= EWorkflowStepStatus.Handled, 1, 0)),
+                 DelayWait = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status <= EWorkflowStepStatus.Handled, 1, 0)),
                  OrderDelayCount = 0,
                  ScreenCount = 0,
                  ScreenApproval = 0,
@@ -1679,7 +1681,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(x => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = x.OrgCode,
-                    OrderCountNum = 0,//总量
+                    //  OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -1722,7 +1724,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(x => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = x.OrgCode,
-                    OrderCountNum = 0,//总量
+                    // OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -1763,7 +1765,7 @@ namespace Hotline.Api.Controllers.Bi
             .Select(x => new DepartmentalProcessingStatisticsDataDto
             {
                 OrgCode = x.OrgCode,
-                OrderCountNum = 0,//总量
+                //  OrderCountNum = 0,//总量
                 YBOrderCountNum = 0,//已办
                 ZBOrderCountNum = 0,//在办
                 Archived = 0,
@@ -1797,7 +1799,7 @@ namespace Hotline.Api.Controllers.Bi
                     OrgCode = p.OrgCode,
                     OrgName = o.Name,
                     OrgType = o.OrgType,
-                    OrderCountNum = p.OrderCountNum,
+                    //OrderCountNum = p.OrderCountNum,
                     YBOrderCountNum = p.YBOrderCountNum,
                     ZBOrderCountNum = p.ZBOrderCountNum,
                     Archived = p.Archived,
@@ -1829,7 +1831,7 @@ namespace Hotline.Api.Controllers.Bi
                 OrgCode = "",
                 OrgName = "合计",
                 OrgType = EOrgType.City,
-                OrderCountNum = items.Sum(p => p.OrderCountNum),
+                // OrderCountNum = items.Sum(p => p.OrderCountNum),
                 YBOrderCountNum = items.Sum(p => p.YBOrderCountNum),
                 ZBOrderCountNum = items.Sum(p => p.ZBOrderCountNum),
                 Archived = items.Sum(p => p.Archived),
@@ -1892,16 +1894,16 @@ namespace Hotline.Api.Controllers.Bi
                       .Select(it => new DepartmentalProcessingStatisticsDataDto
                       {
                           OrgCode = it.OrgCode,
-                          OrderCountNum = SqlFunc.AggregateCount(it.OrgCode),//总量
+                          //  OrderCountNum = SqlFunc.AggregateCount(it.OrgCode),//总量
                           YBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已办
-                          ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed, 1, 0)),//在办
+                          ZBOrderCountNum = 0,//  ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed, 1, 0)),//在办
                           Archived = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed, 1, 0)),//已归档
                           ToBeArchived = 0,
                           WaitPublished = 0,
                           PublishedOpen = 0,
                           PublishedNoOpen = 0,
                           YBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ActualHandleTime > it.ExpiredTime, 1, 0)),//已办超期
-                          ZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed && it.ExpiredTime < SqlFunc.GetDate(), 1, 0)),//待办超期
+                          ZBOverdue = 0,// SqlFunc.AggregateSum(SqlFunc.IIF(it.Status < EOrderStatus.Filed && it.ExpiredTime < SqlFunc.GetDate(), 1, 0)),//待办超期
                           CompleteOnTime = SqlFunc.AggregateSum(SqlFunc.IIF(it.Status >= EOrderStatus.Filed && it.ActualHandleTime <= it.ExpiredTime, 1, 0)),//按时办结
                           HQYBOverdue = 0,
                           HQZBOverdue = 0,
@@ -1937,7 +1939,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(it => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = it.OrgCode,
-                    OrderCountNum = 0,//总量
+                    // OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -1967,36 +1969,37 @@ namespace Hotline.Api.Controllers.Bi
             //会签(已办超期、待办超期)
             var queryCountersign = _workflowStepHandleRepository.Queryable()
              .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
-             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CountersignPosition == ECountersignPosition.Multi && o.CountersignPosition == ECountersignPosition.Single && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
+             .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CreationTime >= StartDate && o.CreationTime <= EndDate)
              .WhereIF(OrgCode == "001", (x, o) => x.OrgId == OrgCode)
              .WhereIF(OrgCode != "001", (x, o) => x.OrgId.StartsWith(OrgCode))
              .Select((x, o) => new
              {
                  OrgCode = x.OrgId.Substring(0, OrgCode.Length + 3),
-                 HandleTime = o.HandleTime,
-                 StepExpiredTime = o.StepExpiredTime,
-                 Status = o.Status
+                 o.HandleTime,
+                 o.StepExpiredTime,
+                 o.Status,
+                 o.CountersignPosition,
              })
               .MergeTable()
              .GroupBy(d => new { d.OrgCode })
              .Select(d => new DepartmentalProcessingStatisticsDataDto
              {
                  OrgCode = d.OrgCode,
-                 OrderCountNum = 0,//总量
+                 // OrderCountNum = 0,//总量
                  YBOrderCountNum = 0,//已办
-                 ZBOrderCountNum = 0,//在办
+                 ZBOrderCountNum = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EWorkflowStepStatus.Handled, 1, 0)),// 0,//在办
                  Archived = 0,
                  ToBeArchived = 0,
                  WaitPublished = 0,
                  PublishedOpen = 0,
                  PublishedNoOpen = 0,
                  YBOverdue = 0,
-                 ZBOverdue = 0,
+                 ZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status < EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),// 0, 
                  CompleteOnTime = 0,
-                 HQYBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status == EWorkflowStepStatus.Handled && d.HandleTime > d.StepExpiredTime, 1, 0)),
-                 HQZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status != EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),
-                 DelayEnd = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status == EWorkflowStepStatus.Handled, 1, 0)),
-                 DelayWait = SqlFunc.AggregateSum(SqlFunc.IIF(d.Status != EWorkflowStepStatus.Handled, 1, 0)),
+                 HQYBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status >= EWorkflowStepStatus.Handled && d.HandleTime > d.StepExpiredTime, 1, 0)),
+                 HQZBOverdue = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status < EWorkflowStepStatus.Handled && DateTime.Now >= d.StepExpiredTime, 1, 0)),
+                 DelayEnd = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status >= EWorkflowStepStatus.Handled, 1, 0)),
+                 DelayWait = SqlFunc.AggregateSum(SqlFunc.IIF(d.CountersignPosition > ECountersignPosition.None && d.Status < EWorkflowStepStatus.Handled, 1, 0)),
                  OrderDelayCount = 0,
                  ScreenCount = 0,
                  ScreenApproval = 0,
@@ -2024,7 +2027,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(x => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = x.OrgCode,
-                    OrderCountNum = 0,//总量
+                    //  OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -2055,7 +2058,7 @@ namespace Hotline.Api.Controllers.Bi
             var orderScreen = _orderScreenRepository.Queryable()
                 .Where(x => x.CreationTime >= StartDate && x.CreationTime <= EndDate)
                 .WhereIF(!string.IsNullOrEmpty(OrgName), x => x.CreatorOrgId.Contains(OrgName))
-                  .WhereIF(OrgCode == "001", x => x.CreatorOrgId == OrgCode)
+                .WhereIF(OrgCode == "001", x => x.CreatorOrgId == OrgCode)
                 .WhereIF(OrgCode != "001", x => x.CreatorOrgId.StartsWith(OrgCode))
                 .Select(x => new
                 {
@@ -2068,7 +2071,7 @@ namespace Hotline.Api.Controllers.Bi
                 .Select(x => new DepartmentalProcessingStatisticsDataDto
                 {
                     OrgCode = x.OrgCode,
-                    OrderCountNum = 0,//总量
+                    //  OrderCountNum = 0,//总量
                     YBOrderCountNum = 0,//已办
                     ZBOrderCountNum = 0,//在办
                     Archived = 0,
@@ -2110,7 +2113,7 @@ namespace Hotline.Api.Controllers.Bi
             .Select(x => new DepartmentalProcessingStatisticsDataDto
             {
                 OrgCode = x.OrgCode,
-                OrderCountNum = 0,//总量
+                // OrderCountNum = 0,//总量
                 YBOrderCountNum = 0,//已办
                 ZBOrderCountNum = 0,//在办
                 Archived = 0,
@@ -2144,7 +2147,7 @@ namespace Hotline.Api.Controllers.Bi
                     OrgCode = p.OrgCode,
                     OrgName = o.Name,
                     OrgType = o.OrgType,
-                    OrderCountNum = p.OrderCountNum,
+                    //OrderCountNum = p.OrderCountNum,
                     YBOrderCountNum = p.YBOrderCountNum,
                     ZBOrderCountNum = p.ZBOrderCountNum,
                     Archived = p.Archived,
@@ -2177,7 +2180,7 @@ namespace Hotline.Api.Controllers.Bi
                 OrgCode = "",
                 OrgName = "合计",
                 OrgType = EOrgType.City,
-                OrderCountNum = items.Sum(p => p.OrderCountNum),
+                // OrderCountNum = items.Sum(p => p.OrderCountNum),
                 YBOrderCountNum = items.Sum(p => p.YBOrderCountNum),
                 ZBOrderCountNum = items.Sum(p => p.ZBOrderCountNum),
                 Archived = items.Sum(p => p.Archived),
@@ -2219,11 +2222,9 @@ namespace Hotline.Api.Controllers.Bi
             switch (dto.StatisticsType)
             {
                 case EStatisticsType.YBOrderCountNum:
-                case EStatisticsType.ZBOrderCountNum:
                 case EStatisticsType.ToBeArchived:
                 case EStatisticsType.Archived:
                 case EStatisticsType.YBOverdue:
-                case EStatisticsType.ZBOverdue:
                     //工单
                     stye = "1";
                     break;
@@ -2252,6 +2253,8 @@ namespace Hotline.Api.Controllers.Bi
                 case EStatisticsType.HQZBOverdue:
                 case EStatisticsType.DelayEnd:
                 case EStatisticsType.DelayWait:
+                case EStatisticsType.ZBOrderCountNum:
+                case EStatisticsType.ZBOverdue:
                     //会签
                     stye = "5";
                     break;
@@ -2367,13 +2370,17 @@ namespace Hotline.Api.Controllers.Bi
                 var queryCountersign = await _workflowStepHandleRepository.Queryable()
                .LeftJoin<WorkflowTrace>((x, o) => x.WorkflowStepId == o.StepId)
                .LeftJoin<Order>((x, o, p) => o.WorkflowId == p.WorkflowId)
-               .Where((x, o, p) => o.ModuleCode == WorkflowModuleConsts.OrderHandle && o.CountersignPosition == ECountersignPosition.Multi && o.CountersignPosition == ECountersignPosition.Single && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
+                .Where((x, o) => o.ModuleCode == WorkflowModuleConsts.OrderHandle
+             && o.CreationTime >= dto.StartDate && o.CreationTime <= dto.EndDate)
                .WhereIF(dto.OrgCode == "001", (x, o, p) => x.OrgId == dto.OrgCode)
                .WhereIF(dto.OrgCode != "001", (x, o, p) => x.OrgId.StartsWith(dto.OrgCode))
-               .WhereIF(dto.StatisticsType == EStatisticsType.HQYBOverdue, (x, o, p) => o.Status == EWorkflowStepStatus.Handled && o.HandleTime > o.StepExpiredTime)//会签已办超期
-               .WhereIF(dto.StatisticsType == EStatisticsType.HQZBOverdue, (x, o, p) => o.Status != EWorkflowStepStatus.Handled && DateTime.Now >= o.StepExpiredTime)//会签待办超期
-               .WhereIF(dto.StatisticsType == EStatisticsType.DelayEnd, (x, o, p) => o.Status == EWorkflowStepStatus.Handled)//会签已办
-               .WhereIF(dto.StatisticsType == EStatisticsType.DelayWait, (x, o, p) => o.Status != EWorkflowStepStatus.Handled)//会签待办
+               .WhereIF(dto.StatisticsType == EStatisticsType.HQYBOverdue, (x, o, p) => o.Status >= EWorkflowStepStatus.Handled && o.HandleTime > o.StepExpiredTime && o.CountersignPosition > ECountersignPosition.None)//会签已办超期
+               .WhereIF(dto.StatisticsType == EStatisticsType.HQZBOverdue, (x, o, p) => o.Status < EWorkflowStepStatus.Handled && DateTime.Now >= o.StepExpiredTime && o.CountersignPosition > ECountersignPosition.None)//会签待办超期
+               .WhereIF(dto.StatisticsType == EStatisticsType.DelayEnd, (x, o, p) => o.Status >= EWorkflowStepStatus.Handled && o.CountersignPosition > ECountersignPosition.None)//会签已办
+               .WhereIF(dto.StatisticsType == EStatisticsType.DelayWait, (x, o, p) => o.Status < EWorkflowStepStatus.Handled && o.CountersignPosition > ECountersignPosition.None)//会签待办
+               .WhereIF(dto.StatisticsType == EStatisticsType.ZBOrderCountNum, (x, o, p) => o.Status < EWorkflowStepStatus.Handled)//在办总量
+                .WhereIF(dto.StatisticsType == EStatisticsType.ZBOverdue, (x, o, p) => o.Status < EWorkflowStepStatus.Handled && DateTime.Now >= o.StepExpiredTime)//在办超期
+
                .OrderByDescending((x, o, p) => p.CreationTime)
                 .Select((x, o, p) => new { p })
                 .ToPageListAsync(dto.PageIndex, dto.PageSize, total, HttpContext.RequestAborted);

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

@@ -30,6 +30,7 @@ using XF.Domain.Exceptions;
 using XF.Domain.Filters;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
+using static Grpc.Core.ChannelOption;
 
 namespace Hotline.Api.Controllers
 {
@@ -55,6 +56,7 @@ namespace Hotline.Api.Controllers
         private readonly IAiQualityService _aiQualityService;
         private readonly IRepository<QualityTemplate> _qualityTemplate;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+        private readonly IRepository<TelActionRecord> _telActionRecordRepository;
 
 
         public IPPbxController(ITrClient trClient, IMapper mapper, IUserDomainService userDomainService,
@@ -65,7 +67,8 @@ namespace Hotline.Api.Controllers
             IUserCacheManager userCacheManager, ICapPublisher capPublisher,
             ITelRestRepository telRestRepository, IRepository<User> userRepository,
             ITelApplication telApplication, IRepository<Quality.Quality> qualiteyRepository,
-            IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate, ISystemSettingCacheManager systemSettingCacheManager)
+            IAiQualityService aiQualityService, IRepository<QualityTemplate> qualityTemplate, 
+            ISystemSettingCacheManager systemSettingCacheManager,IRepository<TelActionRecord> telActionRecordRepository)
         {
             _trClient = trClient;
             _mapper = mapper;
@@ -87,6 +90,7 @@ namespace Hotline.Api.Controllers
             _aiQualityService = aiQualityService;
             _qualityTemplate = qualityTemplate;
             _systemSettingCacheManager = systemSettingCacheManager;
+            _telActionRecordRepository = telActionRecordRepository;
         }
 
         #region 添添呼
@@ -265,6 +269,8 @@ namespace Hotline.Api.Controllers
             var user = await _userRepository.GetAsync(work.UserId, HttpContext.RequestAborted);
             var telRest = new TelRest(work.TelNo, work.TelNo, work.UserId, work.UserName, dto.Reason, false, user.StaffNo);
             await _telRestRepository.AddAsync(telRest, HttpContext.RequestAborted);
+            var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, EActionType.TelRest);
+            await _telActionRecordRepository.AddAsync(telAction, HttpContext.RequestAborted);
         }
 
         /// <summary>
@@ -283,10 +289,58 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("未查询到分机休息信息");
             telRest.EndRest();
             await _telRestRepository.UpdateAsync(telRest, HttpContext.RequestAborted);
+
+            var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, HttpContext.RequestAborted);
+            if (telAction!=null)
+            {
+                telAction.EndAction();
+                await _telActionRecordRepository.UpdateAsync(telAction);
+            }
         }
 
         #endregion
 
+        #region 添添呼话后整理
+
+        /// <summary>
+        /// 话后整理开始
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("callennd-arrange-begin")]
+        public async Task CallEndArrangeBegin()
+        {
+            var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
+
+            if (work is null)
+                throw UserFriendlyException.SameMessage("分机未签入,不能操作");
+
+            var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, EActionType.CallEndArrange);
+            await _telActionRecordRepository.AddAsync(telAction, HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 话后整理结束
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("callend-arrange-end")]
+        public async Task CallEndArrangeEnd()
+        {
+            var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
+            if (work is null)
+                throw UserFriendlyException.SameMessage("分机未签入,不能操作");
+
+            var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && !x.EndTime.HasValue, HttpContext.RequestAborted);
+            if (telAction != null)
+            {
+                telAction.EndAction();
+                await _telActionRecordRepository.UpdateAsync(telAction);
+            }
+        }
+
+
+        #endregion
+
+
         #region 通话记录(对外)
         /// <summary>
         /// 接收通话记录
@@ -577,6 +631,47 @@ namespace Hotline.Api.Controllers
 
 
 
+        #endregion
+
+        #region 坐席动作记录
+
+        /// <summary>
+        /// 坐席动作列表
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("telaction-list")]
+        public async Task<PagedDto<TelActionListRep>> TelActionList([FromQuery] TelActionListDto dto)
+        {
+            if (!dto.EndTime.HasValue)
+            {
+                dto.EndTime = DateTime.Now.Date;
+            }
+            dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
+            var (total,items) = await _telActionRecordRepository.Queryable()
+                .WhereIF(string.IsNullOrEmpty(dto.TelNo) == false, x => x.TelNo.Contains(dto.TelNo))
+                .WhereIF(dto.ActionTtype != null, x => x.ActionType == dto.ActionTtype)
+                .WhereIF(string.IsNullOrEmpty(dto.UserName) == false, x => x.UserName.Contains(dto.UserName))
+                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+                .OrderByDescending(x => x.CreationTime)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<TelActionListRep>(total, _mapper.Map<IReadOnlyList<TelActionListRep>>(items));
+        }
+
+        /// <summary>
+        /// 坐席动作列表基础数据
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("telaction-basedata")]
+        public async Task<object> TelActionBaseData()
+        {
+            return new
+            {
+                ActionType = EnumExts.GetDescriptions<EActionType>(),
+            };
+        }
         #endregion
 
         #endregion

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

@@ -132,7 +132,7 @@ namespace Hotline.Api.Controllers
         [HttpGet("treelist")]
         public async Task<List<KnowledgeType>> GetTreeList(bool? IsEnable)
         {
-            return await _knowledgeTypeRepository.Queryable().WhereIF(IsEnable.HasValue, p => p.IsEnable == IsEnable).ToTreeAsync(it => it.children, it => it.ParentId, null,it=> it.Id);
+            return await _knowledgeTypeRepository.Queryable().WhereIF(IsEnable.HasValue, p => p.IsEnable == IsEnable).OrderBy(p => p.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null,it=> it.Id);
         }
 
         /// <summary>

+ 7 - 7
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -502,7 +502,7 @@ namespace Hotline.Api.Controllers
                 .WhereIF(!string.IsNullOrEmpty(pagedDto.Summary), x => x.Summary != null && x.Summary.Contains(pagedDto.Summary!))
                 .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => SqlFunc.JsonLike(x.KnowledgeType, typeSpliceName))
                 .WhereIF(!string.IsNullOrEmpty(hotspotHotSpotFullName), x => x.HotspotType.HotSpotFullName.EndsWith(hotspotHotSpotFullName!))
-                .WhereIF(!string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.CreatorOrgId != null && x.CreatorOrgId.EndsWith(pagedDto.CreateOrgId!))
+                .WhereIF(!string.IsNullOrEmpty(pagedDto.CreateOrgId), x => x.SourceOrganizeId != null && x.SourceOrganizeId.EndsWith(pagedDto.CreateOrgId!))
                 .OrderByDescending(d => d.CreationTime)
                 .ToPagedListAsync(pagedDto.PageIndex, pagedDto.PageSize, HttpContext.RequestAborted);
             //temp.ForEach(x => x.IsCanHandle = x.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId));
@@ -581,18 +581,18 @@ namespace Hotline.Api.Controllers
             return new PagedDto<KnowledgeWorkFlowDto>(total, _mapper.Map<IReadOnlyList<KnowledgeWorkFlowDto>>(temp));
         }
         /// <summary>
-        /// 获取知识审批信息
+        /// 知识查重
         /// </summary>
         /// <param name="id"></param>
         /// <returns></returns>
-        [HttpGet("finding_duplicate")]
+        [HttpPost("finding_duplicate")]
 
-        public async Task<bool> FindingDuplicate([FromQuery] KnowledgeFindingDuplicateDto dto) 
+        public async Task<bool> FindingDuplicate([FromBody] KnowledgeFindingDuplicateDto dto) 
         {
             var any = await _knowledgeRepository.Queryable().Where(x => x.Status == EKnowledgeStatus.Auditing || x.Status >= EKnowledgeStatus.OnShelf)
-                .WhereIF(string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
-                .WhereIF(string.IsNullOrEmpty(dto.Summary), x => x.Title.Equals(dto.Summary))
-                .WhereIF(string.IsNullOrEmpty(dto.Content), x => x.Title.Equals(dto.Content))
+                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
+                .WhereIF(!string.IsNullOrEmpty(dto.Summary), x => x.Summary.Equals(dto.Summary))
+                .WhereIF(!string.IsNullOrEmpty(dto.Content), x => x.Content.Equals(dto.Content))
                 .AnyAsync();
             return any;
 		}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 463 - 327
src/Hotline.Api/Controllers/OrderController.cs


+ 15 - 0
src/Hotline.Api/Controllers/OrgController.cs

@@ -50,6 +50,21 @@ namespace Hotline.Api.Controllers
             return await _systemOrganizeRepository.GetOrgJson();
         }
 
+        [Permission(EPermission.GetOrgJson)]
+        [HttpGet("getorgjsonforuser")]
+        [AllowAnonymous]
+        public async Task<IReadOnlyList<SystemOrganize>> GetOrgJsonForUser()
+        {
+            if (_sessionContext.OrgIsCenter)
+            {
+                return await _systemOrganizeRepository.GetOrgJson();
+            }
+            else
+            {
+                return await _systemOrganizeRepository.GetOrgJsonForUser(_sessionContext.RequiredOrgId);
+            }
+        }
+
         ///// <summary>
         ///// 新增组织架构
         ///// </summary>

+ 150 - 5
src/Hotline.Api/Controllers/TestController.cs

@@ -17,13 +17,18 @@ using Hotline.Import;
 using Hotline.Orders;
 using Hotline.Realtimes;
 using Hotline.Repository.SqlSugar;
+using Hotline.Repository.SqlSugar.System;
 using Hotline.Repository.SqlSugar.Ts;
+using Hotline.Settings;
 using Hotline.Settings.TimeLimits;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Realtime;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Mq;
+using Hotline.Tools;
 using Hotline.Users;
+using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Components.Routing;
@@ -85,6 +90,9 @@ public class TestController : BaseController
     private readonly IRepository<WorkflowTrace> _workflowTraceRepository;
     private readonly IRepository<WorkflowStepHandler> _workflowStepHandleRepository;
 
+    private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
+    private readonly IMapper _mapper;
+
 
     //private readonly ITypedCache<List<User>> _cache;
     //private readonly ICacheManager<User> _cache;
@@ -118,7 +126,10 @@ public class TestController : BaseController
         IExportApplication exportApplication,
         IAiVisitService aiVisitService,
         IRepository<WorkflowTrace> workflowTraceRepository,
-        IRepository<WorkflowStepHandler> workflowStepHandleRepository)
+        IRepository<WorkflowStepHandler> workflowStepHandleRepository,
+        IRepository<SystemOrganize> systemOrganizeRepository,
+        IMapper mapper
+        )
     {
         _logger = logger;
         _authorizeGenerator = authorizeGenerator;
@@ -145,6 +156,8 @@ public class TestController : BaseController
         _aiVisitService = aiVisitService;
         _workflowTraceRepository = workflowTraceRepository;
         _workflowStepHandleRepository = workflowStepHandleRepository;
+        _systemOrganizeRepository = systemOrganizeRepository;
+        _mapper = mapper;
     }
 
     [HttpGet("testo")]
@@ -154,6 +167,58 @@ public class TestController : BaseController
         return OpenResponse.Ok(now);
     }
 
+
+    [HttpGet("init-orgname")]
+    [AllowAnonymous]
+    public async Task InitUserOrgFullName()
+    {
+        var list = await _userRepository.Queryable().Where(x => 1 == 1 && string.IsNullOrEmpty(x.FullOrgName)).ToListAsync();
+
+        foreach (var item in list)
+        {
+            var orgFullName = "";
+            var orgFullCode = "";
+            var orgId = item.OrgId;
+            int strLength = orgId.Length;
+            int segmentsCount = strLength / 3;
+            List<string> strings = new List<string>();
+
+            for (int i = 0; i < segmentsCount; i++)
+            {
+                int startIndex = i * 3;
+                int length = Math.Min(3, strLength - startIndex);
+                strings.Add(orgId.Substring(startIndex, length));
+            }
+
+            if (strLength > 3)
+            {
+                orgFullCode = strings[0];
+                strings.Remove(orgFullCode);
+
+            }
+
+            foreach (var str in strings)
+            {
+                orgFullCode = orgFullCode + str;
+
+                var org = await _systemOrganizeRepository.GetAsync(orgFullCode);
+                if (org != null)
+                {
+
+                    orgFullName = orgFullName + org.Name + "/";
+                }
+            }
+            if (orgFullName.Length > 0)
+            {
+                orgFullName = orgFullName.Remove(orgFullName.Length - 1);
+            }
+            item.FullOrgName = orgFullName;
+            await _userRepository.UpdateAsync(item);
+        }
+    }
+
+
+
     [HttpPost("import")]
     [AllowAnonymous]
     public async Task<List<ExcelContent>> Import(IFormFile file)
@@ -336,7 +401,7 @@ public class TestController : BaseController
         //var list = await query
         //    .Select((t, w, o) => new { t, w, o })
         //    .ToListAsync(HttpContext.RequestAborted);
-        
+
         //var toUsers = list.Where(d => d.t.FlowAssignType == EFlowAssignType.User).ToList();
         //var userIds = toUsers.SelectMany(d => d.t.Handlers).Select(d => d.Key).Distinct().ToList();
         //var users = await _userRepository.Queryable()
@@ -391,10 +456,59 @@ public class TestController : BaseController
 
     [AllowAnonymous]
     [HttpPost("t3")]
-    public Task<int> TestDaprPubsub(int data)
+    public IActionResult TestExportExcel()
     {
-        _logger.LogDebug("receive dapr event, params: {0}", data);
-        return Task.FromResult(data);
+       //var students = new List<Student>
+       // {
+       //     new Student
+       //     {
+       //         Id = "student001",
+       //         Name = "student001Name",
+       //         School = new School
+       //         {
+       //             Id = "schoolABC",
+       //             Name = "schoolABCName",
+       //             Sponser = new Sponser
+       //             {
+       //                 Amount = 1000
+       //             }
+       //         }
+       //     },
+       //     new Student
+       //     {
+       //         Id = "student002",
+       //         Name = "student002Name",
+       //         School = new School
+       //         {
+       //             Id = "schoolABCD",
+       //             Name = "schoolABCDName",
+       //             Sponser = new Sponser
+       //             {
+       //                 Amount = 2000
+       //             }
+       //         }
+       //     }
+       // };
+
+       //var ps = new List<Kv>
+       //{
+       //    new("Id", "编号"),
+       //    new("SchoolId", "流程标题"),
+       //    new("SchoolSponserAmount", "金额"),
+       //};
+
+       //dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(ps);
+
+       // var dtos = students.Select(stu => _mapper.Map(stu, typeof(Student), dynamicClass))
+       //     .Cast<object>()
+       //     .ToList();
+
+       // var stream = ExcelHelper.CreateStream(dtos);
+
+       // return ExcelStreamResult(stream);
+
+       throw new NotImplementedException();
+
     }
 
     [HttpGet("rsa")]
@@ -406,4 +520,35 @@ public class TestController : BaseController
         return $"{publicKey} \r\n {privateKey}";
     }
 
+}
+
+public class School
+{
+    public string Id { get; set; }
+    public string Name { get; set; }
+    public Sponser Sponser { get; set; }
+}
+
+public class Student
+{
+    public string Id { get; set; }
+    public string Name { get; set; }
+
+    public School School { get; set; }
+}
+
+public class Sponser
+{
+    public int Amount { get; set; }
+}
+
+public class StudentDto
+{
+    public string Id { get; set; }
+    public string Name { get; set; }
+
+    public string SchoolId { get; set; }
+    public string SchoolName { get; set; }
+
+    public int SchoolSponserAmount { get; set; }
 }

+ 1 - 1
src/Hotline.Application/Bigscreen/SeatStateDataRefreshService.cs

@@ -40,7 +40,7 @@ namespace Hotline.Application.Bigscreen
 
 		protected override async Task ExecuteAsync(CancellationToken stoppingToken)
 		{
-			using var scope = _serviceScopeFactory.CreateScope();
+			using var scope = _serviceScopeFactory.CreateScope(); 
 			var realtimeService = scope.ServiceProvider.GetRequiredService<IRealtimeService>();
 			var logger = scope.ServiceProvider.GetRequiredService<ILogger<SeatStateDataRefreshService>>();
 			var systemSettingCacheManager = scope.ServiceProvider.GetRequiredService<ISystemSettingCacheManager>();

+ 24 - 1
src/Hotline.Application/CallCenter/Calls/TelsStatusRefreshService.cs

@@ -1,6 +1,9 @@
-using Hotline.CallCenter.Tels;
+using Hotline.CallCenter.Calls;
+using Hotline.CallCenter.Tels;
 using Hotline.Realtimes;
+using Hotline.Share.Enums.CallCenter;
 using Hotline.Users;
+using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using System.Threading;
@@ -27,6 +30,7 @@ namespace Hotline.Application.CallCenter.Calls
             var _workRepository = scope.ServiceProvider.GetRequiredService<IRepository<Work>>();
             var _telRestRepository = scope.ServiceProvider.GetRequiredService<IRepository<TelRest>>();
             var _cacheWork = scope.ServiceProvider.GetRequiredService<ITypedCache<Work>>();
+            var _telActionRecordRepository = scope.ServiceProvider.GetRequiredService<IRepository<TelActionRecord>>();
             int times = 300000;
             while (!stoppingToken.IsCancellationRequested)
             {
@@ -54,6 +58,25 @@ namespace Hotline.Application.CallCenter.Calls
                                 await _workRepository.UpdateAsync(item, stoppingToken);
                                 _cacheWork.Remove(item.GetKey(KeyMode.UserId));
                                 _cacheWork.Remove(item.GetKey(KeyMode.TelNo));
+
+                                #region 小休状态
+                                var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, stoppingToken);
+                                if (telAction != null)
+                                {
+                                    telAction.EndAction();
+                                    await _telActionRecordRepository.UpdateAsync(telAction);
+                                }
+                                #endregion
+                                #region 话后整理
+
+                                var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == item.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue,stoppingToken);
+                                if (telarrangeAction != null)
+                                {
+                                    telarrangeAction.EndAction();
+                                    await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+                                }
+
+                                #endregion
                             }
                         }
                     }

+ 2 - 2
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -44,8 +44,8 @@ namespace Hotline.Application.FlowEngine
         /// <summary>
         /// 跳转至结束节点(无视流程模板配置直接跳至结束节点)
         /// </summary>
-        Task JumpToEndAsync(string workflowId, string opinion, List<FileDto> file,
-            EReviewResult? reviewResult = EReviewResult.Unknown,
+        Task HandleToEndAsync(string workflowId, string opinion, List<FileDto> file,
+            EReviewResult? reviewResult = EReviewResult.Unknown, bool isProvince = false,
             CancellationToken cancellationToken = default);
         
         ////////

+ 7 - 6
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -324,10 +324,10 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     }
 
     /// <summary>
-    /// 跳转至结束节点(无视流程模板配置直接跳至结束节点)
+    /// 无视流程模板配置直接将当前节点办理至结束节点
     /// </summary>
-    public async Task JumpToEndAsync(string workflowId, string opinion, List<FileDto> files,
-        EReviewResult? reviewResult = EReviewResult.Unknown,
+    public async Task HandleToEndAsync(string workflowId, string opinion, List<FileDto> files,
+        EReviewResult? reviewResult = EReviewResult.Unknown, bool isProvince = false,
         CancellationToken cancellationToken = default)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true,
@@ -339,12 +339,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (currentStep is null)
             throw new UserFriendlyException("未找到实际办理节点");
 
-        await _workflowDomainService.EndAsync(workflow, new BasicWorkflowDto
+        await _workflowDomainService.EndAsync(workflow, 
+            new BasicWorkflowDto
         {
             Opinion = opinion,
             Files = files
-        }, endStepDefine, currentStep,
-            reviewResult, cancellationToken);
+        }, 
+            endStepDefine, currentStep, reviewResult, isProvince,  cancellationToken: cancellationToken);
     }
 
     /// <summary>

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

@@ -194,7 +194,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                 //司法行政监督管理-工单处理
                 await _enforcementApplication.AddEnforcementOrderAsync(order, cancellationToken);
                 //推诿工单
-                await _enforcementApplication.AddPassTheBuckOrderAsync(order, _sessionContext.RequiredOrgId, _sessionContext.OrgName, cancellationToken);
+                await _enforcementApplication.AddPassTheBuckOrderAsync(order, _sessionContext.OrgId, _sessionContext.OrgName, cancellationToken);
                 break;
             case WorkflowModuleConsts.OrderScreen:
                 var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);

+ 58 - 58
src/Hotline.Application/Handlers/Order/DelayProvinceResultNotifyHandler.cs

@@ -1,62 +1,62 @@
-using MediatR;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Hotline.Application.FlowEngine;
-using Hotline.DataSharing.Province.Notifications;
-using Hotline.Orders;
-using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Enums.FlowEngine;
-using Hotline.Share.Enums.Order;
-using XF.Domain.Exceptions;
-using XF.Domain.Repository;
+//using MediatR;
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Text;
+//using System.Threading.Tasks;
+//using Hotline.Application.FlowEngine;
+//using Hotline.DataSharing.Province.Notifications;
+//using Hotline.Orders;
+//using Hotline.Share.Dtos.FlowEngine;
+//using Hotline.Share.Enums.FlowEngine;
+//using Hotline.Share.Enums.Order;
+//using XF.Domain.Exceptions;
+//using XF.Domain.Repository;
 
-namespace Hotline.Application.Handlers.Order
-{
-    public class DelayProvinceResultNotifyHandler : INotificationHandler<DelayProvinceResultNotify>
-    {
-        private readonly IRepository<OrderDelay> _orderDelayRepository;
-        private readonly IWorkflowApplication _workflowApplication;
+//namespace Hotline.Application.Handlers.Order
+//{
+//    public class DelayProvinceResultNotifyHandler : INotificationHandler<DelayProvinceResultNotify>
+//    {
+//        private readonly IRepository<OrderDelay> _orderDelayRepository;
+//        private readonly IWorkflowApplication _workflowApplication;
 
-        public DelayProvinceResultNotifyHandler(
-            IRepository<OrderDelay> orderDelayRepository,
-            IWorkflowApplication workflowApplication)
-        {
-            _orderDelayRepository = orderDelayRepository;
-            _workflowApplication = workflowApplication;
-        }
+//        public DelayProvinceResultNotifyHandler(
+//            IRepository<OrderDelay> orderDelayRepository,
+//            IWorkflowApplication workflowApplication)
+//        {
+//            _orderDelayRepository = orderDelayRepository;
+//            _workflowApplication = workflowApplication;
+//        }
 
-        /// <summary>Handles a notification</summary>
-        /// <param name="notification">The notification</param>
-        /// <param name="cancellationToken">Cancellation token</param>
-        public async Task Handle(DelayProvinceResultNotify notification, CancellationToken cancellationToken)
-        {
-            var dto = notification;
-            var orderDelay = await _orderDelayRepository.Queryable()
-                .Includes(d => d.Order)
-                .Includes(d => d.Workflow)
-                .FirstAsync(d => d.Order.ProvinceNo == dto.No && d.DelayState == EDelayState.Examining, cancellationToken);
-            if (orderDelay is null)
-                throw new UserFriendlyException("无效省工单编号");
-            if (string.IsNullOrEmpty(orderDelay.WorkflowId))
-                throw new UserFriendlyException("无效延期审批流程编号");
+//        /// <summary>Handles a notification</summary>
+//        /// <param name="notification">The notification</param>
+//        /// <param name="cancellationToken">Cancellation token</param>
+//        public async Task Handle(DelayProvinceResultNotify notification, CancellationToken cancellationToken)
+//        {
+//            var dto = notification;
+//            var orderDelay = await _orderDelayRepository.Queryable()
+//                .Includes(d => d.Order)
+//                .Includes(d => d.Workflow)
+//                .FirstAsync(d => d.Order.ProvinceNo == dto.No && d.DelayState == EDelayState.Examining, cancellationToken);
+//            if (orderDelay is null)
+//                throw new UserFriendlyException("无效省工单编号");
+//            if (string.IsNullOrEmpty(orderDelay.WorkflowId))
+//                throw new UserFriendlyException("无效延期审批流程编号");
 
-            if (dto.IsPass)
-            {
-                await _workflowApplication.JumpToEndAsync(orderDelay.WorkflowId, dto.Opinion, notification.Files,EReviewResult.Approval,
-                    cancellationToken);
-            }
-            else
-            {
-                var rejectDto = new RejectDto
-                {
-                    WorkflowId = orderDelay.WorkflowId,
-                    Opinion = dto.Opinion,
-                };
-                await _workflowApplication.RejectAsync(rejectDto, cancellationToken);
-            }
-        }
-    }
-}
+//            if (dto.IsPass)
+//            {
+//                await _workflowApplication.JumpToEndAsync(orderDelay.WorkflowId, dto.Opinion, notification.Files,EReviewResult.Approval,
+//                    true,cancellationToken);
+//            }
+//            else
+//            {
+//                var rejectDto = new RejectDto
+//                {
+//                    WorkflowId = orderDelay.WorkflowId,
+//                    Opinion = dto.Opinion,
+//                };
+//                await _workflowApplication.RejectAsync(rejectDto, cancellationToken);
+//            }
+//        }
+//    }
+//}

+ 39 - 39
src/Hotline.Application/Handlers/Order/OrderResultNotifyHandler.cs

@@ -1,42 +1,42 @@
-using Hotline.Application.FlowEngine;
-using Hotline.DataSharing.Province.Notifications;
-using Hotline.File;
-using Hotline.Orders;
-using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Dtos.Order;
-using Hotline.Share.Enums.Order;
-using MapsterMapper;
-using MediatR;
+//using Hotline.Application.FlowEngine;
+//using Hotline.DataSharing.Province.Notifications;
+//using Hotline.File;
+//using Hotline.Orders;
+//using Hotline.Share.Dtos.FlowEngine;
+//using Hotline.Share.Dtos.Order;
+//using Hotline.Share.Enums.Order;
+//using MapsterMapper;
+//using MediatR;
 
-namespace Hotline.Application.Handlers.Order
-{
-	public class OrderResultNotifyHandler : INotificationHandler<OrderResultNotify>
-	{
-		private readonly IOrderRepository _orderRepository;
-		private readonly IWorkflowApplication _workflowApplication;
+//namespace Hotline.Application.Handlers.Order
+//{
+//	public class OrderResultNotifyHandler : INotificationHandler<OrderResultNotify>
+//	{
+//		private readonly IOrderRepository _orderRepository;
+//		private readonly IWorkflowApplication _workflowApplication;
 
-		public OrderResultNotifyHandler(
-			IOrderRepository orderRepository, 
-			IWorkflowApplication workflowApplication)
-		{
-			_orderRepository = orderRepository;
-			_workflowApplication = workflowApplication;
-		}
+//		public OrderResultNotifyHandler(
+//			IOrderRepository orderRepository, 
+//			IWorkflowApplication workflowApplication)
+//		{
+//			_orderRepository = orderRepository;
+//			_workflowApplication = workflowApplication;
+//		}
 
-		public async Task Handle(OrderResultNotify request, CancellationToken cancellationToken)
-		{
-			var order = await  _orderRepository.GetAsync(request.OrderId, cancellationToken);
-            if (order != null)
-            {
-				if ("0".Equals(request.FinishType))
-				{
-					await _workflowApplication.PreviousAsync(
-						new PreviousWorkflowDto { WorkflowId = order.WorkflowId, Opinion = request.Opinion, Files = request.Files }, cancellationToken: cancellationToken);
-				}
-				else if ("1".Equals(request.FinishType)) {
-					await _workflowApplication.JumpToEndAsync(order.WorkflowId, request.Opinion, request.Files, cancellationToken: cancellationToken);
-				}
-			}
-        }
-	}
-}
+//		public async Task Handle(OrderResultNotify request, CancellationToken cancellationToken)
+//		{
+//			var order = await  _orderRepository.GetAsync(request.OrderId, cancellationToken);
+//            if (order != null)
+//            {
+//				if ("0".Equals(request.FinishType))
+//				{
+//					await _workflowApplication.PreviousAsync(
+//						new PreviousWorkflowDto { WorkflowId = order.WorkflowId, Opinion = request.Opinion, Files = request.Files }, cancellationToken: cancellationToken);
+//				}
+//				else if ("1".Equals(request.FinishType)) {
+//					await _workflowApplication.JumpToEndAsync(order.WorkflowId, request.Opinion, request.Files, cancellationToken: cancellationToken);
+//				}
+//			}
+//        }
+//	}
+//}

+ 59 - 60
src/Hotline.Application/Handlers/Order/ScreenProvinceResultNotifyHandler.cs

@@ -1,64 +1,63 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Hotline.Application.FlowEngine;
-using Hotline.DataSharing.Province.Notifications;
-using Hotline.Orders;
-using Hotline.Share.Dtos.FlowEngine;
-using Hotline.Share.Enums.FlowEngine;
-using Hotline.Share.Enums.Order;
-using MediatR;
-using Microsoft.AspNetCore.Http;
-using XF.Domain.Exceptions;
-using XF.Domain.Repository;
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Text;
+//using System.Threading.Tasks;
+//using Hotline.Application.FlowEngine;
+//using Hotline.DataSharing.Province.Notifications;
+//using Hotline.Orders;
+//using Hotline.Share.Dtos.FlowEngine;
+//using Hotline.Share.Enums.FlowEngine;
+//using Hotline.Share.Enums.Order;
+//using MediatR;
+//using Microsoft.AspNetCore.Http;
+//using XF.Domain.Exceptions;
+//using XF.Domain.Repository;
 
-namespace Hotline.Application.Handlers.Order
-{
-    public class ScreenProvinceResultNotifyHandler : INotificationHandler<ScreenProvinceResultNotify>
-    {
-        private readonly IRepository<OrderScreen> _orderScreenRepository;
-        private readonly IWorkflowApplication _workflowApplication;
+//namespace Hotline.Application.Handlers.Order
+//{
+//    public class ScreenProvinceResultNotifyHandler : INotificationHandler<ScreenProvinceResultNotify>
+//    {
+//        private readonly IRepository<OrderScreen> _orderScreenRepository;
+//        private readonly IWorkflowApplication _workflowApplication;
 
-        public ScreenProvinceResultNotifyHandler(
-            IRepository<OrderScreen> orderScreenRepository,
-            IWorkflowApplication workflowApplication)
-        {
-            _orderScreenRepository = orderScreenRepository;
-            _workflowApplication = workflowApplication;
-        }
+//        public ScreenProvinceResultNotifyHandler(
+//            IRepository<OrderScreen> orderScreenRepository,
+//            IWorkflowApplication workflowApplication)
+//        {
+//            _orderScreenRepository = orderScreenRepository;
+//            _workflowApplication = workflowApplication;
+//        }
 
-        /// <summary>Handles a notification</summary>
-        /// <param name="notification">The notification</param>
-        /// <param name="cancellationToken">Cancellation token</param>
-        public async Task Handle(ScreenProvinceResultNotify notification, CancellationToken cancellationToken)
-        {
-            var dto = notification.ProvinceScreenResult;
-            var orderScreen = await _orderScreenRepository.Queryable()
-                .Includes(d => d.Order)
-                .Includes(d => d.Workflow)
-                .FirstAsync(d => d.Order.ProvinceNo == dto.CaseSerial && d.Status == EScreenStatus.Approval, cancellationToken);
-            if (orderScreen is null)
-                throw new UserFriendlyException("无效省工单编号");
-            if (string.IsNullOrEmpty(orderScreen.WorkflowId))
-                throw new UserFriendlyException("无效甄别审批流程编号");
+//        /// <summary>Handles a notification</summary>
+//        /// <param name="notification">The notification</param>
+//        /// <param name="cancellationToken">Cancellation token</param>
+//        public async Task Handle(ScreenProvinceResultNotify notification, CancellationToken cancellationToken)
+//        {
+//            var dto = notification.ProvinceScreenResult;
+//            var orderScreen = await _orderScreenRepository.Queryable()
+//                .Includes(d => d.Order)
+//                .Includes(d => d.Workflow)
+//                .FirstAsync(d => d.Order.ProvinceNo == dto.CaseSerial && d.Status == EScreenStatus.Approval, cancellationToken);
+//            if (orderScreen is null)
+//                throw new UserFriendlyException("无效省工单编号");
+//            if (string.IsNullOrEmpty(orderScreen.WorkflowId))
+//                throw new UserFriendlyException("无效甄别审批流程编号");
 
-            var pass = "1".Equals(dto.AuditResult);
-            if (pass)
-            {
-                await _workflowApplication.JumpToEndAsync(orderScreen.WorkflowId, dto.AuditOpinion, notification.Files,EReviewResult.Approval,
-                    cancellationToken);
-            }
-            else
-            {
-                var rejectDto = new RejectDto
-                {
-                    WorkflowId = orderScreen.WorkflowId,
-                    Opinion = dto.AuditOpinion,
-                };
-                await _workflowApplication.RejectAsync(rejectDto, cancellationToken);
-            }
-        }
-    }
-}
+//            if (dto.AuditResult)
+//            {
+//                await _workflowApplication.JumpToEndAsync(orderScreen.WorkflowId, dto.AuditOpinion, notification.Files,EReviewResult.Approval,
+//                    true,cancellationToken);
+//            }
+//            else
+//            {
+//                var rejectDto = new RejectDto
+//                {
+//                    WorkflowId = orderScreen.WorkflowId,
+//                    Opinion = dto.AuditOpinion,
+//                };
+//                await _workflowApplication.RejectAsync(rejectDto, cancellationToken);
+//            }
+//        }
+//    }
+//}

+ 14 - 13
src/Hotline.Application/Identity/IdentityAppService.cs

@@ -32,7 +32,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
     private readonly IRepository<Scheduling> _schedulingRepository;
     private readonly IOrderDomainService _orderDomainService;
 
-	public IdentityAppService(
+    public IdentityAppService(
         IAccountRepository accountRepository,
         IAccountDomainService accountDomainService,
         IRepository<User> userRepository,
@@ -41,7 +41,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         ITypedCache<AudienceTicket> cacheAudience,
         IMessageCodeDomainService messageCodeDomainService,
         IRepository<Scheduling> schedulingRepository,
-		 IOrderDomainService orderDomainService)
+         IOrderDomainService orderDomainService)
     {
         _accountRepository = accountRepository;
         _accountDomainService = accountDomainService;
@@ -52,7 +52,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         _messageCodeDomainService = messageCodeDomainService;
         _schedulingRepository = schedulingRepository;
         _orderDomainService = orderDomainService;
-	}
+    }
 
     public async Task<string> LoginAsync(LoginDto dto, CancellationToken cancellationToken)
     {
@@ -60,7 +60,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
             d => d.UserName == dto.Username,
             d => d.Includes(x => x.Roles));
         if (account == null)
-            throw UserFriendlyException.SameMessage("用户名或密码错误!");
+            throw new UserFriendlyException($"用户名或密码错误!{System.Text.Json.JsonSerializer.Serialize(dto)}", "用户名或密码错误!");
 
         //校验验证码
         await _messageCodeDomainService.CheckdCode(account.UserName, account.PhoneNo, dto.MsgCode, cancellationToken);
@@ -79,7 +79,7 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
             if (account.LockoutEnabled && account.AccessFailedCount >= lockoutOptions.MaxFailedAccessAttempts)
                 account.LockoutEnd = DateTime.Now.Add(lockoutOptions.DefaultLockoutTimeSpan);
             await _accountRepository.UpdateAsync(account, cancellationToken);
-            throw UserFriendlyException.SameMessage("账号名或密码错误!");
+            throw new UserFriendlyException($"用户名或密码错误!{System.Text.Json.JsonSerializer.Serialize(dto)}", "用户名或密码错误!");
         }
 
         //限制系统类型账户频繁获取token的行为
@@ -134,15 +134,16 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
         return token;
     }
 
-    public async Task AverageOrderScheduling(string id, CancellationToken cancellationToken) {
+    public async Task AverageOrderScheduling(string id, CancellationToken cancellationToken)
+    {
         try
         {
             DateTime time = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd"));
 
-	            //&& x.AtWork!.Value != true
-			//根据当前时间获取排班信息
-			var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
-                .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && ( x.AtWork == true || x.AtWork  == null) && x.SchedulingUser.UserId == id)
+            //&& x.AtWork!.Value != true
+            //根据当前时间获取排班信息
+            var scheduling = await _schedulingRepository.Queryable().Includes(x => x.SchedulingUser)
+                .Where(x => x.SchedulingTime == time && x.WorkingTime <= DateTime.Now.TimeOfDay && x.OffDutyTime >= DateTime.Now.TimeOfDay && (x.AtWork == true || x.AtWork == null) && x.SchedulingUser.UserId == id)
                 .OrderBy(x => x.SendOrderNum).FirstAsync(cancellationToken);
             if (scheduling != null)
             {
@@ -150,11 +151,11 @@ public class IdentityAppService : IIdentityAppService, IScopeDependency
                 await _schedulingRepository.UpdateAsync(scheduling, cancellationToken);
                 //执行登录平均派单
                 await _orderDomainService.LogAverageOrder(id, cancellationToken);
-			}
+            }
         }
-        catch 
+        catch
         {
-	        // ignored
+            // ignored
         }
     }
 }

+ 3 - 0
src/Hotline.Application/JudicialManagement/EnforcementApplication.cs

@@ -105,6 +105,9 @@ namespace Hotline.Application.JudicialManagement
         /// <returns></returns>
         public async Task AddPassTheBuckOrderAsync(Hotline.Orders.Order order, string orgCode, string orgName, CancellationToken cancellationToken)
         {
+            if (string.IsNullOrEmpty(orgCode) || string.IsNullOrEmpty(orgName))
+                return;
+
             //排除咨询件
             if (order.AcceptTypeCode == "10")
                 return;

+ 1 - 0
src/Hotline.Application/Mappers/IdentityMapperConfigs.cs

@@ -21,6 +21,7 @@ public class IdentityMapperConfigs : IRegister
         config.NewConfig<User, UserDto>()
             .IgnoreIf((s, d) => s.Account == null, d => d.UserName)
             .IgnoreIf((s, d) => s.Roles == null || !s.Roles.Any(), d => d.RoleNames)
+            .IgnoreIf((s, d) => s.Organization == null, d => d.Organization)
             .Map(d => d.UserName, x => x.Account.UserName)
             .Map(d => d.State, x => x.IsDeleted ? "已删除" : "正常")
             .Map(d => d.RoleNames, x => string.Join(',', x.Roles.Select(s => s.DisplayName)))

+ 7 - 0
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -10,6 +10,7 @@ using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Settings;
+using SqlSugar;
 using XF.Domain.Entities;
 
 namespace Hotline.Application.Orders
@@ -48,5 +49,11 @@ namespace Hotline.Application.Orders
         /// 接收外部平台修改工单附件
         /// </summary>
         Task UpdateOrderFilesAnonymousAsync(UpdateOrderFilesDto dto, CancellationToken cancellationToken);
+
+        #region 工单办理
+
+        ISugarQueryable<Order> QueryOrders(QueryOrderDto dto);
+
+        #endregion
     }
 }

+ 22 - 0
src/Hotline.Application/Orders/IOrderSecondaryHandlingApplication.cs

@@ -0,0 +1,22 @@
+using Hotline.Orders;
+using Hotline.Share.Dtos.Order;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Orders
+{
+	public interface IOrderSecondaryHandlingApplication
+	{
+		Task AddAsync(AddOrderSecondaryHandlingDto dto, CancellationToken cancellationToken);
+
+		Task SendBackAsync(SendBackOrderSecondaryHandlingDto dto, CancellationToken cancellationToken);
+		Task AuditAsync(AuditOrderSecondaryHandlingDto dto, OrderSecondaryHandling model, CancellationToken cancellationToken);
+		ISugarQueryable<OrderVisitDetail> ApplyQuery(MayScreenListDto dto, CancellationToken cancellationToken);
+		Task<OrderSecondaryHandling> Entity(string id, CancellationToken cancellationToken);
+		ISugarQueryable<OrderSecondaryHandling> Query(SecondaryHandlingListDto dto, CancellationToken cancellationToken);
+	}
+}

+ 74 - 23
src/Hotline.Application/Orders/OrderApplication.cs

@@ -16,6 +16,9 @@ using Hotline.Share.Enums.Settings;
 using Hotline.Tools;
 using Hotline.Users;
 using MapsterMapper;
+using MediatR;
+using SqlSugar;
+using XF.Domain.Authentications;
 using XF.Domain.Constants;
 using XF.Domain.Dependency;
 using XF.Domain.Entities;
@@ -35,6 +38,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     private readonly IRepository<OrderWord> _orderWrodRepository;
     private readonly IRepositoryTextSearch<OrderTs> _repositoryts;
     private readonly IFileRepository _fileRepository;
+    private readonly ISessionContext _sessionContext;
 
     public OrderApplication(
         IOrderDomainService orderDomainService,
@@ -45,7 +49,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IMapper mapper,
         IRepository<OrderWord> orderWrodRepository,
         IRepositoryTextSearch<OrderTs> repositoryts,
-        IFileRepository fileRepository
+        IFileRepository fileRepository,
+        ISessionContext sessionContext
         )
     {
         _orderDomainService = orderDomainService;
@@ -57,6 +62,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _orderWrodRepository = orderWrodRepository;
         _repositoryts = repositoryts;
         _fileRepository = fileRepository;
+        _sessionContext = sessionContext;
     }
 
     /// <summary>
@@ -75,17 +81,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         order.ExpiredTime = expiredTimeConfig.ExpiredTime;
         order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime;
 
-		//if (string.IsNullOrEmpty(order.WorkflowId))
-		//    throw new UserFriendlyException("该工单流程id异常");
-		//var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, cancellationToken: cancellationToken);
-		//await _workflowDomainService.UpdateExpiredTimeAsync(workflow, expiredTimeConfig.ExpiredTime,
-		//    expiredTimeConfig.TimeText, expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.NearlyExpiredTime, cancellationToken);
+        //if (string.IsNullOrEmpty(order.WorkflowId))
+        //    throw new UserFriendlyException("该工单流程id异常");
+        //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, cancellationToken: cancellationToken);
+        //await _workflowDomainService.UpdateExpiredTimeAsync(workflow, expiredTimeConfig.ExpiredTime,
+        //    expiredTimeConfig.TimeText, expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.NearlyExpiredTime, cancellationToken);
 
-		if (string.IsNullOrEmpty(order.WorkflowId))
-			throw new UserFriendlyException("该工单流程id异常");
-		await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, expiredTimeConfig.ExpiredTime, cancellationToken);
+        if (string.IsNullOrEmpty(order.WorkflowId))
+            throw new UserFriendlyException("该工单流程id异常");
+        await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, expiredTimeConfig.ExpiredTime, cancellationToken);
 
-		await _orderRepository.UpdateAsync(order, cancellationToken);
+        await _orderRepository.UpdateAsync(order, cancellationToken);
     }
 
     /// <summary>
@@ -263,22 +269,22 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         }
     }
 
-    public async Task OrderSensitiveParticiple(string inputStr, string orderId, CancellationToken cancellationToken) 
+    public async Task OrderSensitiveParticiple(string inputStr, string orderId, 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);
-		if (res.Any())
+        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);
+        if (res.Any())
         {
             var intersect = words.Intersect(res).ToList();
-			await _orderRepository.Updateable().SetColumns(o=> new Order() { Sensitive  = intersect }).Where(o=>o.Id == orderId).ExecuteCommandAsync(cancellationToken);
-		}
-	}
-
-	/// <summary>
-	/// 接收外部平台工单
-	/// </summary>
-	public Task<AddOrderResponse> ReceiveOrderFromExternalAsync(AddOrderDto dto, CancellationToken cancellationToken)
+            await _orderRepository.Updateable().SetColumns(o => new Order() { Sensitive = intersect }).Where(o => o.Id == orderId).ExecuteCommandAsync(cancellationToken);
+        }
+    }
+
+    /// <summary>
+    /// 接收外部平台工单
+    /// </summary>
+    public Task<AddOrderResponse> ReceiveOrderFromExternalAsync(AddOrderDto dto, CancellationToken cancellationToken)
     {
         switch (dto.Source)
         {
@@ -313,6 +319,51 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         }
     }
 
+    public ISugarQueryable<Order> QueryOrders(QueryOrderDto dto)
+    {
+        var isCenter = _sessionContext.OrgIsCenter;
+
+        return _orderRepository.Queryable(viewFilter: isCenter ? false : true)
+            .Includes(x => x.OrderScreens)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
+            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号
+            .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) //工单编码
+                                                                                //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!))
+            .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型
+            .WhereIF(dto.Channels.Any(), d => dto.Channels.Contains(d.SourceChannelCode)) //来源渠道
+            .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //热点类型
+            .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!)) //转接号码
+                                                                                                                  //.WhereIF(dto.OrgCodes.Any(), d => d.Workflow.Assigns.Any(s => dto.OrgCodes.Contains(s.OrgCode)))
+            .WhereIF(dto.OrgCodes.Any(), d => dto.OrgCodes.Contains(d.ActualHandleOrgCode)) //接办部门
+            .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) //受理人/坐席
+            .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) //受理时间开始
+            .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //受理时间结束
+            .WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel))  //紧急程度
+            .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone.Contains(dto.FromPhone)) //来电号码
+            .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact.Contains(dto.PhoneNo!)) //联系电话
+            .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) //推送分类
+            .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) //超期时间开始
+            .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) //超期时间结束
+            .WhereIF(dto.Statuses.Any(), d => dto.Statuses.Contains(d.Status))  //工单状态
+            .WhereIF(dto.Statuses.Any(d => d == EOrderStatus.SpecialToUnAccept), d => d.Status <= EOrderStatus.SpecialToUnAccept)
+            .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => d.ActualHandlerName.Contains(dto.ActualHandlerName)) //接办人
+            .WhereIF(dto.IsScreen == true, d => d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //有甄别
+            .WhereIF(dto.IsScreen == false, d => !d.OrderScreens.Any(x => x.Status != EScreenStatus.Refuse)) //无甄别
+            .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepCode), d => d.ActualHandleStepCode == dto.CurrentStepCode) //当前办理节点
+            .WhereIF(dto.ActualHandleTimeStart.HasValue, d => d.ActualHandleTime >= dto.ActualHandleTimeStart) //办结时间开始
+            .WhereIF(dto.ActualHandleTimeEnd.HasValue, d => d.ActualHandleTime <= dto.ActualHandleTimeEnd) //办结时间结束
+            .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期
+            .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期
+            .WhereIF(dto.IdentityType != null, d => d.IdentityType == dto.IdentityType) //来电主体
+            .WhereIF(!string.IsNullOrEmpty(dto.FromName), d => d.FromName.Contains(dto.FromName)) //来电人姓名
+            .WhereIF(dto.AreaCodes.Any(), d => dto.AreaCodes.Contains(d.AreaCode)) //区域
+            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, x => x.IsProvince == true)
+            .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, x => x.IsProvince == false)
+            .WhereIF(!string.IsNullOrEmpty(dto.SensitiveWord), x => SqlFunc.JsonArrayAny(x.Sensitive, dto.SensitiveWord))
+            .WhereIF(dto.IsSensitiveWord.HasValue && dto.IsSensitiveWord == true, x => x.Sensitive != null && SqlFunc.JsonArrayLength(x.Sensitive) > 0)
+            .OrderByDescending(d => d.CreationTime);
+    }
+
 
     #region private
 

+ 291 - 0
src/Hotline.Application/Orders/OrderSecondaryHandlingApplication.cs

@@ -0,0 +1,291 @@
+using DotNetCore.CAP;
+using Hotline.Application.FlowEngine;
+using Hotline.File;
+using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Orders;
+using Hotline.Settings.TimeLimits;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Order;
+using MapsterMapper;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using System.Threading;
+using Hotline.Repository.SqlSugar.Extensions;
+using XF.Domain.Authentications;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Orders
+{
+	public class OrderSecondaryHandlingApplication : IOrderSecondaryHandlingApplication, IScopeDependency
+	{
+		private readonly IMapper _mapper;
+		private readonly IRepository<OrderSecondaryHandling> _orderSecondaryHandlingRepository;
+		private readonly IFileRepository _fileRepository;
+		private readonly IRepository<OrderVisit> _orderVisitRepository;
+		private readonly ISessionContext _sessionContext;
+		private readonly IOrderRepository _orderRepository;
+		private readonly ITimeLimitDomainService _timeLimitDomainService;
+		private readonly ICapPublisher _capPublisher;
+		private readonly IWorkflowApplication _workflowApplication;
+		private readonly IRepository<OrderPublish> _orderPublishRepository;
+		private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
+		private readonly IWorkflowDomainService _workflowDomainService;
+		private readonly IRepository<OrderVisitDetail> _orderVisitedDetailRepository;
+
+		public OrderSecondaryHandlingApplication(
+			IMapper mapper,
+			IRepository<OrderSecondaryHandling> orderSecondaryHandlingRepository,
+			IFileRepository fileRepository,
+			IRepository<OrderVisit> orderVisitRepository,
+			ISessionContext sessionContext,
+			IOrderRepository orderRepository,
+			ITimeLimitDomainService timeLimitDomainService,
+			ICapPublisher capPublisher,
+			IWorkflowApplication workflowApplication,
+			IRepository<OrderPublish> orderPublishRepository,
+			IRepository<OrderPublishHistory> orderPublishHistoryRepository,
+			IWorkflowDomainService workflowDomainService,
+			IRepository<OrderVisitDetail> orderVisitedDetailRepository
+			) {
+			_mapper = mapper;
+			_orderSecondaryHandlingRepository = orderSecondaryHandlingRepository;
+			_fileRepository = fileRepository;
+			_orderVisitRepository = orderVisitRepository;
+			_sessionContext = sessionContext;
+			_orderRepository = orderRepository;
+			_timeLimitDomainService = timeLimitDomainService;
+			_capPublisher = capPublisher;
+			_workflowApplication = workflowApplication;
+			_orderPublishRepository = orderPublishRepository;
+			_orderPublishHistoryRepository = orderPublishHistoryRepository;
+			_workflowDomainService = workflowDomainService;
+			_orderVisitedDetailRepository = orderVisitedDetailRepository;
+		}
+
+		/// <summary>
+		///  二次办理新增
+		/// </summary>
+		/// <returns></returns>
+		public async Task AddAsync(AddOrderSecondaryHandlingDto dto, CancellationToken cancellationToken)
+		{
+			var model = _mapper.Map<OrderSecondaryHandling>(dto);
+			if (string.IsNullOrEmpty(dto.Id))
+			{
+				model.InitId();
+			}
+			else {
+				model = await _orderSecondaryHandlingRepository.GetAsync(dto.Id , cancellationToken);
+				model.Content = dto.Content;
+			}
+			model.State = ESecondaryHandlingState.Apply;
+			model.ApplyOrgId = _sessionContext.OrgId;
+			model.ApplyOrgName = _sessionContext.OrgName;
+		
+			if (dto.Files.Any())
+				model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", cancellationToken);
+
+			var visit = await _orderVisitRepository.GetAsync(x => x.Id  == dto.VisitId && x.VisitState != EVisitState.None, cancellationToken);
+			if (visit != null)
+			{
+				model.VisitState = visit.VisitState;
+				visit.VisitState = EVisitState.None;
+				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+			}
+
+			if (!string.IsNullOrEmpty(dto.Id))
+			{
+				await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+			}
+			else {
+				await _orderSecondaryHandlingRepository.AddAsync(model, cancellationToken);
+			}
+		}
+
+		public async Task SendBackAsync(SendBackOrderSecondaryHandlingDto dto, CancellationToken cancellationToken) 
+		{
+			var model =await _orderSecondaryHandlingRepository.GetAsync(dto.Id, cancellationToken);
+			model.State = ESecondaryHandlingState.NotApply;
+			model.SendBackContent = dto.SendBackContent;
+			model.AuditUser = _sessionContext.UserName;
+			model.AuditTime = DateTime.Now;
+			model.SendBackNum = model.SendBackNum is null ? 1 : model.SendBackNum + 1;
+			await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+			var visit = await _orderVisitRepository.GetAsync(x => x.Id == model.VisitId , cancellationToken);
+			if (visit != null)
+			{
+				visit.VisitState = model.VisitState;
+				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+			}
+		}
+
+
+		/// <summary>
+		/// 二次办理审批
+		/// </summary>
+		/// <returns></returns>
+		public async Task AuditAsync(AuditOrderSecondaryHandlingDto dto, OrderSecondaryHandling model, CancellationToken cancellationToken)
+		{
+			model.State = dto.State;
+			model.AuditContent = dto.AuditContent;
+			model.AuditId = _sessionContext.UserId;
+			model.AuditUser = _sessionContext.UserName;
+			model.AuditTime = DateTime.Now;
+			if (model.State == ESecondaryHandlingState.End)
+			{
+				var order = await _orderRepository.GetAsync(x => x.Id == model.OrderId, cancellationToken);
+				if (string.IsNullOrEmpty(order.WorkflowId))
+					throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程信息!");
+				var step = await _workflowDomainService.FindLastHandleStepAsync(order.WorkflowId, model.ApplyOrgId, cancellationToken);
+				if (step == null)
+					throw UserFriendlyException.SameMessage("无效二次办理审批信息,没有找到对应流程节点!");
+				var recall = new RecallDto
+				{
+					WorkflowId = order.WorkflowId!,
+					NextStepCode = step.Code,
+					NextStepName = step.Name,
+					NextHandlers = step.Handlers,
+					Opinion = dto.AuditContent,
+					FlowDirection = Share.Enums.FlowEngine.EFlowDirection.CenterToOrg,
+					HandlerType = step.HandlerType,
+					BusinessType = step.BusinessType
+				};
+				var expiredTime = _timeLimitDomainService.CalcEndTime(DateTime.Now, order.AcceptTypeCode);
+				await _orderRepository.Updateable().SetColumns(o => new Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime })
+					.Where(o => o.Id == order.Id).ExecuteCommandAsync(cancellationToken);
+				var orderDto = _mapper.Map<OrderDto>(order);
+				await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: cancellationToken);
+
+				await _workflowApplication.RecallAsync(recall, expiredTime.ExpiredTime, cancellationToken);
+				var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == model.OrderId);
+				if (publish != null)
+				{
+					var publishHistory = _mapper.Map<OrderPublishHistory>(publish);
+					publishHistory.OrderPublishId = publish.Id;
+					publishHistory.ArrangeTitleAfter = publish.ArrangeTitle;
+					publishHistory.ArrangeTitleBefor = publish.ArrangeTitle;
+					publishHistory.ArrangeContentAfter = publish.ArrangeContent;
+					publishHistory.ArrangeContentBefor = publish.ArrangeContent;
+					publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion;
+					publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion;
+					await _orderPublishHistoryRepository.AddAsync(publishHistory, cancellationToken);
+					await _orderPublishRepository.RemoveAsync(publish, false, cancellationToken);
+				}
+			}
+			else {
+				var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == model.OrderId, cancellationToken);
+				visit.VisitState = model.VisitState;
+				await _orderVisitRepository.UpdateAsync(visit, cancellationToken);
+			}
+			await _orderSecondaryHandlingRepository.UpdateAsync(model, cancellationToken);
+		}
+
+
+		/// <summary>
+		/// 获取申请列表
+		/// </summary>
+		/// <returns></returns>
+		public ISugarQueryable<OrderVisitDetail> ApplyQuery(MayScreenListDto dto, CancellationToken cancellationToken)
+		{
+			dto.CreationTimeEnd = DateTime.Now;
+			dto.CreationTimeStart = DateTime.Now;
+			if (dto.IsHomePage != null && dto.IsHomePage == true)
+			{
+				dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5);
+			}
+
+			var query = _orderVisitedDetailRepository.Queryable(false, true)
+				.Includes(x => x.OrderVisit)
+				.Includes(x => x.OrderVisit, y => y.Order)
+				.Includes(x => x.OrderVisit, y => y.Employee)
+				.Includes(x => x.SecondaryHandling)
+				.LeftJoin<OrderScreen>((x, s) => x.Id == s.VisitDetailId && s.Status < EScreenStatus.End && s.IsDeleted == false)
+				.Where((x, s) => s.Id == null && (x.SecondaryHandling.State == ESecondaryHandlingState.NotApply || x.SecondaryHandling.Id == null))
+				.WhereIF(dto.IsHomePage.HasValue && dto.IsHomePage == true, x => x.OrderVisit.VisitTime < dto.CreationTimeEnd && x.OrderVisit.VisitTime > dto.CreationTimeStart)
+				.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.OrderVisit.Order!.No!.Contains(dto.No!))
+				.WhereIF(dto.IsProvince.HasValue, x => x.OrderVisit.Order!.IsProvince == dto.IsProvince)
+				.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.OrderVisit.Order!.Title!.Contains(dto.Title!))
+				.WhereIF(!string.IsNullOrEmpty(dto.SourceChannel), x => x.OrderVisit.Order!.SourceChannelCode! == dto.SourceChannel!)
+				.WhereIF(!string.IsNullOrEmpty(dto.AcceptType), x => x.OrderVisit.Order!.AcceptTypeCode! == dto.AcceptType!)
+				.WhereIF(dto.CounterSignType.HasValue, x => x.OrderVisit.Order!.CounterSignType == dto.CounterSignType)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), x => x.OrderVisit.Order!.OrgLevelOneName!.Contains(dto.OrgLevelOneName!))
+				.WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), x => x.OrderVisit.Order!.ActualHandleOrgName!.Contains(dto.ActualHandleOrgName!))
+				.WhereIF(dto.ActualHandleTime.HasValue && dto.EndActualHandleTime.HasValue, x => x.OrderVisit.Order!.ActualHandleTime >= dto.ActualHandleTime && x.OrderVisit.Order!.ActualHandleTime <= dto.EndActualHandleTime)
+				.WhereIF(dto.FiledTime.HasValue && dto.EndFiledTime.HasValue, x => x.OrderVisit.Order!.FiledTime == dto.FiledTime && x.OrderVisit.Order!.FiledTime <= dto.EndFiledTime)
+				.WhereIF(dto.CreationTime.HasValue && dto.EndCreationTime.HasValue, x => x.OrderVisit.Order!.CreationTime == dto.CreationTime && x.OrderVisit.Order!.CreationTime <= dto.EndCreationTime)
+				.WhereIF(dto.VisitTime.HasValue && dto.EndVisitTime.HasValue, x => x.OrderVisit.VisitTime == dto.VisitTime && x.OrderVisit.VisitTime <= dto.EndVisitTime)
+				.WhereIF(!string.IsNullOrEmpty(dto.VisitOrgName), x => x.VisitOrgName!.Contains(dto.VisitOrgName!))
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgProcessingResults), x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == dto.OrgProcessingResults)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgHandledAttitude), x => SqlFunc.JsonListObjectAny(x.OrgHandledAttitude, "Key", dto.OrgHandledAttitude))
+				.WhereIF(!string.IsNullOrEmpty(dto.OrgNoSatisfiedReason), x => SqlFunc.JsonField(x.OrgNoSatisfiedReason, "Key") == dto.OrgNoSatisfiedReason)
+				.Where((x, s) => x.OrderVisit.VisitState != EVisitState.None && x.OrderVisit.IsCanHandle)
+				.Where((x, s) => x.OrderVisit.Order.CounterSignType == null && x.OrderVisit.Order.ActualHandleOrgCode == _sessionContext.OrgId)
+				;
+			if (_sessionContext.OrgId != null && !_sessionContext.OrgIsCenter)
+			{
+				query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+						(x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
+								  x.OrderVisit.Order.No.Contains(dto.Keyword!))
+					.Where((x, s) => x.VisitTarget == EVisitTarget.Org && x.VisitOrgCode.StartsWith(_sessionContext.OrgId) && (
+						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
+						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
+						SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
+						SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
+					));
+			}
+			else
+			{
+				query.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+						(x, s) => x.OrderVisit.Order.Title.Contains(dto.Keyword!) ||
+								  x.OrderVisit.Order.No.Contains(dto.Keyword!))
+					.Where((x, s) => x.VisitTarget == EVisitTarget.Org && (
+						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" ||
+						SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2" ||
+						SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "1" ||
+						SqlFunc.JsonField(x.OrgHandledAttitude, "Key") == "2"
+					));
+			}
+
+			return query.OrderByDescending((x, s) => x.CreationTime);
+		}
+
+		/// <summary>
+		/// 二次办理列表查询
+		/// </summary>
+		/// <returns></returns>
+		public ISugarQueryable<OrderSecondaryHandling> Query(SecondaryHandlingListDto dto, CancellationToken cancellationToken)
+		{
+			return _orderSecondaryHandlingRepository.Queryable()
+				.Includes(x => x.Order)
+				.Includes(x => x.VisitDetail)
+				.Includes(x => x.Visit, d => d.Order)
+				.Where(x=>x.State> ESecondaryHandlingState.NotApply)
+				.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+					x => x.Visit.Order.Title.Contains(dto.Keyword!) || x.Visit.Order.No.Contains(dto.Keyword!))
+				.WhereIF(dto.Status is ESecondaryHandlingState.Apply, x => x.State == ESecondaryHandlingState.Apply)
+				.WhereIF(dto.Status is ESecondaryHandlingState.Handled, x => x.State != ESecondaryHandlingState.Apply)
+				.WhereIF(dto.Status is ESecondaryHandlingState.End, x => x.State == ESecondaryHandlingState.End)
+				.WhereIF(dto.Status is ESecondaryHandlingState.Refuse, x => x.State == ESecondaryHandlingState.Refuse)
+				.WhereIF(dto.CreationTimeStart.HasValue, x => x.CreationTime >= dto.CreationTimeStart)
+				.WhereIF(dto.CreationTimeEnd.HasValue, x => x.CreationTime <= dto.CreationTimeEnd)
+				.WhereIF(!string.IsNullOrEmpty(dto.OrderId), x => x.OrderId == dto.OrderId)
+				.OrderByDescending(x => x.CreationTime);
+		}
+
+		/// <summary>
+		/// 获取实体
+		/// </summary>
+		/// <returns></returns>
+		public async Task<OrderSecondaryHandling> Entity(string id, CancellationToken cancellationToken)
+		{
+			return await _orderSecondaryHandlingRepository.Queryable()
+				.FirstAsync(x => x.Id == id, cancellationToken);
+		}
+
+	}
+}

+ 80 - 28
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -1,12 +1,15 @@
 using DotNetCore.CAP;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.Quality;
-using Hotline.Orders;
 using Hotline.File;
 using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
+using Hotline.OrderTranspond;
+using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.DataSharing.PusherHotlineDto;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.OrderTranspond;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Quality;
 using Hotline.Share.Mq;
@@ -15,11 +18,6 @@ using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
-using System.Security.Permissions;
-using MediatR;
-using Hotline.Settings;
-using Hotline.OrderTranspond;
-using Hotline.Share.Dtos.OrderTranspond;
 
 namespace Hotline.Application.Subscribers
 {
@@ -49,6 +47,7 @@ namespace Hotline.Application.Subscribers
         private readonly IRepository<SystemDicData> _systemDicDataRepository;
         private readonly ISystemOrganizeRepository _systemOrganizeRepository;
         private readonly IRepository<TranspondCityRawData> _transpondCityRawDataRepository;
+        private readonly IRepository<Workflow> _workflowRepository;
 
         public DataSharingSubscriber(
             IRepository<OrderVisit> orderVisitRepository,
@@ -70,7 +69,8 @@ namespace Hotline.Application.Subscribers
             IFileRepository fileRepository,
             IRepository<SystemDicData> systemDicDataRepository,
             ISystemOrganizeRepository systemOrganizeRepository,
-            IRepository<TranspondCityRawData> transpondCityRawDataRepository)
+            IRepository<TranspondCityRawData> transpondCityRawDataRepository,
+            IRepository<Workflow> workflowRepository)
         {
             _orderSendBackRepository = orderSendBackRepository;
             _workflowApplication = workflowApplication;
@@ -91,7 +91,7 @@ namespace Hotline.Application.Subscribers
             _systemDicDataRepository = systemDicDataRepository;
             _systemOrganizeRepository = systemOrganizeRepository;
             _transpondCityRawDataRepository = transpondCityRawDataRepository;
-
+            _workflowRepository = workflowRepository;
         }
 
         /// <summary>
@@ -105,18 +105,18 @@ namespace Hotline.Application.Subscribers
             {
                 sendBack.Result = dto.Result;
                 sendBack.Reason = dto.Reason;
+                var order = await _orderRepository.GetAsync(sendBack.OrderId, cancellationToken);
+                order.Status = EOrderStatus.WaitForAccept;
+                await _orderRepository.UpdateAsync(order, cancellationToken);
                 if (dto.Result is 1)
                 {
-                    var order = await _orderRepository.GetAsync(sendBack.OrderId, cancellationToken);
-                    await _workflowApplication.JumpToEndAsync(order.WorkflowId, "省工单同意退回", null, cancellationToken: cancellationToken);
-                }
-                else
-                {
-                    var order = await _orderRepository.GetAsync(sendBack.OrderId, cancellationToken);
-                    order.Status = EOrderStatus.WaitForAccept;
-                    await _orderRepository.UpdateAsync(order, cancellationToken);
+                    if (!string.IsNullOrEmpty(order.WorkflowId))
+                    {
+                        await _workflowApplication.HandleToEndAsync(order.WorkflowId, "省工单同意退回", null, isProvince: true, cancellationToken: cancellationToken);
+                    }
                 }
             }
+            await _orderSendBackRepository.UpdateAsync(sendBack, cancellationToken);
         }
 
         /// <summary>
@@ -125,8 +125,13 @@ namespace Hotline.Application.Subscribers
         [CapSubscribe(Hotline.Share.Mq.EventNames.SharingOrderRevoke)]
         public async Task RecCancelOrderAsync(CancelOrderDto dto, CancellationToken cancellationToken)
         {
-            var order = await _orderRepository.GetAsync(dto.OrderId, cancellationToken);
-            await _workflowApplication.JumpToEndAsync(order.WorkflowId, dto.Opinion, null, cancellationToken: cancellationToken);
+            var order = await _orderRepository.GetAsync(p => p.ProvinceNo == dto.ProvinceNo, cancellationToken);
+            if (!string.IsNullOrEmpty(order.WorkflowId))
+                await _workflowApplication.HandleToEndAsync(order.WorkflowId, dto.Opinion, null, isProvince: true, cancellationToken: cancellationToken);
+            else
+            {
+
+            }
         }
 
         /// <summary>
@@ -136,21 +141,68 @@ namespace Hotline.Application.Subscribers
         public async Task RecOrderUrgeAsync(ProvinceOrderUrgeDto dto, CancellationToken cancellationToken)
         {
             var order = await _orderRepository.Queryable().Where(x => x.ProvinceNo == dto.CaseSerial).FirstAsync(cancellationToken);
-            var org = await _workflowDomainService.FindActualHandlerAsync(order.WorkflowId, cancellationToken);
             var model = new OrderUrge();
             model.InitId();
-            model.OrgId = org.Key;
-            model.OrgName = org.Value;
             model.State = 0;
             model.CreatorOrgName = "省12345";
             model.CrUser = dto.RemindName;
             model.ApplyContent = dto.RemindReasion;
+            model.OrderId = order.Id;
+            model.OrgId = "001";
+            model.OrgName = "热线中心";
+            model.ApplyContent = dto.RemindReasion;
+
+            if (!string.IsNullOrEmpty(order.WorkflowId))
+            {
+                var org = await _workflowDomainService.FindActualHandlerAsync(order.WorkflowId, cancellationToken);
+                if (org != null)
+                {
+                    model.OrgId = org.Key;
+                    model.OrgName = org.Value;
+                }
+            }
+
+
             if (dto.Files.Any())
                 model.FileJson =
                     await _fileRepository.AddFileAsync(dto.Files, model.Id, "", cancellationToken);
             await _orderUrgeRepository.AddAsync(model, cancellationToken);
         }
 
+        /// <summary>
+        /// 服务工单预警---收到预警给当前办理部门发催办,如果没有办理部门直接催办中心
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        [CapSubscribe(Hotline.Share.Mq.EventNames.SharingOrderWarning)]
+        public async Task RecWarnInfoAsync(WarningDto dto, CancellationToken cancellationToken)
+        {
+            var order = await _orderRepository.Queryable().Where(x => x.ProvinceNo == dto.CaseSerial).FirstAsync(cancellationToken);
+            var model = new OrderUrge();
+            model.InitId();
+            model.State = 0;
+            model.CreatorOrgName = "省12345";
+            model.CrUser = "省12345";
+            model.ApplyContent = dto.WarnRulename + "    " + dto.WarnDescribe;
+            model.OrderId = order.Id;
+            model.ReplyLimitTime = dto.WarnTimebf;
+            model.OrgId = "001";
+            model.OrgName = "热线中心";
+
+            if (!string.IsNullOrEmpty(order.WorkflowId))
+            {
+                var org = await _workflowDomainService.FindActualHandlerAsync(order.WorkflowId, cancellationToken);
+                if (org != null)
+                {
+                    model.OrgId = org.Key;
+                    model.OrgName = org.Value;
+                }
+            }
+
+            await _orderUrgeRepository.AddAsync(model, cancellationToken);
+        }
+
         /// <summary>
         /// 督办工单派发接口
         /// </summary>
@@ -158,7 +210,7 @@ namespace Hotline.Application.Subscribers
         public async Task RecOrderSuperviseAsync(ProvinceSendOrderSuperviseDto dto, CancellationToken cancellationToken)
         {
             var order = await _orderRepository.Queryable().Where(x => x.ProvinceNo == dto.ProvinceOrderSuperviseDto!.CaseSerial).FirstAsync(cancellationToken);
-            var org = await _systemOrganizeRepository.GetAsync(x => x.Name == dto.ProvinceOrderSuperviseDto!.SuperviseRsvDept, cancellationToken);
+            var org = await _systemOrganizeRepository.GetAsync(x => x.Id == order.ActualHandleOrgCode, cancellationToken);
             var model = new OrderSupervise();
             model.InitId();
             model.OrderId = order.Id;
@@ -184,8 +236,8 @@ namespace Hotline.Application.Subscribers
         {
             var order = await _orderRepository.Queryable().Where(x => x.ProvinceNo == dto.ProvinceScreenResult!.CaseSerial).FirstAsync(cancellationToken);
             var orderScreen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == order.Id && x.Status == Share.Enums.Order.EScreenStatus.Approval).FirstAsync(cancellationToken);
-            await _workflowApplication.JumpToEndAsync(orderScreen.WorkflowId, "省上推送甄别结果", null, cancellationToken: cancellationToken);
-            orderScreen.Status = "1".Equals(dto.ProvinceScreenResult.AuditResult) ? Share.Enums.Order.EScreenStatus.End : Share.Enums.Order.EScreenStatus.Refuse;
+            await _workflowApplication.HandleToEndAsync(orderScreen.WorkflowId, "省上推送甄别结果", null, dto.ProvinceScreenResult.AuditResult ? Share.Enums.FlowEngine.EReviewResult.Approval : Share.Enums.FlowEngine.EReviewResult.Failed, isProvince: true, cancellationToken: cancellationToken);
+            orderScreen.Status = dto.ProvinceScreenResult.AuditResult ? Share.Enums.Order.EScreenStatus.End : Share.Enums.Order.EScreenStatus.Refuse;
             if (orderScreen.Status == Share.Enums.Order.EScreenStatus.End)
             {
                 var visitDetail = await _orderVisitedDetailRepository.GetAsync(orderScreen.VisitDetailId, cancellationToken);
@@ -356,7 +408,7 @@ namespace Hotline.Application.Subscribers
                                 VisitType = visit.VisitType,
                                 VisitName = visit.CreatorName,
                                 VisitTime = visit.VisitTime,
-                                VisitRemark = string.IsNullOrEmpty(first.VisitContent)? first.OrgProcessingResults?.Value: first.VisitContent,
+                                VisitRemark = string.IsNullOrEmpty(first.VisitContent) ? first.OrgProcessingResults?.Value : first.VisitContent,
                                 AreaCode = visit.Order.AreaCode!,
                                 SubjectResultSatifyCode = first.OrgProcessingResults.Key,
                                 FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
@@ -437,7 +489,7 @@ namespace Hotline.Application.Subscribers
             {
                 //查询延期
                 var orderDelay = await _orderDelayRepository.GetAsync(x => x.OrderId == order.Id && x.DelayState == EDelayState.Examining, cancellationToken);
-                await _workflowApplication.JumpToEndAsync(orderDelay.WorkflowId, dto.Opinion, null);
+                await _workflowApplication.HandleToEndAsync(orderDelay.WorkflowId, dto.Opinion, null, dto.IsPass ? Share.Enums.FlowEngine.EReviewResult.Approval : Share.Enums.FlowEngine.EReviewResult.Failed, isProvince: true, cancellationToken);
             }
         }
 
@@ -453,7 +505,7 @@ namespace Hotline.Application.Subscribers
             if (string.IsNullOrEmpty(order.WorkflowId))
                 throw new UserFriendlyException($"该工单未开启流程,orderId: {dto.OrderId}");
 
-            if (dto.Files.Any())
+            if (dto.Files != null && dto.Files.Any())
             {
                 order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, order.WorkflowId,
                     cancellationToken);
@@ -467,7 +519,7 @@ namespace Hotline.Application.Subscribers
                     break;
                 case "1":
                     //办结:归档
-                    await _workflowApplication.JumpToEndAsync(order.WorkflowId, dto.Opinion, dto.Files,
+                    await _workflowApplication.HandleToEndAsync(order.WorkflowId, dto.Opinion, dto.Files, isProvince: true,
                         cancellationToken: cancellationToken);
                     break;
             }

+ 36 - 1
src/Hotline.Application/Tels/TelApplication.cs

@@ -1,9 +1,13 @@
 using Hotline.Caching.Interfaces;
+using Hotline.CallCenter.Calls;
 using Hotline.CallCenter.Tels;
+using Hotline.Share.Enums.CallCenter;
 using Hotline.Users;
+using Microsoft.AspNetCore.Http;
 using XF.Domain.Cache;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
+using XF.Domain.Repository;
 
 namespace Hotline.Application.Tels;
 
@@ -13,17 +17,20 @@ public class TelApplication : ITelApplication, IScopeDependency
     private readonly ITelRestRepository _telRestRepository;
     private readonly ITypedCache<Work> _cacheWork;
     private readonly IWorkRepository _workRepository;
+    private readonly IRepository<TelActionRecord> _telActionRecordRepository;
 
     public TelApplication(
         IUserCacheManager userCacheManager,
         ITelRestRepository telRestRepository,
         ITypedCache<Work> cacheWork,
-        IWorkRepository workRepository)
+        IWorkRepository workRepository,
+        IRepository<TelActionRecord> telActionRecordRepository)
     {
         _userCacheManager = userCacheManager;
         _telRestRepository = telRestRepository;
         _cacheWork = cacheWork;
         _workRepository = workRepository;
+        _telActionRecordRepository = telActionRecordRepository;
     }
 
     /// <summary>
@@ -45,6 +52,20 @@ public class TelApplication : ITelApplication, IScopeDependency
         await _workRepository.UpdateAsync(work, cancellationToken);
         _cacheWork.Remove(work.GetKey(KeyMode.UserId));
         _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
+
+        var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
+        if (telAction != null)
+        {
+            telAction.EndAction();
+            await _telActionRecordRepository.UpdateAsync(telAction);
+        }
+
+        var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
+        if (telarrangeAction != null)
+        {
+            telarrangeAction.EndAction();
+            await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+        }
     }
 
     public async Task SignOutByTelNoAsync(string telNo,CancellationToken cancellationToken)
@@ -63,5 +84,19 @@ public class TelApplication : ITelApplication, IScopeDependency
         await _workRepository.UpdateAsync(work, cancellationToken);
         _cacheWork.Remove(work.GetKey(KeyMode.UserId));
         _cacheWork.Remove(work.GetKey(KeyMode.TelNo));
+
+        var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, cancellationToken);
+        if (telAction != null)
+        {
+            telAction.EndAction();
+            await _telActionRecordRepository.UpdateAsync(telAction);
+        }
+
+        var telarrangeAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.CallEndArrange && !x.EndTime.HasValue, cancellationToken);
+        if (telarrangeAction != null)
+        {
+            telarrangeAction.EndAction();
+            await _telActionRecordRepository.UpdateAsync(telarrangeAction);
+        }
     }
 }

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

@@ -125,7 +125,7 @@ namespace Hotline.Repository.SqlSugar.Orders
                        .Select(p => new DepartmentalProcessingStatisticsDataDto
                        {
                            OrgCode = p.OrgCode,
-                           OrderCountNum = SqlFunc.AggregateSum(p.OrderCountNum),
+                         //  OrderCountNum = SqlFunc.AggregateSum(p.OrderCountNum),
                            YBOrderCountNum = SqlFunc.AggregateSum(p.YBOrderCountNum),
                            ZBOrderCountNum = SqlFunc.AggregateSum(p.ZBOrderCountNum),
                            Archived = SqlFunc.AggregateSum(p.Archived),

+ 12 - 0
src/Hotline.Repository.SqlSugar/System/SystemOrganizeRepository.cs

@@ -2,6 +2,7 @@
 using Hotline.SeedData;
 using Hotline.Settings;
 using SqlSugar;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
 
 namespace Hotline.Repository.SqlSugar.System
@@ -21,6 +22,17 @@ namespace Hotline.Repository.SqlSugar.System
             return list;
         }
 
+        public async Task<IReadOnlyList<SystemOrganize>> GetOrgJsonForUser(string orgCode)
+        {
+            var list = await Db.Queryable<SystemOrganize>()
+                .Where(it => it.Id.StartsWith(orgCode))
+                .OrderBy(d => d.Id)
+                .ToTreeAsync(it => it.Children, it => it.ParentId, orgCode.Length > 6 ? orgCode.Substring(0, orgCode.Length - 3) : null);
+            return list;
+        }
+
+
+
         public async Task<IReadOnlyList<SystemOrganize>> GetCanUseOrg()
         {
             var list = await Db.Queryable<SystemOrganize>()

+ 1 - 1
src/Hotline.Share/Dtos/DataSharing/PusherHotlineDto/CancelOrderDto.cs

@@ -14,7 +14,7 @@ namespace Hotline.Share.Dtos.DataSharing.PusherHotlineDto
         /// <summary>
         /// 工单Id
         /// </summary>
-        public string OrderId { get; set; }
+        public string ProvinceNo { get; set; }
 
         /// <summary>
         /// 意见

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

@@ -107,6 +107,11 @@ namespace Hotline.Share.Dtos.FlowEngine.Workflow
         /// </summary>
         public DateTime? ActualHandleTime { get; set; }
 
+        /// <summary>
+        /// 实际办理节点名称(会签状态此字段保存最外层会签发起节点名称)
+        /// </summary>
+        public string? ActualHandleStepName { get; set; }
+
 	}
 
     public class WorkflowAssignDto

+ 44 - 0
src/Hotline.Share/Dtos/Order/ExportExcelDto.cs

@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Order
+{
+    public record ExportExcelDto<TQueryDto>
+    {
+        /// <summary>
+        /// 查询参数
+        /// </summary>
+        public TQueryDto QueryDto { get; set; }
+
+        /// <summary>
+        /// 导出列信息
+        /// </summary>
+        public List<ColumnInfo> ColumnInfos { get; set; }
+
+        /// <summary>
+        /// 是否全量导出
+        /// </summary>
+        public bool IsExportAll { get; set; }
+    }
+
+    public class ColumnInfo
+    {
+        /// <summary>
+        /// 字段名称
+        /// </summary>
+        public string Prop { get; set; }
+
+        /// <summary>
+        /// 表头展示名称
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 排序
+        /// </summary>
+        public int Sort { get; set; }
+    }
+}

+ 26 - 22
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -30,7 +30,7 @@ namespace Hotline.Share.Dtos.Order
         /// 过期状态
         /// </summary>
         public string ExpiredStatusText => ExpiredStatus?.GetDescription() ?? string.Empty;
-            
+
         /// <summary>
         /// 处理方式(直办、交办)
         /// </summary>
@@ -425,14 +425,18 @@ namespace Hotline.Share.Dtos.Order
         public string? RecordingBaseAddress { get; set; }
         public string? RecordingAbsolutePath { get; set; }
 
-        public int? ReTransactNum { get; set; }
+        public int ReTransactNum { get; set; }
 
         /// <summary>
         /// 敏感标签
         /// </summary>
         public List<string>? Sensitive { get; set; }
 
-	}
+        public string? SensitiveText => (Sensitive != null && Sensitive.Any()) ? string.Join(',', Sensitive) : "";
+
+        public string IsProvinceText => IsProvince ? "省工单" : "市工单";
+
+    }
 
     public class UpdateOrderDto : AddOrderDto
     {
@@ -684,28 +688,28 @@ namespace Hotline.Share.Dtos.Order
 
         public ETimeType? TimeLimitUnit { get; set; }
 
-		#endregion
+        #endregion
 
-		#region 市州工单互转
-		/// <summary>
-		/// 是否转发
-		/// </summary>
-		public bool? Transpond { get; set; }
+        #region 市州工单互转
+        /// <summary>
+        /// 是否转发
+        /// </summary>
+        public bool? Transpond { get; set; }
 
-		/// <summary>
-		/// 转发市州Id
-		/// </summary>
-		public string? TranspondCityId { get; set; }
+        /// <summary>
+        /// 转发市州Id
+        /// </summary>
+        public string? TranspondCityId { get; set; }
 
-		/// <summary>
-		/// 转发市州名称
-		/// </summary>
-		public string? TranspondCityName { get; set; }
+        /// <summary>
+        /// 转发市州名称
+        /// </summary>
+        public string? TranspondCityName { get; set; }
 
-		/// <summary>
-		/// 转发市州Value
-		/// </summary>
-		public string? TranspondCityValue { get; set; }
+        /// <summary>
+        /// 转发市州Value
+        /// </summary>
+        public string? TranspondCityValue { get; set; }
         #endregion
 
         /// <summary>
@@ -714,7 +718,7 @@ namespace Hotline.Share.Dtos.Order
         public bool? IsEnforcementOrder { get; set; }
     }
 
-	public record CanLinkCallRecordOrderDto : PagedKeywordRequest
+    public record CanLinkCallRecordOrderDto : PagedKeywordRequest
     {
 
     }

+ 12 - 1
src/Hotline.Share/Dtos/Order/OrderScreenDto.cs

@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Order
@@ -114,6 +115,9 @@ namespace Hotline.Share.Dtos.Order
 		/// </summary>
 		public OrderDto Order { get; set; }
 
+
+		public WorkflowDto Workflow { get; set; }
+
 		/// <summary>
 		/// 回访明细id
 		/// </summary>
@@ -201,6 +205,13 @@ namespace Hotline.Share.Dtos.Order
 		public List<FileJson>? FileJson { get; set; } = new();
 
 		public List<FileDto> Files { get; set; }
+
+		/// <summary>
+		/// 甄别耗时
+		/// </summary>
+		public decimal? TimeConsuming { get; set; }
+
+		public string TimeConsuminText => TimeConsuming.HasValue ? TimeConsuming.ToString() + "天" : "-";
 	}
 
 	public class PublishScreenDto {
@@ -229,7 +240,7 @@ namespace Hotline.Share.Dtos.Order
 		/// <summary>
 		/// 审核结果是否通过
 		/// </summary>
-		public string AuditResult { get; set; }
+		public bool AuditResult { get; set; }
 
 		/// <summary>
 		/// 审核意见

+ 201 - 0
src/Hotline.Share/Dtos/Order/OrderSecondaryHandlingDto.cs

@@ -0,0 +1,201 @@
+using Hotline.Share.Dtos.File;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Requests;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Utility.EnumExtensions;
+
+namespace Hotline.Share.Dtos.Order
+{
+	public class OrderSecondaryHandlingDto: OrderSecondaryHandlingBaseDto
+	{
+		/// <summary>
+		/// 工单ID
+		/// </summary>
+		public string OrderId { get; set; }
+
+		/// <summary>
+		/// 状态
+		/// </summary>
+		public ESecondaryHandlingState? State { get; set; }
+
+		public string StateText => State.GetDescription();
+
+		/// <summary>
+		/// 重提办理
+		/// </summary>
+		public int? SendBackNum { get; set; }
+
+		public string SendBack => SendBackNum is > 0 ? "是" : "否";
+
+		/// <summary>
+		/// 申请理由
+		/// </summary>
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 退回意见
+		/// </summary>
+		public string? SendBackContent { get; set; }
+
+
+		/// <summary>
+		/// 审批意见
+		/// </summary>
+		public string? AuditContent { get; set; }
+
+		/// <summary>
+		/// 工单
+		/// </summary>
+		public OrderDto Order { get; set; }
+
+		/// <summary>
+		/// 回访
+		/// </summary>
+		public OrderVisitDetailDto VisitDetail { get; set; }
+
+		/// <summary>
+		/// 回访
+		/// </summary>
+		public OrderVisitDto Visit { get; set; }
+
+		/// <summary>
+		/// 审批人ID
+		/// </summary>
+		public string? AuditId { get; set; }
+
+		public string? AuditUser { get; set; }
+
+		/// <summary>
+		/// 审批时间
+		/// </summary>
+		public DateTime? AuditTime { get; set; }
+
+		/// <summary>
+		/// 申请部门ID
+		/// </summary>
+		public string ApplyOrgId { get; set; }
+
+		/// <summary>
+		/// 申请部门名称
+		/// </summary>
+		public string ApplyOrgName { get; set; }
+
+		/// <summary>
+		/// 附件列表
+		/// </summary>
+		public List<FileDto> Files { get; set; } = new();
+
+	}
+
+	public class AddOrderSecondaryHandlingDto {
+
+		public string Id { get; set; }
+
+		/// <summary>
+		/// 工单ID
+		/// </summary>
+		public string OrderId { get; set; }
+
+		/// <summary>
+		/// 回访id
+		/// </summary>
+		public string VisitId { get; set; }
+
+		/// <summary>
+		/// 回访明细id
+		/// </summary>
+		public string VisitDetailId { get; set; }
+
+		/// <summary>
+		/// 申请理由
+		/// </summary>
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 附件列表
+		/// </summary>
+		public List<FileDto> Files { get; set; } = new();
+
+		public List<FileJson>? FileJson { get; set; }
+	}
+
+	public class AuditOrderSecondaryHandlingDto
+	{
+		public string Id { get; set; }
+		/// <summary>
+		/// 状态
+		/// </summary>
+		public ESecondaryHandlingState? State { get; set; }
+
+
+		/// <summary>
+		/// 审批意见
+		/// </summary>
+		public string? AuditContent { get; set; }
+
+		public List<string> Ids { get; set; }
+	}
+
+	public class SendBackOrderSecondaryHandlingDto
+	{
+		public string Id { get; set; }
+
+		/// <summary>
+		/// 退回意见
+		/// </summary>
+		public string? SendBackContent { get; set; }
+	}
+
+	public class OrderSecondaryHandlingBaseDto
+	{
+		public DateTime? LastModificationTime { get; set; }
+
+		public bool IsDeleted { get; set; }
+
+		/// <summary>
+		/// 删除时间
+		/// </summary>
+		public DateTime? DeletionTime { get; set; }
+
+
+		/// <summary>
+		/// 创建时间
+		/// </summary>
+		public DateTime CreationTime { get; set; }
+
+		public string Id { get; set; }
+
+		/// <summary>
+		/// 组织Id
+		/// </summary>
+		public string? CreatorOrgId { get; set; }
+
+
+		public string? CreatorOrgName { get; set; }
+
+		/// <summary>
+		/// 创建人
+		/// </summary>
+		public string? CreatorId { get; set; }
+
+		public string? CreatorName { get; set; }
+	}
+
+	public record SecondaryHandlingListDto : PagedKeywordRequest
+	{
+		/// <summary>
+		/// 申请状态
+		/// </summary>
+		public ESecondaryHandlingState? Status { get; set; }
+
+		public DateTime? CreationTimeStart { get; set; }
+		public DateTime? CreationTimeEnd { get; set; }
+
+		public string? OrderId { get; set; }
+
+	}
+}

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

@@ -153,6 +153,11 @@ namespace Hotline.Share.Dtos.Order
 		public EBusinessType? BusinessType { get; set; } 
 
 	}
+
+	public class BatchAuditOrderSpecialDto :AuditOrderSpecialDto {
+
+		public List<string> ids { get; set; }
+	}
 	public class OrderSpecialDto : OrderSpecialBaseDto
 	{
 

+ 2 - 0
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -372,6 +372,8 @@ namespace Hotline.Share.Dtos.Order
 
         public OrderVisitDto OrderVisit { get; set; }
 
+        public OrderSecondaryHandlingDto SecondaryHandling { get; set; }
+
         public OrderDto Order => OrderVisit != null ? OrderVisit.Order : null;
 
         /// <summary>

+ 4 - 0
src/Hotline.Share/Dtos/Order/SendBackDto.cs

@@ -26,6 +26,10 @@ namespace Hotline.Share.Dtos.Order
 		public string? AuditContent { get; set; }
 
 	}
+
+	public class BatchAuditSendBackDto : AuditSendBackDto {
+		public List<string> Ids { get; set; }
+	}
 	public class SendBackDto : SendBackBaseDto
 	{
 		/// <summary>

+ 65 - 0
src/Hotline.Share/Dtos/TrCallCenter/TrTelDao.cs

@@ -715,4 +715,69 @@ namespace Hotline.Share.Dtos.TrCallCenter
     }
 
     #endregion
+
+    #region 坐席动作类型
+
+    public record TelActionListDto:PagedRequest
+    {
+        public string TelNo { get; set; }
+
+        public EActionType? ActionTtype { get; set; }
+
+        public string? UserName { get; set; }
+
+        public DateTime? StartTime { get; set; }
+
+        public DateTime? EndTime { get; set; }
+    }
+
+    public class TelActionListRep
+    {
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// 用户名称
+        /// </summary>
+        public string UserName { get; set; }
+
+        /// <summary>
+        /// 分机号
+        /// </summary>
+        public string TelNo { get; set; }
+
+        /// <summary>
+        /// 分机组
+        /// </summary>
+        public string QueueId { get; set; }
+
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public DateTime StartTime { get; set; }
+
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 动作类型
+        /// </summary>
+        public EActionType ActionType { get; set; }
+
+        public string ActionTypeText => ActionType.GetDescription();
+
+        /// <summary>
+        /// 用时
+        /// </summary>
+        public double Duration { get; private set; }
+
+    }
+
+    #endregion
 }

+ 13 - 0
src/Hotline.Share/Dtos/Users/UserDto.cs

@@ -23,6 +23,9 @@ public record UserDto : AddUserDto
 
     public bool IsDeleted { get; set; }
 
+    public string? FullOrgName { get; set; }
+
+
     public IReadOnlyList<RoleDto> Roles { get; set; }
 
     public OrgDto Organization { get; set; }
@@ -57,6 +60,11 @@ public record AddUserDto
     /// </summary>
     public string? OrgId { get; set; }
 
+    /// <summary>
+    /// 部门全名
+    /// </summary>
+    public string? FullOrgName { get; set; }
+
     /// <summary>
     /// 用户类型
     /// </summary>
@@ -102,6 +110,11 @@ public record UpdateUserDto
     /// 部门Id
     /// </summary>
     public string? OrgId { get; set; }
+    
+    /// <summary>
+    /// 部门全名
+    /// </summary>
+    public string? FullOrgName { get; set; }
 
     /// <summary>
     /// 用户类型

+ 14 - 0
src/Hotline.Share/Enums/CallCenter/EActionType.cs

@@ -0,0 +1,14 @@
+using System.ComponentModel;
+
+
+namespace Hotline.Share.Enums.CallCenter
+{
+    public enum EActionType
+    {
+        [Description("小休")]
+        TelRest = 0,
+
+        [Description("话后整理")]
+        CallEndArrange = 1,
+    }
+}

+ 6 - 0
src/Hotline.Share/Enums/FlowEngine/EWorkflowStepStatus.cs

@@ -24,4 +24,10 @@ public enum EWorkflowStepStatus
     /// </summary>
     [Description("已办理")]
     Handled = 2,
+
+    ///// <summary>
+    ///// 未办理,由结束会签结束掉
+    ///// </summary>
+    //[Description("已办理")]
+    //Terminal = 3,
 }

+ 43 - 0
src/Hotline.Share/Enums/Order/ESecondaryHandlingState.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Order
+{
+	public enum ESecondaryHandlingState
+	{
+
+		/// <summary>
+		/// 待申请
+		/// </summary>
+		[Description("待申请")]
+		NotApply = 0,
+
+		/// <summary>
+		/// 待办
+		/// </summary>
+		[Description("待办")]
+		Apply = 1,
+
+		/// <summary>
+		/// 审批通过
+		/// </summary>
+		[Description("审批通过")]
+		End = 2,
+
+		/// <summary>
+		/// 审批拒绝
+		/// </summary>
+		[Description("审批拒绝")]
+		Refuse = 3,
+
+		/// <summary>
+		/// 已办理
+		/// </summary>
+		[Description("已办理")]
+		Handled = 4,
+	}
+}

+ 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.67</Version>
+    <Version>1.0.70</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 2 - 2
src/Hotline.Share/Requests/DepartmentalProcessingStatisticsDto.cs

@@ -46,7 +46,7 @@ namespace Hotline.Share.Requests
         /// <summary>
         /// 信件总量
         /// </summary>
-        public int OrderCountNum { get; set; }
+        public int OrderCountNum => YBOrderCountNum + ZBOrderCountNum;
 
         /// <summary>
         /// 信件已办总量
@@ -61,7 +61,7 @@ namespace Hotline.Share.Requests
         /// <summary>
         /// 按时办结
         /// </summary>
-       public int CompleteOnTime { get; set; }
+        public int CompleteOnTime { get; set; }
 
         /// <summary>
         /// 按时办结率

+ 71 - 0
src/Hotline/CallCenter/Calls/TelActionRecord.cs

@@ -0,0 +1,71 @@
+using Hotline.Share.Enums.CallCenter;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.CallCenter.Calls
+{
+    public class TelActionRecord: CreationEntity
+    {
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public string UserId { get; set; }
+
+        /// <summary>
+        /// 用户名称
+        /// </summary>
+        public string UserName { get; set; }
+
+        /// <summary>
+        /// 分机号
+        /// </summary>
+        public string TelNo { get; set; }
+
+        /// <summary>
+        /// 分机组
+        /// </summary>
+        public string QueueId { get; set; }
+
+        /// <summary>
+        /// 开始时间
+        /// </summary>
+        public DateTime StartTime { get; set; }
+
+        /// <summary>
+        /// 结束时间
+        /// </summary>
+        public DateTime? EndTime { get; set; }
+
+        /// <summary>
+        /// 动作类型
+        /// </summary>
+        public EActionType ActionType { get; set; }
+
+        /// <summary>
+        /// 用时
+        /// </summary>
+        
+        public double Duration { get; private set; }
+
+        public TelActionRecord()
+        {
+            
+        }
+
+        public TelActionRecord(string userId,string userName,string telNo,string queueId,EActionType actionType)
+        {
+            UserId = userId;UserName = userName;TelNo = telNo;QueueId = queueId;ActionType = actionType;StartTime = DateTime.Now;
+        }
+
+
+        public void EndAction()
+        {
+            EndTime = DateTime.Now;
+            Duration = Math.Round((EndTime.Value - StartTime).TotalSeconds,2);
+        }
+    }
+}

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

@@ -102,7 +102,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 结束流程(流程直接流转至结束节点)
         /// </summary>
         Task<WorkflowTrace> EndAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine endStepDefine,
-            WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown,
+            WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown,bool isProvince = false,
             CancellationToken cancellationToken = default);
 
         StepDefine GetStepDefine(WorkflowDefinition workflowDefinition, string stepCode);
@@ -229,5 +229,11 @@ namespace Hotline.FlowEngine.Workflows
         /// 更新未办理节点的期满时间
         /// </summary>
         Task UpdateUnhandleExpiredTimeAsync(string workflowId, DateTime expiredTime, CancellationToken cancellation);
+
+        /// <summary>
+        /// 查询该部门最后办理节点
+        /// </summary>
+        /// <returns></returns>
+        Task<WorkflowStep> FindLastHandleStepAsync(string workflowId, string orgId, CancellationToken cancellation);
     }
 }

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

@@ -363,17 +363,20 @@ public abstract class StepBasicEntity : CreationEntity
         AcceptorOrgAreaCode = orgAreaCode;
         AcceptorOrgAreaName = orgAreaName;
         AcceptTime = DateTime.Now;
+        Status = EWorkflowStepStatus.WaitForHandle;
     }
 
     public void Handle(
         string userId, string? userName,
         string orgId, string? orgName,
         string? orgAreaCode, string? orgAreaName,
-        bool orgIsCenter, string opinion)
+        bool orgIsCenter, string opinion,
+        string? nextStepCode = null)
     {
         if (!HasAccepted())
             Accept(userId, userName, orgId, orgName, orgAreaCode, orgAreaName);
 
+        Status = EWorkflowStepStatus.Handled;
         HandlerId = userId;
         HandlerName = userName;
         HandlerOrgId = orgId;
@@ -389,7 +392,21 @@ public abstract class StepBasicEntity : CreationEntity
         ExpiredStatus = HandleTime > StepExpiredTime
             ? EExpiredStatus.Expired
             : EExpiredStatus.Normal;
+
+        if (!IsInCountersign()
+            && InstanceMode is EInstanceMode.Config
+            && StepType is not EStepType.End)
+        {
+            var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
+            if (step != null)
+                step.Selected = true;
+        }
     }
 
+    /// <summary>
+    /// 是否处于会签流程中(不包含顶层发起会签节点)
+    /// </summary>
+    public bool IsInCountersign() => CountersignPosition != ECountersignPosition.None;
+
     #endregion
 }

+ 38 - 19
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -463,7 +463,7 @@ namespace Hotline.FlowEngine.Workflows
             if (nextStepDefine.StepType is EStepType.End)
             {
                 var endTrace = await EndAsync(workflow, dto, nextStepDefine, currentStep, EReviewResult.Approval,
-                    cancellationToken);
+                    cancellationToken: cancellationToken);
                 return;
             }
 
@@ -727,8 +727,8 @@ namespace Hotline.FlowEngine.Workflows
                 .ToListAsync(cancellation);
 
             var orgs = handlers.Select(d => new Kv(d.OrgId, d.OrgName))
-				.DistinctBy(d => d.Key)
-				.ToList();
+                .DistinctBy(d => d.Key)
+                .ToList();
 
             return orgs;
             //var workflow = await GetWorkflowAsync(workflowId, withSteps: true, cancellationToken: cancellation);
@@ -762,6 +762,18 @@ namespace Hotline.FlowEngine.Workflows
                 .ExecuteCommandAsync();
         }
 
+        /// <summary>
+        /// 查询该部门最后办理节点
+        /// </summary>
+        /// <returns></returns>
+        public async Task<WorkflowStep> FindLastHandleStepAsync(string workflowId, string orgId, CancellationToken cancellation)
+        {
+            return await _workflowStepRepository.Queryable()
+                .Where(d => d.StepHandlers.Any(sh => sh.OrgId == orgId) && d.WorkflowId == workflowId)
+                .OrderByDescending(d => d.HandleTime)
+                .FirstAsync(cancellation);
+        }
+
         /// <summary>
         /// 查找当前会签内所有节点(含start,end)
         /// </summary>
@@ -980,7 +992,7 @@ namespace Hotline.FlowEngine.Workflows
 
             var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
             var endTrace = await EndAsync(workflow, dto, endStepDefine, currentStep, EReviewResult.Failed,
-                cancellationToken);
+                cancellationToken: cancellationToken);
 
             //await _mediator.Publish(new RejectNotify(workflow, dto), cancellationToken);
         }
@@ -1108,7 +1120,7 @@ namespace Hotline.FlowEngine.Workflows
 
             var basicDto = _mapper.Map<BasicWorkflowDto>(dto);
             var endTrace = await EndAsync(workflow, basicDto, endStepDefine, currentStep, EReviewResult.Unknown,
-                cancellationToken);
+                cancellationToken: cancellationToken);
 
             await _mediator.Publish(new CancelWorkflowNotify(workflow), cancellationToken);
         }
@@ -1167,18 +1179,22 @@ namespace Hotline.FlowEngine.Workflows
         /// 流程结束
         /// </summary>
         public async Task<WorkflowTrace> EndAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine endStepDefine,
-            WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown,
+            WorkflowStep currentStep, EReviewResult? reviewResult = EReviewResult.Unknown, bool isProvince = false,
             CancellationToken cancellationToken = default)
         {
+            string userId = isProvince ? "08daa5f2-1878-4cfa-8764-1244f0229994" : _sessionContext.RequiredOrgId;
+            string userName = isProvince ? "省平台" : _sessionContext.UserName;
+            string orgId = isProvince ? "001" : _sessionContext.RequiredOrgId;
+            string OrgName = isProvince ? "市民热线服务系统" : _sessionContext.OrgName;
+
             var endStepHandles = new List<WorkflowStepHandler>
             {
                 WorkflowStepHandler.Create(workflow.Id, workflow.ExternalId,
-                    EFlowAssignType.User, _sessionContext.RequiredUserId, _sessionContext.UserName,
-                    _sessionContext.RequiredOrgId, _sessionContext.OrgName)
+                    EFlowAssignType.User, userId, userName,orgId, OrgName)
             };
 
             //create endStep
-            var endStep = await CreateEndStepAsync(workflow, endStepDefine, currentStep, endStepHandles, cancellationToken);
+            var endStep = await CreateEndStepAsync(workflow, endStepDefine, currentStep, endStepHandles, cancellationToken, isProvince);
             workflow.Steps.Add(endStep);
 
             //update endTrace
@@ -1546,14 +1562,19 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// 办理节点(赋值节点的办理对象信息)
         /// </summary>
-        private void HandleStep(WorkflowStep step, string opinion, string nextStepCode)
+        private void HandleStep(WorkflowStep step, string opinion, string nextStepCode, bool isProvince = false)
         {
-            step.Handle(_sessionContext.RequiredUserId, _sessionContext.UserName,
-                _sessionContext.RequiredOrgId, _sessionContext.OrgName,
+            string userId = isProvince ? "08daa5f2-1878-4cfa-8764-1244f0229994" : _sessionContext.RequiredOrgId;
+            string userName = isProvince ? "省平台" : _sessionContext.UserName;
+            string orgId = isProvince ? "001" : _sessionContext.RequiredOrgId;
+            string OrgName = isProvince ? "市民热线服务系统" : _sessionContext.OrgName;
+
+            step.Handle(userId, userName,
+                orgId, OrgName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
                 _sessionContext.OrgIsCenter, opinion, nextStepCode);
 
-            var handler = step.FindActualHandler(_sessionContext.Roles, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
+            var handler = step.FindActualHandler(_sessionContext.Roles, userId, orgId);
             if (handler is not null)
                 handler.IsActualHandler = true;
         }
@@ -1702,7 +1723,6 @@ namespace Hotline.FlowEngine.Workflows
             return countersign;
         }
 
-
         private async Task JumpTraceAsync(string workflowId, RecallDto dto, CancellationToken cancellationToken)
         {
             //未办理的traces
@@ -1745,8 +1765,7 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private async Task<WorkflowTrace> PreviousTraceAsync(string workflowId, PreviousWorkflowDto dto,
-            WorkflowStep step,
-            CancellationToken cancellationToken)
+            WorkflowStep step, CancellationToken cancellationToken)
         {
             var trace = await GetWorkflowTraceAsync(workflowId, step.Id, cancellationToken);
             _mapper.Map(dto, trace);
@@ -1924,12 +1943,12 @@ namespace Hotline.FlowEngine.Workflows
             StepDefine endStepDefine,
             WorkflowStep prevStep,
             List<WorkflowStepHandler> stepHandlers,
-            CancellationToken cancellationToken)
+            CancellationToken cancellationToken, bool isProvince = false)
         {
             if (workflow.Steps.Any(d => d.StepType == EStepType.End))
                 throw UserFriendlyException.SameMessage("无法重复创建结束节点");
 
-            var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
+            var handler = new Kv { Key = _sessionContext.UserId, Value = _sessionContext.UserName };
 
             var step = CreateStep(workflow, endStepDefine, prevStep, null, new List<Kv> { handler },
                 stepHandlers, null, null, null, EWorkflowStepStatus.WaitForAccept,
@@ -1939,7 +1958,7 @@ namespace Hotline.FlowEngine.Workflows
             //    _sessionContext.RequiredOrgId, _sessionContext.OrgName,
             //    _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName);
 
-            HandleStep(step, "流程归档", string.Empty);
+            HandleStep(step, "流程归档", string.Empty, isProvince);
 
             await _workflowStepRepository.AddAsync(step, cancellationToken);
 

+ 35 - 36
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -32,43 +32,42 @@ public class WorkflowStep : StepBasicEntity
     ///// </summary>
     //public bool HasStartedCountersign() => !string.IsNullOrEmpty(StartCountersignId);
 
-    /// <summary>
-    /// 接办
-    /// </summary>
-    public void Accept(string userId, string? userName, string orgId, string? orgName, string? orgAreaCode,
-        string? orgAreaName)
-    {
-        AcceptorId = userId;
-        AcceptorName = userName;
-        AcceptorOrgId = orgId;
-        AcceptorOrgName = orgName;
-        AcceptorOrgAreaCode = orgAreaCode;
-        AcceptorOrgAreaName = orgAreaName;
-        AcceptTime = DateTime.Now;
-        Status = EWorkflowStepStatus.WaitForHandle;
-    }
+    ///// <summary>
+    ///// 接办
+    ///// </summary>
+    //public void Accept(string userId, string? userName, string orgId, string? orgName, string? orgAreaCode,
+    //    string? orgAreaName)
+    //{
+    //    AcceptorId = userId;
+    //    AcceptorName = userName;
+    //    AcceptorOrgId = orgId;
+    //    AcceptorOrgName = orgName;
+    //    AcceptorOrgAreaCode = orgAreaCode;
+    //    AcceptorOrgAreaName = orgAreaName;
+    //    AcceptTime = DateTime.Now;
+    //    Status = EWorkflowStepStatus.WaitForHandle;
+    //}
 
-    /// <summary>
-    /// 节点办理完成
-    /// </summary>
-    public void Handle(
-        string userId, string? userName,
-        string orgId, string? orgName,
-        string? orgAreaCode, string? orgAreaName,
-        bool orgIsCenter, string opinion, string nextStepCode)
-    {
-        base.Handle(userId, userName, orgId, orgName, orgAreaCode, orgAreaName, orgIsCenter, opinion);
-        Status = EWorkflowStepStatus.Handled;
-
-        if (!IsInCountersign()
-            && InstanceMode is EInstanceMode.Config
-            && StepType is not EStepType.End)
-        {
-            var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
-            if (step != null)
-                step.Selected = true;
-        }
-    }
+    ///// <summary>
+    ///// 节点办理完成
+    ///// </summary>
+    //public void Handle(
+    //    string userId, string? userName,
+    //    string orgId, string? orgName,
+    //    string? orgAreaCode, string? orgAreaName,
+    //    bool orgIsCenter, string opinion, string nextStepCode)
+    //{
+    //    base.Handle(userId, userName, orgId, orgName, orgAreaCode, orgAreaName, orgIsCenter, opinion);
+        
+    //    if (!IsInCountersign()
+    //        && InstanceMode is EInstanceMode.Config
+    //        && StepType is not EStepType.End)
+    //    {
+    //        var step = NextSteps.FirstOrDefault(d => d.Code == nextStepCode);
+    //        if (step != null)
+    //            step.Selected = true;
+    //    }
+    //}
 
     /// <summary>
     /// 会签结束

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

@@ -46,7 +46,7 @@ public class WorkflowStepHandler : CreationEntity
         return handler;
     }
 
-    public void Assign(EFlowAssignType assignType, string? userId, string? username,
+        public void Assign(EFlowAssignType assignType, string? userId, string? username,
         string? orgId, string? orgName, string? roleId, string? roleName)
     {
         FlowAssignType = assignType;

+ 1 - 1
src/Hotline/KnowledgeBase/KnowledgeDomainService.cs

@@ -47,7 +47,7 @@ namespace Hotline.KnowledgeBase
         /// <returns></returns>
         public async Task<Knowledge> KnowledgeInfo(string Id, CancellationToken cancellationToken)
         {
-            var know = await _knowledgeRepository.Queryable(false, false, false).Includes(x => x.Workflow).FirstAsync(p => p.Id == Id);
+            var know = await _knowledgeRepository.Queryable(false, false, false).Includes(x => x.Workflow).Includes(x=>x.SourceOrganize).FirstAsync(p => p.Id == Id);
             if (know is null)
                 throw UserFriendlyException.SameMessage("知识查询失败!");
             return know;

+ 7 - 0
src/Hotline/Orders/IOrderDomainService.cs

@@ -75,5 +75,12 @@ namespace Hotline.Orders
         /// <returns></returns>
         Task TriggerAverageOrder(CancellationToken cancellationToken);
 		#endregion
+		#region  工单校验- 交通类工单
+		/// <summary>
+		/// 工单校验  - 交通类工单
+		/// </summary>
+		/// <returns></returns>
+		Task<OrderValidation> OrderValidation(AddOrderDto dto, CancellationToken cancellationToken);
+		#endregion
 	}
 }

+ 6 - 2
src/Hotline/Orders/OrderDefaults.cs

@@ -16,6 +16,10 @@ namespace Hotline.Orders
             /// 派单池id(用作派单池的用户id)
             /// </summary>
             public const string SendPoolId = "08dc592a-ecce-4d32-88d0-03eeae3c41c6";
-        }
-    }
+
+            public const string TrafficTrunkNum = "12328";
+
+
+		}
+	}
 }

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

@@ -15,6 +15,7 @@ using Hotline.FlowEngine.Workflows;
 using Hotline.Schedulings;
 using Hotline.Users;
 using Hotline.Share.Dtos;
+using Hotline.Settings.Hotspots;
 
 namespace Hotline.Orders;
 
@@ -36,9 +37,10 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     private readonly IRepository<User> _userRepository;
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     private readonly IWorkflowDomainService _workflowDomainService;
+    private readonly IRepository<Hotspot> _hotspotRepository;
 
 
-    public OrderDomainService(
+	public OrderDomainService(
         IOrderRepository orderRepository,
         IRepository<OrderRedo> orderRedoRepository,
         IRepository<OrderPublish> orderPublishRepository,
@@ -55,7 +57,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         IRepository<User> userRepository,
         ISystemSettingCacheManager systemSettingCacheManager,
         IRepository<Scheduling> schedulingRepository,
-        IWorkflowDomainService workflowDomainService)
+        IWorkflowDomainService workflowDomainService,
+        IRepository<Hotspot> hotspotRepository)
     {
         _orderRepository = orderRepository;
         _orderRedoRepository = orderRedoRepository;
@@ -73,7 +76,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         _schedulingRepository = schedulingRepository;
         _systemSettingCacheManager = systemSettingCacheManager;
         _workflowDomainService = workflowDomainService;
-    }
+        _hotspotRepository = hotspotRepository;
+	}
 
     public async Task<Order> GetOrderAsync(string? orderId, bool withHotspot = false, bool withAcceptor = false,
         bool withExtension = false, CancellationToken cancellationToken = default)
@@ -302,17 +306,96 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
             }
         }
     }
-    #endregion
+	#endregion
+	#region  工单校验- 交通类工单
+
+	/// <summary>
+	/// 工单校验  - 交通类工单
+	/// </summary>
+	/// <returns></returns>
+	public async Task<OrderValidation> OrderValidation(AddOrderDto dto, CancellationToken cancellationToken) 
+    {
+        var valid = new OrderValidation { Validation = false, Result = "" };
+        var hotspot = await _hotspotRepository.GetAsync(dto.HotspotId, cancellationToken);
+        if (hotspot.TrunkNum.Equals(OrderDefaults.SourceChannel.TrafficTrunkNum))
+        {
+	        switch (dto.AcceptTypeCode)
+	        {
+                //投诉举报
+                case "30":
+                case "35":
+                    valid.Validation = dto.Title.Contains("意见") || dto.Title.Contains("建议") || dto.Title.Contains("信息") || dto.Title.Contains("咨询");
+                    valid.Validation = dto.Content.Contains("意见") || dto.Content.Contains("建议") || dto.Content.Contains("信息") || dto.Content.Contains("咨询");
+                    if (dto.Content.Length < 25)
+                    {
+	                    valid.Validation = true;
+	                    valid.Result = "保存失败,受理内容字数不足!";
+                    }
+					break;
+                // 意见
+                case "1":
+	                valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("信息") || dto.Title.Contains("咨询");
+	                valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("信息") || dto.Content.Contains("咨询");
+	                if (dto.Content.Length < 5)
+	                {
+		                valid.Validation = true;
+		                valid.Result = "保存失败,受理内容字数不足!";
+	                }
+					break;
+				//建议求助
+				case "15":
+                case "20":
+	                valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("信息") || dto.Title.Contains("咨询");
+	                valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("信息") || dto.Content.Contains("咨询");
+	                if (dto.Content.Length < 25)
+	                {
+		                valid.Validation = true;
+		                valid.Result = "保存失败,受理内容字数不足!";
+	                }
+					break;
+                // 咨询
+                case "10":
+	                valid.Validation = dto.Title.Contains("投诉") || dto.Title.Contains("举报") || dto.Title.Contains("意见") || dto.Title.Contains("建议");
+	                valid.Validation = dto.Content.Contains("投诉") || dto.Content.Contains("举报") || dto.Content.Contains("意见") || dto.Content.Contains("建议");
+                    if (dto.Content.Length < 5)
+                    {
+                        valid.Validation = true;
+                        valid.Result = "保存失败,受理内容字数不足!";
+					}
+					break;
+                // 表扬
+                case "25":
+	                if (dto.Content.Length < 25)
+	                {
+		                valid.Validation = true;
+		                valid.Result = "保存失败,受理内容字数不足!";
+	                }
+					break;
+                default:
+	                if (dto.Content.Length < 5)
+	                {
+		                valid.Validation = true;
+		                valid.Result = "保存失败,受理内容字数不足!";
+	                }
+					break;
+			}
+        }
 
-    #region SchedulingSendOrder
+        if (valid.Validation && string.IsNullOrEmpty(valid.Result))
+            valid.Result = "标题或受理内容出现限制词,请检查!";
+		return valid;
+	}
+	#endregion
 
+	#region SchedulingSendOrder
 
 
-    #endregion
 
-    #region private
+	#endregion
 
-    private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
+	#region private
+
+	private async Task<Order> GetOrderByFlowIdAsync(string workflowId, CancellationToken cancellationToken)
     {
         if (string.IsNullOrEmpty(workflowId))
             throw UserFriendlyException.SameMessage("无效流程编号");
@@ -384,4 +467,12 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 public class CacheOrderNO
 {
     public int TotalCount { get; set; }
+}
+
+public class OrderValidation 
+{
+    public bool Validation { get; set; }
+
+    public string Result { get; set; }
+
 }

+ 8 - 1
src/Hotline/Orders/OrderScreen.cs

@@ -103,5 +103,12 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
         public List<FileJson>? FileJson { get; set; }
 
-    }
+
+		/// <summary>
+		/// 甄别耗时
+		/// </summary>
+		[SugarColumn(ColumnDescription = "甄别耗时")]
+		public decimal? TimeConsuming { get; set; }
+
+	}
 }

+ 118 - 0
src/Hotline/Orders/OrderSecondaryHandling.cs

@@ -0,0 +1,118 @@
+using Hotline.Share.Dtos.File;
+using Hotline.Share.Enums.Order;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+	[Description("二次办理")]
+	public class OrderSecondaryHandling : FullStateEntity
+	{
+		/// <summary>
+		/// 工单ID
+		/// </summary>
+		[SugarColumn(ColumnDescription = "工单ID")]
+		public string OrderId { get; set; }
+
+
+		/// <summary>
+		/// 回访id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "回访id")]
+		public string VisitId { get; set; }
+
+		/// <summary>
+		/// 回访明细id
+		/// </summary>
+		[SugarColumn(ColumnDescription = "回访明细id")]
+		public string VisitDetailId { get; set; }
+
+		/// <summary>
+		/// 状态
+		/// </summary>
+		[SugarColumn(ColumnDescription = "状态")]
+		public ESecondaryHandlingState? State { get; set; }
+
+		/// <summary>
+		/// 重提办理
+		/// </summary>
+		public int? SendBackNum { get; set; }
+
+		/// <summary>
+		/// 申请理由
+		/// </summary>
+		[SugarColumn(ColumnDescription = "申请理由", ColumnDataType = "varchar(2000)")]
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 退回意见
+		/// </summary>
+		[SugarColumn(ColumnDescription = "退回意见", ColumnDataType = "varchar(2000)")]
+		public string? SendBackContent { get; set; }
+
+		/// <summary>
+		/// 审批意见
+		/// </summary>
+		[SugarColumn(ColumnDescription = "审批意见", ColumnDataType = "varchar(2000)")]
+		public string? AuditContent { get; set; }
+
+		/// <summary>
+		/// 工单
+		/// </summary>
+		[Navigate(NavigateType.OneToOne, nameof(OrderId))]
+		public Order Order { get; set; }
+
+
+		/// <summary>
+		/// 回访
+		/// </summary>
+		[Navigate(NavigateType.OneToOne, nameof(VisitDetailId))]
+		public OrderVisitDetail VisitDetail { get; set; }
+
+		/// <summary>
+		/// 回访
+		/// </summary>
+		[Navigate(NavigateType.OneToOne, nameof(VisitId))]
+		public OrderVisit Visit { get; set; }
+
+		/// <summary>
+		/// 审批人ID
+		/// </summary>
+		[SugarColumn(ColumnDescription = "审批人ID")]
+		public string? AuditId { get; set; }
+
+		[SugarColumn(ColumnDescription = "审批人")]
+		public string? AuditUser { get; set; }
+
+		/// <summary>
+		/// 审批时间
+		/// </summary>
+		public DateTime? AuditTime { get; set; }
+
+		/// <summary>
+		/// 申请部门ID
+		/// </summary>
+		[SugarColumn(ColumnDescription = "申请部门ID")]
+		public string ApplyOrgId { get; set; }
+
+		/// <summary>
+		/// 申请部门名称
+		/// </summary>
+		[SugarColumn(ColumnDescription = "申请部门名称")]
+		public string ApplyOrgName { get; set; }
+
+		[SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+		public List<FileJson>? FileJson { get; set; }
+
+		/// <summary>
+		/// 回访状态
+		/// </summary>
+		public EVisitState VisitState { get; set; }
+	}
+}

+ 8 - 2
src/Hotline/Orders/OrderVisitDetail.cs

@@ -1,5 +1,6 @@
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using SqlSugar;
 using XF.Domain.Repository;
@@ -19,9 +20,14 @@ namespace Hotline.Orders
         public OrderVisit OrderVisit { get; set; }
 
         /// <summary>
-        /// 语音评价(话务评价)
+        /// 通话记录
         /// </summary>
-        public EVoiceEvaluate? VoiceEvaluate { get; set; }
+        [Navigate(NavigateType.OneToOne, nameof(Id),nameof(OrderSecondaryHandling.VisitDetailId))]
+        public OrderSecondaryHandling SecondaryHandling { get; set; }
+		/// <summary>
+		/// 语音评价(话务评价)
+		/// </summary>
+		public EVoiceEvaluate? VoiceEvaluate { get; set; }
 
         /// <summary>
         /// 话务员评价(话务评价)

+ 40 - 4
src/Hotline/README.md

@@ -1,11 +1,11 @@
-#### 代码编写规范
+### 代码编写规范
 
-##### 1. 参照微软推荐编码规范及约定
+#### 1. 参照微软推荐编码规范及约定
 * https://docs.microsoft.com/zh-cn/dotnet/csharp/fundamentals/coding-style/identifier-names
 * https://docs.microsoft.com/zh-cn/dotnet/csharp/fundamentals/coding-style/coding-conventions
 * https://docs.microsoft.com/zh-cn/dotnet/standard/design-guidelines/naming-guidelines
 
-##### 2. 该项目扩展规范
+#### 2. 该项目扩展规范
 * 枚举:命名以大写E为前缀,在文件列表中可以一目了然
 * 方法命名方式:
 
@@ -17,4 +17,40 @@
 查询所有数据:QueryAllxxx  
 异步方法以Async为后缀:GetxxxAsync  
 * WebApi和Web项目的Action都尽量采用异步方法,但命名不加Async后缀(因为此处的调用方不以Action命名来调用,而是以路由规则来访问)
-* 字段以'_'加小写字母为前缀,如:_orderDomainService
+* 字段以'_'加小写字母为前缀,如:_orderDomainService
+
+### Git版本管理及使用规范
+
+#### Git分支
+
+master, hotfix, fix, dev, feature, release
+
+| 分支 | 说明 |
+|-----|------|
+| master | 项目主分支,任何人不得直接修改代码,除项目负责人外任何人不得向该分支合并内容 |
+| hotfix | 紧急bug修复分支,拉取自master |
+| fix | 非紧急bug修复分支,拉取自dev |
+| dev | 开发分支,开发环境共有分支,提供前后端对接环境 |
+| feature | 功能开发分支,一般拉取至dev |
+
+#### 分支命名规范
+
+前缀/功能
+
+如:hotfix/AddOrderError  feature/ExportExcel
+
+#### 代码提交规范
+
+add, del, mod, fix, refactor, optimize, style, doc
+
+#### 代码提交流程
+
+1. 代码修改以后,检查编码规范、注释以及进行单元测试等
+2. 测试通过后提交到本地,检查提交文件是否正确,有无遗漏,添加commit说明
+3. 拉取服务器代码,检查合并结果,解决冲突后重新编译测试通过后提交本地
+4. 推送代码至服务器
+
+#### 代码提交注意事项
+
+* 单次提交问题必须为同一功能,建议不超过3个内容
+* 提交得commit发现不符合规范,git commit --amend -m "新的提交信息"或 git reset --hard HEAD 重新提交一次

+ 5 - 1
src/Hotline/Settings/ISystemOrganizeRepository.cs

@@ -1,4 +1,5 @@
-using XF.Domain.Repository;
+using XF.Domain.Authentications;
+using XF.Domain.Repository;
 
 namespace Hotline.Settings
 {
@@ -7,6 +8,9 @@ namespace Hotline.Settings
     {
         Task<IReadOnlyList<SystemOrganize>> GetOrgJson();
 
+        Task<IReadOnlyList<SystemOrganize>> GetOrgJsonForUser(string orgCode);
+
+
         Task<IReadOnlyList<SystemOrganize>> GetCanUseOrg();
 
         Task<IReadOnlyList<SystemOrganize>> GetCanUseOrgByOrgCode(string orgCode);

+ 54 - 0
src/Hotline/Tools/DynamicClassHelper.cs

@@ -0,0 +1,54 @@
+using System.Reflection;
+using System.Reflection.Emit;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Order;
+using MiniExcelLibs.Attributes;
+using XF.Domain.Extensions;
+
+namespace Hotline.Tools;
+
+public class DynamicClassHelper
+{
+    public static Type CreateDynamicClass(List<ColumnInfo> propInfos)
+    {
+        string className = "DynamicClass";
+        AssemblyName assemblyName = new AssemblyName("DynamicAssembly");
+        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
+        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
+        TypeBuilder typeBuilder = moduleBuilder.DefineType(className, TypeAttributes.Public);
+
+        foreach (var property in propInfos)
+        {
+            var propertyName = property.Prop.Trim().ToPascalCase();
+            var propertyType = typeof(string);
+
+            FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
+            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
+
+            MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
+
+            MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + propertyName, getSetAttributes, propertyType, Type.EmptyTypes);
+            ILGenerator getIL = getMethodBuilder.GetILGenerator();
+            getIL.Emit(OpCodes.Ldarg_0);
+            getIL.Emit(OpCodes.Ldfld, fieldBuilder);
+            getIL.Emit(OpCodes.Ret);
+
+            MethodBuilder setMethodBuilder = typeBuilder.DefineMethod("set_" + propertyName, getSetAttributes, null, new Type[] { propertyType });
+            ILGenerator setIL = setMethodBuilder.GetILGenerator();
+            setIL.Emit(OpCodes.Ldarg_0);
+            setIL.Emit(OpCodes.Ldarg_1);
+            setIL.Emit(OpCodes.Stfld, fieldBuilder);
+            setIL.Emit(OpCodes.Ret);
+
+            propertyBuilder.SetGetMethod(getMethodBuilder);
+            propertyBuilder.SetSetMethod(setMethodBuilder);
+
+            var columnNameCtorInfo = typeof(ExcelColumnNameAttribute).GetConstructor(new Type[] { typeof(string), typeof(string[]) });
+            var attributeBuilder = new CustomAttributeBuilder(columnNameCtorInfo, new object[] { property.Name, null });
+            propertyBuilder.SetCustomAttribute(attributeBuilder);
+        }
+
+        Type generatedType = typeBuilder.CreateType();
+        return generatedType;
+    }
+}

+ 21 - 0
src/Hotline/Tools/ExcelHelper.cs

@@ -0,0 +1,21 @@
+using MiniExcelLibs;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mapster;
+
+namespace Hotline.Tools
+{
+    public class ExcelHelper
+    {
+        public static MemoryStream CreateStream(List<object> values)
+        {
+            var stream = new MemoryStream();
+            stream.SaveAs(values);
+            stream.Seek(0, SeekOrigin.Begin);
+            return stream;
+        }
+    }
+}

+ 4 - 0
src/Hotline/Users/User.cs

@@ -38,6 +38,10 @@ namespace Hotline.Users
         /// </summary>
         public string? OrgId { get; set; }
 
+        /// <summary>
+        /// 部门全称
+        /// </summary>
+        public string? FullOrgName { get; set; }
 
         /// <summary>
         /// 默认分机号

+ 28 - 0
src/XF.Domain/Extensions/StringExtensions.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 
 namespace XF.Domain.Extensions
@@ -10,6 +11,8 @@ namespace XF.Domain.Extensions
     {
         public static string ToSnakeCase(this string name)
         {
+            if (string.IsNullOrEmpty(name))
+                throw new ArgumentNullException(nameof(name));
             var sb = new StringBuilder();
             sb.Append(char.ToLower(name[0]));
             for (int i = 1; i < name.Length; i++)
@@ -26,5 +29,30 @@ namespace XF.Domain.Extensions
             }
             return sb.ToString();
         }
+
+        public static string UpperFirstChar(this string str)
+        {
+            if(string.IsNullOrEmpty(str))
+                throw new ArgumentNullException(nameof(str));
+            var firstChar = str[0];
+            if (char.IsUpper(firstChar))
+                return str;
+            firstChar = char.ToUpper(firstChar);
+            str = str.Remove(0, 1);
+            return str.Insert(0,firstChar.ToString());
+        }
+
+        public static string ToPascalCase(this string str)
+        {
+            if (string.IsNullOrEmpty(str))
+                throw new ArgumentNullException(nameof(str));
+            var array = str.Split('.', StringSplitOptions.TrimEntries);
+            var sb = new StringBuilder();
+            foreach (var item in array)
+            {
+                sb.Append(item.UpperFirstChar());
+            }
+            return sb.ToString();
+        }
     }
 }

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно