Quellcode durchsuchen

Merge branch 'dev' into test

# Conflicts:
#	src/Hotline/Settings/SettingConstants.cs
xf vor 5 Monaten
Ursprung
Commit
1baf1a37d0
31 geänderte Dateien mit 1274 neuen und 318 gelöschten Zeilen
  1. 141 76
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  2. 1 126
      src/Hotline.Api/Controllers/OrderController.cs
  3. 2 2
      src/Hotline.Api/config/appsettings.Development.json
  4. 10 5
      src/Hotline.Application.Tests/Controller/DefaultHttpContextAccessor.cs
  5. 116 20
      src/Hotline.Application.Tests/Controller/OrderControllerTest.cs
  6. 14 0
      src/Hotline.Application.Tests/Dto/CreateOrderOutDto.cs
  7. 0 4
      src/Hotline.Application.Tests/Hotline.Application.Tests.csproj
  8. 2 0
      src/Hotline.Application.Tests/Infrastructure/TestSettingConstants.cs
  9. 238 0
      src/Hotline.Application.Tests/Mock/OrderServiceMock.cs
  10. 4 0
      src/Hotline.Application.Tests/Startup.cs
  11. 24 13
      src/Hotline.Application.Tests/TestBase.cs
  12. 2 0
      src/Hotline.Application/FlowEngine/WorkflowApplication.cs
  13. 1 0
      src/Hotline.Application/Handlers/FlowEngine/WorkflowEndHandler.cs
  14. 4 0
      src/Hotline.Application/Hotline.Application.csproj
  15. 10 9
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  16. 9 1
      src/Hotline.Application/Orders/IOrderApplication.cs
  17. 133 17
      src/Hotline.Application/Orders/OrderApplication.cs
  18. 47 0
      src/Hotline.Repository.SqlSugar/System/SystemLogRepository.cs
  19. 10 0
      src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs
  20. 8 2
      src/Hotline.Share/Dtos/Order/OrderBiDto.cs
  21. 41 1
      src/Hotline.Share/Dtos/Order/OrderDto.cs
  22. 3 2
      src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs
  23. 128 0
      src/Hotline.Share/Dtos/WebPortal/GetCaseReultSendModel.cs
  24. 5 0
      src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs
  25. 32 1
      src/Hotline/Caching/Services/SystemSettingCacheManager.cs
  26. 28 28
      src/Hotline/FlowEngine/Workflows/Workflow.cs
  27. 2 2
      src/Hotline/Orders/IOrderDomainService.cs
  28. 30 4
      src/Hotline/Orders/Order.cs
  29. 205 2
      src/Hotline/Orders/OrderDomainService.cs
  30. 21 0
      src/Hotline/Settings/ISystemLogRepository.cs
  31. 3 3
      src/Hotline/Settings/SettingConstants.cs

+ 141 - 76
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -538,6 +538,121 @@ namespace Hotline.Api.Controllers.Bi
             return new PagedDto<HotspotDataLsitVo>(total, items);
         }
 
+        /// <summary>
+        /// 热点数据统计导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("hotspot_data_list/export")]
+        public async Task<FileStreamResult> HotspotDataLsitExprot([FromBody] ExportExcelDto<HotspotReportPagedRequest> dto)
+        {
+            if (!dto.QueryDto.StartTime.HasValue || !dto.QueryDto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
+            if (dto.QueryDto.Type == 0 && (!dto.QueryDto.ChainStartTime.HasValue || !dto.QueryDto.ChainEndTime.HasValue)) throw UserFriendlyException.SameMessage("请选择环比时间!");
+
+            dto.QueryDto.EndTime = dto.QueryDto.EndTime.Value.AddDays(1).AddSeconds(-1);
+
+            var IsCenter = _sessionContext.OrgIsCenter;
+
+            if (dto.QueryDto.Type == 0)
+            {
+                dto.QueryDto.ChainEndTime = dto.QueryDto.ChainEndTime.Value.AddDays(1).AddSeconds(-1);
+            }
+
+            var items = await _hotspotTypeRepository.Queryable(false, true)
+                .LeftJoin<Order>((x, o) => o.HotspotSpliceName != null && (x.HotSpotName == o.HotspotSpliceName || o.HotspotSpliceName.Contains(x.HotSpotName)) && o.IsDeleted == false)
+                .WhereIF(dto.QueryDto.StartTime.HasValue, (x, o) => o.CreationTime >= dto.QueryDto.StartTime)
+                .WhereIF(dto.QueryDto.EndTime.HasValue, (x, o) => o.CreationTime <= dto.QueryDto.EndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Keyword), (x, o) => x.HotSpotName.Contains(dto.QueryDto.Keyword!))
+                .WhereIF(IsCenter == false, (x, o) => o.ActualHandleOrgCode == _sessionContext.RequiredOrgId)
+                .Where((x, o) => x.ParentId == dto.QueryDto.Id)
+                .Where((x, o) => x.IsDeleted == false)
+                .GroupBy((x, o) => new { x.Id, x.HotSpotName })
+                .Select((x, o) => new HotspotDataLsitVo
+                {
+                    Id = x.Id,
+                    Name = x.HotSpotName,
+                    Num = SqlFunc.AggregateSum(SqlFunc.IIF(o.Id != null, 1, 0)),
+                    Sublevel = SqlFunc.AggregateSum(SqlFunc.IIF(x.HotSpotName != o.HotspotName, 1, 0)) > 0,
+                }).MergeTable().ToListAsync();
+            var chainStartTime = dto.QueryDto.StartTime;
+            var chainEndTime = dto.QueryDto.EndTime;
+            switch (dto.QueryDto.Type)
+            {
+                case 1://日
+                    chainStartTime = dto.QueryDto.StartTime.Value.AddDays(-1);
+                    chainEndTime = dto.QueryDto.EndTime.Value.AddDays(-1);
+                    break;
+                case 2://月
+                    chainStartTime = dto.QueryDto.StartTime.Value.AddMonths(-1);
+                    chainEndTime = dto.QueryDto.EndTime.Value.AddMonths(-1);
+                    break;
+                case 3://年
+                    chainStartTime = dto.QueryDto.StartTime.Value.AddYears(-1);
+                    chainEndTime = dto.QueryDto.EndTime.Value.AddYears(-1);
+                    break;
+                case 0:
+                    chainStartTime = dto.QueryDto.ChainStartTime.Value;
+                    chainEndTime = dto.QueryDto.ChainEndTime.Value;
+                    break;
+            }
+            var chainItems = await _hotspotTypeRepository.Queryable(false, true)
+                .LeftJoin<Order>((x, o) => o.HotspotSpliceName != null && (x.HotSpotName == o.HotspotSpliceName || o.HotspotSpliceName.Contains(x.HotSpotName)) && o.IsDeleted == false)
+                .WhereIF(dto.QueryDto.StartTime.HasValue, (x, o) => o.CreationTime >= chainStartTime)
+                .WhereIF(dto.QueryDto.EndTime.HasValue, (x, o) => o.CreationTime <= chainEndTime)
+                .WhereIF(!string.IsNullOrEmpty(dto.QueryDto.Keyword), (x, o) => x.HotSpotName.Contains(dto.QueryDto.Keyword!))
+                .WhereIF(IsCenter == false, (x, o) => o.ActualHandleOrgCode == _sessionContext.RequiredOrgId)
+                .Where((x, o) => x.ParentId == dto.QueryDto.Id)
+                .Where((x, o) => x.IsDeleted == false)
+                .GroupBy((x, o) => new { x.Id, x.HotSpotName })
+                .Select((x, o) => new
+                {
+                    Id = x.Id,
+                    ChainNum = SqlFunc.AggregateSum(SqlFunc.IIF(o.Id != null, 1, 0)),
+                }).MergeTable().ToListAsync();
+            var res = (from t1 in items
+                       join t2 in chainItems on t1.Id equals t2.Id into t1_t2
+                       from item in t1_t2.DefaultIfEmpty()
+                       select new HotspotDataLsitVo
+                       {
+                           Id = t1.Id,
+                           Name = t1.Name,
+                           Num = t1.Num,
+                           Sublevel = t1.Sublevel,
+                           Children = new List<HotspotDataLsitVo>(),
+                           ChainNum = t1_t2.Select(x => x.ChainNum).FirstOrDefault(),
+                           ChainRate = t1_t2.Select(x => x.ChainNum).FirstOrDefault() > 0 ?
+                           ((double.Parse(t1.Num.ToString()) - double.Parse(t1_t2.Select(x => x.ChainNum).FirstOrDefault().ToString())) / double.Parse(t1_t2.Select(x => x.ChainNum).FirstOrDefault().ToString()) * 100).ToString("F2") + "%" : "100.00%",
+                       }).ToList();
+            var total = new HotspotDataLsitVo()
+            {
+                Id = "0",
+                Name = "合计",
+                Num = res.Sum(x => x.Num),
+                Sublevel = false,
+                Children = new List<HotspotDataLsitVo>(),
+                ChainNum = res.Sum(x => x.ChainNum),
+                ChainRate = res.Sum(x => x.ChainNum) > 0 ? ((double.Parse(res.Sum(x => x.Num).ToString()) - double.Parse(res.Sum(x => x.ChainNum).ToString())) / double.Parse(res.Sum(x => x.ChainNum).ToString()) * 100).ToString("F2") + "%" : "100.00%"
+            };
+            res.Add(total);
+
+            List<HotspotDataLsitVo> data;
+            data = res;
+
+            var dataDtos = _mapper.Map<ICollection<HotspotDataLsitVo>>(data);
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos);
+
+            var dtos = dataDtos
+                .Select(stu => _mapper.Map(stu, typeof(HotspotDataLsitVo), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "热点类型统计");
+            //return new { List = res, Total = total };
+        }
+
         /// <summary>
         /// 热点数据统计 TODO和前端沟通
         /// </summary>
@@ -612,7 +727,7 @@ namespace Hotline.Api.Controllers.Bi
             var res = (from t1 in items
                        join t2 in chainItems on t1.Id equals t2.Id into t1_t2
                        from item in t1_t2.DefaultIfEmpty()
-                       select new
+                       select new HotspotDataLsitVo()
                        {
                            Id = t1.Id,
                            Name = t1.Name,
@@ -623,7 +738,7 @@ namespace Hotline.Api.Controllers.Bi
                            ChainRate = t1_t2.Select(x => x.ChainNum).FirstOrDefault() > 0 ?
                            ((double.Parse(t1.Num.ToString()) - double.Parse(t1_t2.Select(x => x.ChainNum).FirstOrDefault().ToString())) / double.Parse(t1_t2.Select(x => x.ChainNum).FirstOrDefault().ToString()) * 100).ToString("F2") + "%" : "100.00%",
                        }).ToList();
-            var total = new
+            var total = new HotspotDataLsitVo()
             {
                 Id = "0",
                 Name = "合计",
@@ -892,84 +1007,34 @@ namespace Hotline.Api.Controllers.Bi
             return new PagedDto<OrderSpecialDto>(total, _mapper.Map<IReadOnlyList<OrderSpecialDto>>(items));
         }
 
-        /// <summary>
-        /// 受理类型前十
-        /// </summary>
-        /// <param name="dto"></param>
-        /// <returns></returns>
-        [HttpGet("accept_type_top10_list")]
-        public async Task<PagedDto<AcceptTypeTop10Vo>> AcceptTypeTop10List([FromQuery] ReportPagedRequest dto)
+
+		/// <summary>
+		/// 受理类型前十
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpGet("accept_type_top10_list")]
+        public async Task<object> AcceptTypeTop10List([FromQuery] ReportPagedRequest dto)
         {
-            if (!dto.StartTime.HasValue || !dto.EndTime.HasValue) throw UserFriendlyException.SameMessage("请选择时间!");
+            var (areaList, returnList,data) = await _orderApplication.AcceptTypeTop10List(dto,false);
 
-            dto.PageIndex = 1;
-            dto.PageSize = 10;
-            var IsCenter = _sessionContext.OrgIsCenter;
-            var query = _orderRepository.Queryable(false, false, false)
-                .WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
-                .WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
-                .WhereIF(IsCenter == false, x => x.ActualHandleOrgCode.StartsWith(_sessionContext.RequiredOrgId))
-                .Select(x => new
-                {
-                    AcceptType = x.AcceptType,
-                    OneHotspot = SqlFunc.Substring(x.HotspotSpliceName, 0, SqlFunc.CharIndex("-", x.HotspotSpliceName + "-")),
-                    Id = x.Id
-                }).MergeTable().Where(x => x.OneHotspot != "非受理范围")
-                .GroupBy(x => new { x.OneHotspot })
-                .Select(x => new AcceptTypeTop10Vo
-                {
-                    Name = x.OneHotspot,
-                    ValidAccept = SqlFunc.AggregateSum(SqlFunc.IIF(true, 1, 0)),
-                    Consult = SqlFunc.AggregateSum(SqlFunc.IIF("咨询".Equals(x.AcceptType), 1, 0)),
-                    Report = SqlFunc.AggregateSum(SqlFunc.IIF("举报".Equals(x.AcceptType), 1, 0)),
-                    Complaint = SqlFunc.AggregateSum(SqlFunc.IIF("投诉".Equals(x.AcceptType), 1, 0)),
-                    SeekHelp = SqlFunc.AggregateSum(SqlFunc.IIF("求助".Equals(x.AcceptType), 1, 0)),
-                    Suggest = SqlFunc.AggregateSum(SqlFunc.IIF("建议".Equals(x.AcceptType), 1, 0)),
-                    Opinion = SqlFunc.AggregateSum(SqlFunc.IIF("意见".Equals(x.AcceptType), 1, 0)),
-                    Rests = SqlFunc.AggregateSum(SqlFunc.IIF("其他".Equals(x.AcceptType), 1, 0)),
-                    BenefitThePeople = SqlFunc.AggregateSum(SqlFunc.IIF("惠民帮助".Equals(x.AcceptType), 1, 0)),
-                    Praise = SqlFunc.AggregateSum(SqlFunc.IIF("表扬".Equals(x.AcceptType), 1, 0)),
-                }).MergeTable();
-            switch (dto.SortField)
-            {
-                case "validAccept":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.ValidAccept) : query.OrderByDescending(x => x.ValidAccept);
-                    break;
-                case "consult":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Consult) : query.OrderByDescending(x => x.Consult);
-                    break;
-                case "report":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Report) : query.OrderByDescending(x => x.Report);
-                    break;
-                case "complaint":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Complaint) : query.OrderByDescending(x => x.Complaint);
-                    break;
-                case "seekHelp":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.SeekHelp) : query.OrderByDescending(x => x.SeekHelp);
-                    break;
-                case "suggest":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Suggest) : query.OrderByDescending(x => x.Suggest);
-                    break;
-                case "opinion":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Opinion) : query.OrderByDescending(x => x.Opinion);
-                    break;
-                case "rests":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Rests) : query.OrderByDescending(x => x.Rests);
-                    break;
-                case "benefitThePeople":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.BenefitThePeople) : query.OrderByDescending(x => x.BenefitThePeople);
-                    break;
-                case "praise":
-                    query = dto.SortRule is 0 ? query.OrderBy(x => x.Praise) : query.OrderByDescending(x => x.Praise);
-                    break;
-                default:
-                    query = query.OrderByDescending(x => x.ValidAccept);
-                    break;
-            }
-            var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);
-            return new PagedDto<AcceptTypeTop10Vo>(total, items);
+            return new { List = areaList ,Data = returnList };
         }
 
+		/// <summary>
+		/// 受理类型前十导出
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[HttpPost("accept_type_top10_list-export")]
+        public async Task<FileStreamResult> AcceptTypeTop10ListExport([FromBody] ReportPagedRequest dto)
+        {
+			var (areaList, returnList,data) = await _orderApplication.AcceptTypeTop10List(dto,true);
+			var stream = ExcelHelper.CreateStream(data);
+            return ExcelStreamResult(stream, "受理类型前十统计");
+        }
+
+
         /// <summary>
         /// 热点类型部门统计
         /// </summary>

+ 1 - 126
src/Hotline.Api/Controllers/OrderController.cs

@@ -358,132 +358,7 @@ public class OrderController : BaseController
             {
                 try
                 {
-                    OrderPublish orderPublish = new OrderPublish();
-                    orderPublish.OrderId = order.Id;
-                    orderPublish.No = order.No;
-                    orderPublish.PublishState = false; //当前写死为false
-                    orderPublish.ArrangeTitle = order.Title;
-                    orderPublish.ArrangeContent = order.Content;
-                    orderPublish.ArrangeOpinion = order.FileOpinion;
-                    orderPublish.ProPublishState = false;
-                    orderPublish.FeedBackPhone = order.Contact;
-                    orderPublish.CreatorName = _sessionContext.UserName;
-                    await _orderPublishRepository.AddAsync(orderPublish);
-                    order.Publish(orderPublish.PublishState);
-                    await _orderRepository.UpdateAsync(order);
-                    //推省上
-                    var publishPublishOrder = _mapper.Map<PublishPublishOrderDto>(orderPublish);
-                    publishPublishOrder.Order = _mapper.Map<OrderDto>(order);
-                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder);
-
-                    //推应急管理局
-                    //是否开启
-                    var isOpenContingencyManagement =
-                        _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenContingencyManagement)?.SettingValue[0];
-                    if (isOpenContingencyManagement == "true")
-                        await _publisher.PublishAsync(new ContingencyManagementNotify(order, order.Title, order.Content, order.ActualOpinion),
-                            PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
-
-                    var orderVisit = new OrderVisit();
-                    orderVisit.No = order.No;
-                    orderVisit.OrderId = order.Id;
-                    orderVisit.VisitState = EVisitState.WaitForVisit;
-                    orderVisit.PublishTime = DateTime.Now;
-                    orderVisit.IsCanHandle = true;
-                    orderVisit.EmployeeId = _sessionContext.RequiredUserId;
-
-                    if (_appOptions.Value.IsZiGong)
-                    {
-                        orderVisit.EmployeeId = string.Empty;
-                    }
-
-                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null } && !order.IsProvince)
-                    {
-                        orderVisit.VisitState = EVisitState.Visited;
-                        orderVisit.VisitTime = DateTime.Now;
-                        orderVisit.VisitType = EVisitType.OtherVisit;
-                        orderVisit.NowEvaluate = new Kv() { Key = "4", Value = "满意" };
-                        if (_appOptions.Value.IsZiGong)
-                        {
-                            // 根据禅道 自贡需求 Id_361, 第一条, 3小条需求;
-                            // 直办件归档后自动回访量需统计在“胡玲”的默认回访量中;
-                            orderVisit.EmployeeId = _systemSettingCacheManager.DefaultVisitEmployeeId;
-                        }
-                    }
-
-                    if (order.CounterSignType != ECounterSignType.Center)
-                    {
-                        orderVisit.IsCanAiVisit = true;
-                    }
-
-
-                    string visitId = await _orderVisitRepository.AddAsync(orderVisit);
-
-                    //新增回访信息
-                    var visitedDetail = new List<OrderVisitDetail>();
-
-                    var seatDetail = new OrderVisitDetail();
-                    seatDetail.VisitId = visitId;
-                    seatDetail.VisitTarget = EVisitTarget.Seat;
-
-
-                    var orgDetail = new OrderVisitDetail();
-                    orgDetail.VisitId = visitId;
-                    orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
-                    orgDetail.VisitOrgName = order.ActualHandleOrgName;
-                    orgDetail.VisitTarget = EVisitTarget.Org;
-                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null, IsProvince: false })
-                    {
-                        var satisfy = new Kv() { Key = "4", Value = "满意" };
-                        orgDetail.OrgProcessingResults = satisfy;
-                        //orgDetail.OrgHandledAttitude = satisfy;
-                    }
-
-                    visitedDetail.Add(orgDetail);
-
-                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
-                    {
-                        seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
-                        seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
-                        order.Visited("4", "满意");
-                        order.Status = EOrderStatus.Visited;
-                        await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted);
-                    }
-
-                    visitedDetail.Add(seatDetail);
-                    await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail, HttpContext.RequestAborted);
-
-                    if (orderVisit.VisitState == EVisitState.Visited)
-                    {
-                        //推省上
-                        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
-                            new PublishVisitDto()
-                            {
-                                Order = _mapper.Map<OrderDto>(order),
-                                No = orderVisit.No,
-                                VisitType = orderVisit.VisitType,
-                                VisitName = orderVisit.CreatorName,
-                                VisitTime = orderVisit.VisitTime,
-                                VisitRemark = orderVisit.NowEvaluate?.Value,
-                                AreaCode = order.AreaCode!,
-                                SubjectResultSatifyCode = orderVisit.NowEvaluate?.Key,
-                                FirstSatisfactionCode = orderVisit.NowEvaluate?.Key,
-                                ClientGuid = ""
-                            }, cancellationToken: HttpContext.RequestAborted);
-                    }
-
-                    //推门户
-                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
-                    {
-                        Id = orderVisit.Id,
-                        Order = _mapper.Map<OrderDto>(order),
-                        OrderVisitDetails = _mapper.Map<List<VisitDetailDto>>(orderVisit.OrderVisitDetails),
-                        VisitName = _sessionContext.UserName,
-                        VisitTime = orderVisit.VisitTime,
-                        VisitType = orderVisit.VisitType,
-                        VisitState = orderVisit.VisitState,
-                        PublishTime = orderVisit.PublishTime,
-                    }, cancellationToken: HttpContext.RequestAborted);
+                    await _orderDomainService.OrderPublishAsync(order, HttpContext.RequestAborted);
                 }
                 catch
                 {

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

@@ -62,13 +62,13 @@
     }
   },
   "ConnectionStrings": {
-    "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+    "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
   },
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 3 //release:3, dev:5
+    "Database": 5 //release:3, dev:5
   },
   "Swagger": true,
   "AccLog":  false,

+ 10 - 5
src/Hotline.Application.Tests/Controller/DefaultHttpContextAccessor.cs

@@ -36,15 +36,20 @@ public class DefaultHttpContextAccessor : ISessionContext, IScopeDependency
     /// <summary>
     /// Id of current tenant or null for host
     /// </summary>
-    public string? UserId { get {
+    public string? UserId
+    {
+        get
+        {
             return TestSessionConstants.UserId;
-        } init { } }
+        }
+        init { }
+    }
 
     /// <summary>
     /// Id of current user or throw Exception for guest
     /// </summary>
     /// <exception cref="AuthenticationException"></exception>
-    public string RequiredUserId { get; }
+    public string RequiredUserId { get { return TestSessionConstants.UserId; } }
     public string? UserName { get { return TestSessionConstants.UserName; } init { } }
     public string? Phone { get; init; }
 
@@ -52,8 +57,8 @@ public class DefaultHttpContextAccessor : ISessionContext, IScopeDependency
     /// Roles
     /// </summary>
     public string[] Roles { get { return TestSessionConstants.Roles; } init { } }
-    public string? OrgId { get { return TestSessionConstants.OrgId;  } init { } }
-    public string RequiredOrgId { get; }
+    public string? OrgId { get { return TestSessionConstants.OrgId; } init { } }
+    public string RequiredOrgId { get { return TestSessionConstants.OrgId; } }
     public string? OrgName { get; init; }
     public int OrgLevel { get; init; }
     public string? OrgAreaCode { get; init; }

+ 116 - 20
src/Hotline.Application.Tests/Controller/OrderControllerTest.cs

@@ -1,16 +1,24 @@
 using AutoFixture;
+using Castle.DynamicProxy;
 using Hotline.Api.Controllers;
+using Hotline.Application.Orders.OrderPublishHandler;
 using Hotline.Application.Tests.Infrastructure;
+using Hotline.Application.Tests.Mock;
+using Hotline.FlowEngine.Notifications;
+using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
 using Hotline.Orders;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.Users;
+using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Settings;
 using Hotline.Share.Tools;
 using Hotline.Users;
+using MediatR;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Testing;
@@ -31,8 +39,11 @@ public class OrderControllerTest : TestBase
     private readonly OrderController _orderController;
     private readonly IRepository<Hotspot> _hotspotRepository;
     private readonly IOrderRepository _orderRepository;
+    private readonly OrderServiceMock _orderServiceMock;
+    private readonly IRepository<OrderPublish> _orderPublishRepository;
+    private readonly INotificationHandler<EndWorkflowNotify> _orderPublishEndWorkflowHandler;
 
-    public OrderControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IRepository<Hotspot> hotspotRepository, OrderController orderController, IOrderRepository orderRepository, IServiceScopeFactory scopeFactory, IRepository<User> userRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository)
+    public OrderControllerTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IRepository<Hotspot> hotspotRepository, OrderController orderController, IOrderRepository orderRepository, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, OrderServiceMock orderServiceMock, IRepository<OrderPublish> orderPublishRepository, INotificationHandler<EndWorkflowNotify> orderPublishEndWorkflowHandler) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository)
     {
         _hotspotRepository = hotspotRepository;
         _orderController = orderController;
@@ -41,34 +52,119 @@ public class OrderControllerTest : TestBase
             HttpContext = new DefaultHttpContext()
         };
         _orderRepository = orderRepository;
+        _orderServiceMock = orderServiceMock;
+        _orderPublishRepository = orderPublishRepository;
+        _orderPublishEndWorkflowHandler = orderPublishEndWorkflowHandler;
     }
 
     [Fact]
-    public async Task GetOrderHandleTimeConfigByAcceptType_Test()
+    public async Task ToPaiDanYuan_Test()
     {
-        var result = await _orderController.GetOrderHandleTimeConfigByAcceptType(Share.Enums.FlowEngine.EFlowDirection.OrgToCenter, "10");
-        result.Count.ShouldBe(1);
-        result.TimeText.ShouldBe("1个工作日");
-        result.TimeType.ShouldBe(ETimeType.WorkDay);
+        SetZuoXi();
+        var order = _orderServiceMock.CreateOrder()
+            .办理到派单员()
+            .GetCreateResult();
+        order.ShouldNotBeNull();
     }
 
     [Fact]
-    public async Task CreateOrder_Test()
+    public async Task AutoPublish_Test()
+    {
+        SetZuoXi();
+        var order = _orderServiceMock.CreateOrder()
+            .办理到派单员()
+            .办理到归档(SetPaiDanYuan)
+            .GetCreateResult();
+        await _orderPublishEndWorkflowHandler.Handle(new EndWorkflowNotify(
+        new Hotline.FlowEngine.Workflows.Workflow
+        {
+            ModuleCode = WorkflowModuleConsts.OrderHandle,
+            ExternalId = order.Id
+        },
+        new Hotline.FlowEngine.Workflows.WorkflowTrace(),
+             new Share.Dtos.FlowEngine.BasicWorkflowDto()
+        ), new CancellationToken());
+        var publish = await _orderPublishRepository.GetAsync(m => m.No == order.No);
+        publish.ShouldNotBeNull(order.No);
+    }
+
+    [Fact]
+    public void Set一级部门_Test()
     {
-        await SetPaiDanYuan();
-        var orderDto = _fixture.Create<AddOrderDto>();
-        var hotspot = await _hotspotRepository.Queryable()
-            .OrderByDescending(m => m.CreationTime)
-            .FirstAsync();
-        orderDto.HotspotId = hotspot.Id;
-        orderDto.HotspotName = hotspot.HotSpotName;
-        orderDto.HotspotSpliceName = hotspot.HotSpotFullName;
-        orderDto.Files = new List<FileDto>();
+        Set一级部门();
+    }
 
-        var orderResult = await _orderController.Add(orderDto);
-        var orderId = orderResult.ToJson().FromJson<OrderDto>().Id;
-        var order = await _orderRepository.GetAsync(orderId);
+    [Fact]
+    public async Task IsStepUrgent_True_Test()
+    {
+        SetZuoXi();
+        var order = _orderServiceMock.CreateOrder()
+            .办理到派单员()
+            .办理到归档(SetPaiDanYuan, data => data.IsStepUrgent = true, workflow =>
+            {
+                workflow.BusinessType = EBusinessType.DepartmentLeader;
+                workflow.Opinion = "测试保存勾选紧急";
+            })
+            .GetCreateResult();
         order.ShouldNotBeNull();
-        order.CreatorId.ShouldBe(TestSessionConstants.UserId);
+        order.Id.ShouldNotBeNull();
+        var orderDto = await _orderController.Get(order.Id);
+        orderDto.IsStepUrgent.ShouldBeTrue();
+        orderDto.IsStepUrgenText.ShouldBe("紧急");
+    }
+
+    /// <summary>
+    /// 测试在办理的过程中能正确保存 
+    /// 1.与市民电话联系
+    /// 2.已赴现场处置
+    /// 3.其他
+    /// 4.其他原因
+    /// 5.经办人
+    /// 6.经办人电话
+    /// 7.沟通时间
+    /// 8.沟通地点
+    /// </summary>
+    /// <returns></returns>
+    [Fact]
+    public async Task CreateOrder_Test()
+    {
+        SetZuoXi();
+        var order = _orderServiceMock.CreateOrder()
+            .办理到一级部门()
+            .办理到归档(Set一级部门)
+            .GetCreateResult();
+        order.Id.ShouldNotBeNull();
+        var orderEntity = await _orderRepository.GetAsync(order.Id);
+        orderEntity.RealCommunicationAddress.ShouldNotBeNull();
+        orderEntity.RealCommunicationTime.ShouldNotBeNull();
+        orderEntity.RealContactLocale.ShouldNotBeNull();
+        orderEntity.RealContactLocale.ShouldBe(true);
+        orderEntity.RealHandlerName.ShouldNotBeNull();
+        orderEntity.RealHandlerPhone.ShouldNotBeNull();
+
+
+        SetZuoXi();
+        order = _orderServiceMock.CreateOrder()
+            .办理到一级部门()
+            .办理到二级部门(Set一级部门)
+            .办理一级部门汇总(Set二级部门)
+            .GetCreateResult();
+        order.Id.ShouldNotBeNull();
+        orderEntity = await _orderRepository.GetAsync(order.Id);
+        orderEntity.RealCommunicationAddress.ShouldNotBeNull();
+        orderEntity.RealCommunicationTime.ShouldNotBeNull();
+        orderEntity.RealContactLocale.ShouldNotBeNull();
+        orderEntity.RealContactLocale.ShouldBe(true);
+        orderEntity.RealHandlerName.ShouldNotBeNull();
+        orderEntity.RealHandlerPhone.ShouldNotBeNull();
+    }
+
+    [Fact]
+    public async Task GetOrderHandleTimeConfigByAcceptType_Test()
+    {
+        var result = await _orderController.GetOrderHandleTimeConfigByAcceptType(Share.Enums.FlowEngine.EFlowDirection.OrgToCenter, "10");
+        result.Count.ShouldBe(1);
+        result.TimeText.ShouldBe("1个工作日");
+        result.TimeType.ShouldBe(ETimeType.WorkDay);
     }
 }

+ 14 - 0
src/Hotline.Application.Tests/Dto/CreateOrderOutDto.cs

@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Tests.Dto;
+public class CreateOrderOutDto
+{
+    public string Id { get; set; }
+    public string No { get; set; }
+    public string Password { get; set; }
+    public string CallId { get; set; }
+}

+ 0 - 4
src/Hotline.Application.Tests/Hotline.Application.Tests.csproj

@@ -47,8 +47,4 @@
     <Using Include="Xunit" />
   </ItemGroup>
 
-  <ItemGroup>
-    <Folder Include="Authentications\" />
-  </ItemGroup>
-
 </Project>

+ 2 - 0
src/Hotline.Application.Tests/Infrastructure/TestSettingConstants.cs

@@ -8,6 +8,8 @@ namespace Hotline.Application.Tests.Infrastructure;
 public static class TestSettingConstants
 {
     public const string PaiDanYuanAccountName = "UnitTestPDY";
+    public const string FirstOrgAccountName = "cs";
+    public const string SecondOrgAccountName = "cs21";
 }
 
 public static class TestSessionConstants

+ 238 - 0
src/Hotline.Application.Tests/Mock/OrderServiceMock.cs

@@ -0,0 +1,238 @@
+using Hotline.Api.Controllers;
+using Hotline.Application.Tests.Dto;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.Orders;
+using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.FlowEngine;
+using Hotline.Share.Tools;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Mock;
+public class OrderServiceMock
+{
+    private readonly OrderController _orderController;
+    private CreateOrderOutDto CreateOrderOutDto;
+    private AddOrderDto AddOrderDto;
+    private readonly IRepository<Order> _orderRepository;
+
+    public OrderServiceMock(OrderController orderController, IRepository<Order> orderRepository)
+    {
+        _orderController = orderController;
+        _orderRepository = orderRepository;
+    }
+
+    public OrderServiceMock CreateOrder()
+    {
+        var json = "{\"sourceChannel\":\"因特网\",\"sourceChannelCode\":\"YTW\",\"transferPhone\":null,\"fromPhone\":null,\"acceptorName\":\"单元测试\",\"acceptorStaffNo\":\"\",\"fromName\":\"1233333333\",\"fromGender\":1,\"identityType\":1,\"licenceType\":null,\"licenceTypeCode\":null,\"licenceNo\":null,\"ageRange\":null,\"ageRangeCode\":null,\"contact\":\"12333333333\",\"isSecret\":false,\"acceptSms\":false,\"no\":null,\"title\":\"\",\"hotspotId\":\"1912\",\"eventCategoryId\":null,\"incidentTime\":null,\"incidentPurpose\":null,\"areaCode\":\"519800\",\"city\":\"省内\",\"street\":null,\"isRepeat\":\"false\",\"pushType\":null,\"pushTypeCode\":null,\"content\":\"单元测试内容\",\"duplicateIds\":[],\"duplicateTitle\":null,\"callAddress\":null,\"repeatableEventDetails\":[],\"orderExtension\":null,\"transpond\":false,\"isEnforcementOrder\":false,\"focusOnEventsArr\":[],\"focusOnEvents\":null,\"isFormalistWorkOrder\":false,\"isSensitiveWorkOrders\":false,\"isUrgent\":false,\"isThreePartyConference\":false,\"is24HoursComplete\":false,\"company\":null,\"orderPushTypes\":[],\"acceptType\":\"咨询\",\"acceptTypeCode\":\"10\",\"files\":[],\"hotspotSpliceName\":\"互联互通-转接乐山市12345\",\"hotspotName\":\"转接乐山市12345\",\"hotspotCode\":\"1912\",\"hotspotExternal\":\"19\",\"county\":\"\",\"town\":\"\"}";
+        AddOrderDto = json.FromJson<AddOrderDto>();
+        AddOrderDto.Title = "单元测试" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
+        CreateOrderOutDto = _orderController.Add(AddOrderDto).GetAwaiter().GetResult().ToJson().FromJson<CreateOrderOutDto>();
+        return this;
+    }
+
+    public CreateOrderOutDto GetCreateResult()
+    {
+        return CreateOrderOutDto;
+    }
+
+    public OrderServiceMock 办理到派单员()
+    { 
+        var stepNextInfo = _orderController.GetFlowStartOptions(CreateOrderOutDto.Id).GetAwaiter().GetResult().ToJson().FromJson<NextStepsDto<NextStepOption>>();
+        var stepInfo = stepNextInfo.Steps.FirstOrDefault(m => m.Value == "派单组");
+        var stepOrg = stepInfo.Items.FirstOrDefault(m => m.Username == "单元测试派单员");
+
+        var handleDto = new StartWorkflowDto<OrderHandleFlowDto>
+        {
+            Data = new OrderHandleFlowDto
+            {
+                OrderId = CreateOrderOutDto.Id,
+            },
+            Workflow = new BasicWorkflowDto
+            {
+                NextHandlers = [stepOrg],
+                NextStepCode = stepInfo.Key,
+                NextStepName = stepInfo.Value,
+                Opinion = "办理到派单组意见",
+                BackToCountersignEnd = false,
+                IsSms = false,
+                IsForwarded = false,
+                HandlerType = EHandlerType.OrgLevel,
+                BusinessType = EBusinessType.Send,
+                FlowDirection = EFlowDirection.CenterToCenter,
+            }
+        };
+        _orderController.StartFlow(handleDto).GetAwaiter().GetResult();
+        return this;
+
+    }
+
+    public OrderServiceMock 办理到一级部门()
+    {
+        var stepNextInfo = _orderController.GetFlowStartOptions(CreateOrderOutDto.Id).GetAwaiter().GetResult().ToJson().FromJson<NextStepsDto<NextStepOption>>();
+        var stepInfo = stepNextInfo.Steps.FirstOrDefault(m => m.Value == "一级部门");
+        var stepOrg = stepInfo.Items.FirstOrDefault(m => m.OrgName == "测试部门");
+
+        var handleDto = new StartWorkflowDto<OrderHandleFlowDto>
+        {
+            Data = new OrderHandleFlowDto
+            {
+                OrderId = CreateOrderOutDto.Id,
+            },
+            Workflow = new BasicWorkflowDto
+            {
+                NextHandlers = [stepOrg],
+                NextStepCode = stepInfo.Key,
+                NextStepName = stepInfo.Value,
+                Opinion = "办理意见",
+                BackToCountersignEnd = false,
+                IsSms = false,
+                IsForwarded = false,
+                HandlerType = EHandlerType.OrgLevel,
+                BusinessType = EBusinessType.Department,
+            }
+        };
+        _orderController.StartFlow(handleDto).GetAwaiter().GetResult();
+        return this;
+    }
+
+    public OrderServiceMock 办理到归档(Action action = null, Action<OrderHandleFlowDto> dataAction = null, Action<NextWorkflowDto> workflowAction = null)
+    {
+        action?.Invoke();
+        var stepNextInfo = _orderController.GetNextStepsWithRecommend(CreateOrderOutDto.Id).GetAwaiter().GetResult().ToJson().FromJson<NextStepsDto<NextStepOption>>();
+        var stepInfo = stepNextInfo.Steps.FirstOrDefault(m => m.Value == "归档");
+        var stepOrg = stepInfo.Items.FirstOrDefault();
+
+        var order = _orderRepository.Get(CreateOrderOutDto.Id);
+
+        var handleDto = new NextWorkflowDto<OrderHandleFlowDto>
+        {
+            Data = new OrderHandleFlowDto
+            {
+                OrderId = CreateOrderOutDto.Id,
+                RealHandlerName = "经办人",
+                RealHandlerPhone = "13666666666",
+                RealContactLocale = true,
+                RealIsContacted = true,
+                IsOther = true,
+                OtherRemark = "其它原因",
+                RealCommunicationAddress = "地点地点地点",
+                RealCommunicationTime = DateTime.Now,
+            },
+            Workflow = new NextWorkflowDto
+            {
+                NextStepCode = "end",
+                NextStepName = "归档",
+                Opinion = "办理到归档",
+                BackToCountersignEnd = false,
+                IsSms = false,
+                IsForwarded = false,
+                HandlerType = EHandlerType.OrgLevel,
+                BusinessType = EBusinessType.Department,
+                FlowDirection = EFlowDirection.OrgToOrg,
+                WorkflowId = order.WorkflowId,
+                StepId = stepNextInfo.StepId,
+            }
+        };
+        dataAction?.Invoke(handleDto.Data);
+        workflowAction?.Invoke(handleDto.Workflow);
+        try
+        {
+            _orderController.Handle(handleDto).GetAwaiter().GetResult();
+        }
+        catch (Exception e)
+        {
+            var msg = e.Message;
+            if (msg.Contains("RealtimeService") == false)
+            {
+                throw;
+            }
+            // ignore
+        }
+        return this;
+    }
+
+    public OrderServiceMock 办理到二级部门(Action action = null)
+    {
+        action?.Invoke();
+        var stepNextInfo = _orderController.GetNextStepsWithRecommend(CreateOrderOutDto.Id).GetAwaiter().GetResult().ToJson().FromJson<NextStepsDto<NextStepOption>>();
+        var stepInfo = stepNextInfo.Steps.FirstOrDefault(m => m.Value == "二级部门");
+        var stepOrg = stepInfo.Items.FirstOrDefault(m => m.OrgName == "测试二级部门");
+
+        var order = _orderRepository.Get(CreateOrderOutDto.Id);
+
+        var handleDto = new NextWorkflowDto<OrderHandleFlowDto>
+        {
+            Data = new OrderHandleFlowDto
+            {
+                OrderId = CreateOrderOutDto.Id,
+            },
+            Workflow = new NextWorkflowDto
+            {
+                NextHandlers = [stepOrg],
+                NextStepCode = stepInfo.Key,
+                NextStepName = stepInfo.Value,
+                Opinion = "办理到二级部门",
+                BackToCountersignEnd = false,
+                IsSms = false,
+                IsForwarded = false,
+                HandlerType = EHandlerType.OrgLevel,
+                BusinessType = EBusinessType.Department,
+                FlowDirection = EFlowDirection.OrgToOrg,
+                WorkflowId = order.WorkflowId,
+                StepId = stepNextInfo.StepId,
+            }
+        };
+        _orderController.Handle(handleDto).GetAwaiter().GetResult();
+        return this;
+    }
+
+    public OrderServiceMock 办理一级部门汇总(Action aciton = null)
+    {
+        aciton?.Invoke();
+        var stepNextInfo = _orderController.GetNextStepsWithRecommend(CreateOrderOutDto.Id).GetAwaiter().GetResult().ToJson().FromJson<NextStepsDto<NextStepOption>>();
+        var stepInfo = stepNextInfo.Steps.FirstOrDefault(m => m.Value == "一级部门汇总");
+        var stepOrg = stepInfo.Items.FirstOrDefault(m => m.OrgName == "测试部门");
+
+        var order = _orderRepository.Get(CreateOrderOutDto.Id);
+
+        var handleDto = new NextWorkflowDto<OrderHandleFlowDto>
+        {
+            Data = new OrderHandleFlowDto
+            {
+                OrderId = CreateOrderOutDto.Id,
+                RealHandlerName = "经办人",
+                RealHandlerPhone = "13666666666",
+                RealContactLocale = true,
+                RealIsContacted = true,
+                IsOther = true,
+                OtherRemark = "其它原因",
+                RealCommunicationAddress = "地点地点地点",
+                RealCommunicationTime = DateTime.Now
+            },
+            Workflow = new NextWorkflowDto
+            {
+                NextHandlers = [stepOrg],
+                NextStepCode = stepInfo.Key,
+                NextStepName = stepInfo.Value,
+                Opinion = "办理到一级部门汇总",
+                BackToCountersignEnd = false,
+                IsSms = false,
+                IsForwarded = false,
+                HandlerType = EHandlerType.AssignedUser,
+                BusinessType = EBusinessType.Department,
+                FlowDirection = EFlowDirection.OrgToOrg,
+                StepType = EStepType.Summary,
+                WorkflowId = order.WorkflowId,
+                StepId = stepNextInfo.StepId,
+            }
+        };
+        _orderController.Handle(handleDto).GetAwaiter().GetResult();
+        return this;
+    }
+}

+ 4 - 0
src/Hotline.Application.Tests/Startup.cs

@@ -38,6 +38,8 @@ using Hotline.Identity.Accounts;
 using Hotline.Application.Tests.Controller;
 using Hotline.Application.Tests.Infrastructure;
 using Hotline.Authentications;
+using Hotline.Application.Orders.OrderPublishHandler;
+using Hotline.FlowEngine.Notifications;
 
 namespace Hotline.Application.Tests;
 public class Startup
@@ -150,6 +152,8 @@ public class Startup
             services.AddScoped<ISessionContext, DefaultHttpContextAccessor>();
             services.AddScoped<ISessionContextProvider, SessionContextProvider>();
             services.AddScoped<ICallApplication, XingTangCallApplication>();
+            services.AddScoped<OrderServiceMock>();
+            services.AddScoped<INotificationHandler<EndWorkflowNotify>, OrderPublishEndWorkflowHandler>();
             //ServiceLocator.Instance = services.BuildServiceProvider();
         }
 

+ 24 - 13
src/Hotline.Application.Tests/TestBase.cs

@@ -36,28 +36,39 @@ public class TestBase
         _userRepository = userRepository;
     }
 
-    public async Task SetPaiDanYuan()
+    public void SetPaiDanYuan()
     {
-        await SetOperator("派单员", "市民热线服务中心", "单元测试派单员", "001", "13408389849", EUserType.Normal, TestSettingConstants.PaiDanYuanAccountName);
+        SetOperator("派单员", "市民热线服务中心", "单元测试派单员", "001", "13408389849", EUserType.Normal, TestSettingConstants.PaiDanYuanAccountName);
     }
 
-    public async Task SetZuoXi()
+    public void Set一级部门()
     {
-        await SetOperator("坐席", "市民热线服务中心", "单元测试派单员", "001", "13408389849", EUserType.Seat, TestSettingConstants.PaiDanYuanAccountName);
+        SetOperator("部门经办人", "测试部门", "测试", "001094", "13408389849", EUserType.Seat, TestSettingConstants.FirstOrgAccountName);
     }
 
-    private async Task SetOperator(string displayName, string fullOrgName, string name, string orgId, string phoneNo, EUserType userType, string userName)
+    public void Set二级部门()
     {
-        var account = await _accountRepository.GetExtAsync(
+        SetOperator("部门经办人", "测试部门/测试二级部门", "cs21", "001094001", "13408389849", EUserType.Seat, TestSettingConstants.SecondOrgAccountName);
+    }
+
+
+    public void SetZuoXi()
+    {
+        SetOperator("坐席", "市民热线服务中心", "单元测试派单员", "001", "13408389849", EUserType.Seat, TestSettingConstants.PaiDanYuanAccountName);
+    }
+
+    private void SetOperator(string displayName, string fullOrgName, string name, string orgId, string phoneNo, EUserType userType, string userName)
+    {
+        var account = _accountRepository.GetExtAsync(
             d => d.UserName == userName,
-            d => d.Includes(x => x.Roles));
+            d => d.Includes(x => x.Roles)).GetAwaiter().GetResult();
 
         if (account == null)
         {
-            var roleId = await _roleRepository.Queryable()
+            var roleId = _roleRepository.Queryable()
                 .Where(m => m.DisplayName == displayName)
                 .Select(m => m.Id)
-                .FirstAsync();
+                .First();
             var newUser = new AddUserDto
             {
                 FullOrgName = fullOrgName,
@@ -69,13 +80,13 @@ public class TestBase
                 UserType = userType,
                 UserName = userName
             };
-            var accountId = await _userController.Add(newUser);
+            var accountId = _userController.Add(newUser).GetAwaiter().GetResult();
             TestSessionConstants.UserId = accountId;
-            account = await _accountRepository.GetExtAsync(
+            account = _accountRepository.GetExtAsync(
                 d => d.UserName == userName,
-                d => d.Includes(x => x.Roles));
+                d => d.Includes(x => x.Roles)).GetAwaiter().GetResult();
         }
-        var user = await _userRepository.GetAsync(account.Id);
+        var user = _userRepository.GetAsync(account.Id).GetAwaiter().GetResult();
         TestSessionConstants.UserId = account.Id;
         TestSessionConstants.Roles = account.Roles.Select(m => m.Id).ToArray();
         TestSessionConstants.UserName = account.UserName;

+ 2 - 0
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -665,6 +665,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             //ExpiredTime = workflow.ExpiredTime,
             CanStartCountersign = currentStep.CanStartCountersign,
             CurrentStepBusinessType = currentStep.BusinessType,
+            CurrentStepType = currentStep.StepType,
+            CurrentHandlerType = currentStep.HandlerType,
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList(),
             IsMainHandlerShow = workflow.WorkflowDefinition.IsMainHandlerShow,
             StepId = currentStep.Id,

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

@@ -219,6 +219,7 @@ public class WorkflowEndHandler : INotificationHandler<EndWorkflowNotify>
                     orderFlowDto.IsNonPoliceReturn = notification.Dto.External == null ? false : notification.Dto.External.IsPoliceReturn;
                     await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFiled, orderFlowDto, cancellationToken: cancellationToken);
 
+                    await _orderDomainService.OrderAutomaticPublishAsync(order, cancellationToken);
                     //try
                     //{
                     //    //写入质检  针对受理之后直接结束的工单

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

@@ -29,4 +29,8 @@
     <ProjectReference Include="..\XingTang.Sdk\XingTang.Sdk.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="Orders\OrderPublishHandler\" />
+  </ItemGroup>
+
 </Project>

+ 10 - 9
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -170,15 +170,15 @@ public class OrderMapperConfigs : IRegister
             .IgnoreIf((s, d) => s.VisitDetail == null, d => d.VisitDetail)
             ;
 
-        config.ForType<OrderHandleFlowDto, Workflow>()
-            .Map(d => d.RealHandlerPhone, s => s.RealHandlerPhone)
-            .Map(d => d.RealHandlerName, s => s.RealHandlerName)
-            .Map(d => d.RealCommunicationMode, s => s.RealCommunicationMode)
-            .Map(d => d.RealCommunicationTime, s => s.RealCommunicationTime)
-            .Map(d => d.RealCommunicationAddress, s => s.RealCommunicationAddress)
-            .Map(d => d.RealIsContacted, s => s.RealIsContacted)
-            .Map(d => d.RealContactLocale, s => s.RealContactLocale)
-            .IgnoreNonMapped(true);
+        //config.ForType<OrderHandleFlowDto, Workflow>()
+        //    .Map(d => d.RealHandlerPhone, s => s.RealHandlerPhone)
+        //    .Map(d => d.RealHandlerName, s => s.RealHandlerName)
+        //    .Map(d => d.RealCommunicationMode, s => s.RealCommunicationMode)
+        //    .Map(d => d.RealCommunicationTime, s => s.RealCommunicationTime)
+        //    .Map(d => d.RealCommunicationAddress, s => s.RealCommunicationAddress)
+        //    .Map(d => d.RealIsContacted, s => s.RealIsContacted)
+        //    .Map(d => d.RealContactLocale, s => s.RealContactLocale)
+        //    .IgnoreNonMapped(true);
 
         config.ForType<OrderHandleFlowDto, Order>()
             .Map(src => src.RealCommunicationAddress, dest => dest.RealCommunicationAddress)
@@ -207,6 +207,7 @@ public class OrderMapperConfigs : IRegister
             .IgnoreIf((src, dest) => string.IsNullOrEmpty(src.TranspondCityName), dest => dest.TranspondCityName)
             .Map(src => src.TranspondCityValue, dest => dest.TranspondCityValue)
             .IgnoreIf((src, dest) => string.IsNullOrEmpty(src.TranspondCityValue), dest => dest.TranspondCityValue)
+            .Map(src => src.IsStepUrgent, dest => dest.IsStepUrgent)
             .IgnoreNonMapped(true);
 
         config.ForType<AddOrderComplementDto, OrderComplement>()

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

@@ -321,5 +321,13 @@ namespace Hotline.Application.Orders
         ISugarQueryable<OrderScreen> OrderScreenList(ScreenListDto dto);
 
         ISugarQueryable<OrderListOutDto> QueryWaitedForSeat(QueryOrderWaitedDto dto);
-    }
+
+        /// <summary>
+        /// 受理类型前10
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        Task<(List<SystemDicData> acceptTypes, object items, DataTable data)> AcceptTypeTop10List(ReportPagedRequest dto, bool isExport);
+
+	}
 }

+ 133 - 17
src/Hotline.Application/Orders/OrderApplication.cs

@@ -69,7 +69,7 @@ using XF.Utility.EnumExtensions;
 using Newtonsoft.Json;
 using static NPOI.SS.Format.CellNumberFormatter;
 using System.Linq;
-using DocumentFormat.OpenXml.Bibliography;
+using System.Linq.Dynamic.Core;
 
 namespace Hotline.Application.Orders;
 
@@ -77,6 +77,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
 {
     private readonly IMediator _mediator;
     private readonly IRepository<TranspondCityRawData> _transpondCityRawDataRepository;
+    private readonly Publisher _publisher;
     private readonly ISessionContextProvider _sessionContextProvider;
     private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
@@ -143,6 +144,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         IRepository<OrderVisitDetail> orderVisitedDetailRepository,
         IOptionsSnapshot<AppConfiguration> appOptions,
         ISystemDicDataCacheManager sysDicDataCacheManager,
+        Publisher publisher,
         ISessionContextProvider sessionContextProvider,
         IRepository<TranspondCityRawData> transpondCityRawDataRepository,
         IRepository<OrderObserve> orderObserveRepository,
@@ -178,6 +180,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         _orderVisitedDetailRepository = orderVisitedDetailRepository;
         _appOptions = appOptions;
         _sysDicDataCacheManager = sysDicDataCacheManager;
+        _publisher = publisher;
         _sessionContextProvider = sessionContextProvider;
         _transpondCityRawDataRepository = transpondCityRawDataRepository;
         _orderObserveRepository = orderObserveRepository;
@@ -216,7 +219,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         {
             order.ExpiredTimeProvince = expiredTimeConfig.ExpiredTime;
         }
-        
         //if (string.IsNullOrEmpty(order.WorkflowId))
         //    throw new UserFriendlyException("该工单流程id异常");
         //var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, cancellationToken: cancellationToken);
@@ -228,10 +230,6 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         await _workflowDomainService.UpdateUnhandleExpiredTimeAsync(order.WorkflowId, expiredTimeConfig.ExpiredTime, cancellationToken);
 
         await _orderRepository.UpdateAsync(order, cancellationToken);
-
-        //推省上
-        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate,
-           _mapper.Map<OrderDto>(order), cancellationToken: cancellationToken);
     }
 
     // /// <summary>
@@ -329,7 +327,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var orgCode = _sessionContextProvider.SessionContext.OrgId;
         return _orderRepository.Queryable(canView: !IsCenter).Includes(d => d.OrderDelays)
 
-            .WhereIF(orgLevel ==3,d => SqlFunc.Subqueryable<WorkflowStep>()
+            .WhereIF(orgLevel==3,d => SqlFunc.Subqueryable<WorkflowStep>()
                 .Where(step => step.ExternalId == d.Id && step.Status != EWorkflowStepStatus.Handled &&
                                ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                                  step.HandlerId == _sessionContextProvider.SessionContext.RequiredUserId) ||
@@ -338,14 +336,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                                 (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                                  _sessionContextProvider.SessionContext.Roles.Contains(step.RoleId))))
                 .Any())
-            .WhereIF(orgLevel == 1 || orgLevel == 2, d=> d.ActualHandleOrgCode.StartsWith(orgCode))
+            .WhereIF(orgLevel==2 || orgLevel == 1,d=> d.ActualHandleOrgCode.StartsWith(orgCode))
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No!))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title!))
             .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
             .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
+            //&& stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value
+            //.Where(d => d.ExpiredTime != null &&
+            //         d.Status != EOrderStatus.Filed && d.Status != EOrderStatus.Published && d.Status != EOrderStatus.Visited && stTime >= d.ExpiredTime.Value && stTime2 <= d.ExpiredTime.Value)
             .Where(d => d.Status < EOrderStatus.Filed && dateTime > d.NearlyExpiredTime && dateTime < d.ExpiredTime)
-            .OrderBy(d => d.ExpiredTime);
+            .OrderBy(d => d.NearlyExpiredTime);
     }
 
     // /// <summary>
@@ -389,7 +390,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         int orgLevel = _sessionContextProvider.SessionContext.OrgLevel;
         var orgCode = _sessionContextProvider.SessionContext.OrgId;
         return _orderRepository.Queryable(canView: false).Includes(d => d.OrderDelays)
-            .WhereIF(orgLevel == 3 , d => SqlFunc.Subqueryable<WorkflowStep>()
+            .WhereIF(orgLevel == 3,d => SqlFunc.Subqueryable<WorkflowStep>()
                 .Where(step => step.ExternalId == d.Id && step.Status != EWorkflowStepStatus.Handled &&
                                ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) &&
                                  step.HandlerId == _sessionContextProvider.SessionContext.RequiredUserId) ||
@@ -398,14 +399,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                                 (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) &&
                                  _sessionContextProvider.SessionContext.Roles.Contains(step.RoleId))))
                 .Any())
-            .WhereIF(orgLevel == 1 || orgLevel == 2, d => d.ActualHandleOrgCode.StartsWith(orgCode))
+            .WhereIF(orgLevel == 2 || orgLevel == 1, d => d.ActualHandleOrgCode.StartsWith(orgCode))
             .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince)
             //.WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!))
             .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No))
             .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!))
             .WhereIF(dto.Delay.HasValue && dto.Delay == 1, d => d.OrderDelays.Any() == true)
             .WhereIF(dto.Delay.HasValue && dto.Delay == 2, d => d.OrderDelays.Any() == false)
-            .Where(d=> d.Status < EOrderStatus.Filed)
             .Where(d => d.ExpiredTime != null &&
                         (((d.Status == EOrderStatus.Filed || d.Status == EOrderStatus.Published || d.Status == EOrderStatus.Visited) &&
                           d.FiledTime >= d.ExpiredTime) ||
@@ -1086,8 +1086,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                  d.SourceChannelCode == "S12345" && d.IsProvince == true) //省12345
              .WhereIF(!string.IsNullOrEmpty(dto.ContentRetrieval),
                  d => d.Title.Contains(dto.ContentRetrieval) || d.Content.Contains(dto.ContentRetrieval) || d.FileOpinion.Contains(dto.ContentRetrieval) || d.ActualOpinion.Contains(dto.ContentRetrieval))
-             .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == true, d => d.ActualHandleStepAcceptTime != null)
-             .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == false, d => d.ActualHandleStepAcceptTime == null)
+             .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == true, d => d.CurrentStepAcceptTime != null)
+             .WhereIF(dto.IsSgin.HasValue && dto.IsSgin == false, d => d.CurrentStepAcceptTime == null)
              .WhereIF(dto.FiledType is FiledType.CenterFiled, d => d.ProcessType == EProcessType.Zhiban)
              .WhereIF(dto.FiledType is FiledType.OrgFiled, d => d.ProcessType == EProcessType.Jiaoban)
              .WhereIF(!string.IsNullOrEmpty(dto.OrderTagCode), d => d.OrderTagCode == dto.OrderTagCode)
@@ -2247,8 +2247,8 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Select(x => new OrderScreenAuditVo
             {
                 AuditName = x.HandlerName,
-                AuditNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceState == EWorkflowTraceState.Normal, 1, 0)),
-                AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceState == EWorkflowTraceState.StepRemoveByPrevious, 1, 0)),
+                AuditNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType == EWorkflowTraceType.Normal, 1, 0)),
+                AuditBackNum = SqlFunc.AggregateSum(SqlFunc.IIF(x.TraceType == EWorkflowTraceType.Previous, 1, 0)),
             });
         return query;
     }
@@ -2769,5 +2769,121 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .OrderByIF(dto.IsHandled == false, d => new { IsUrgent = d.IsUrgent, CreationTime = d.CreationTime }, OrderByType.Desc)
             .Select<OrderListOutDto>();
     }
-    #endregion
+
+    /// <summary>
+    /// 受理前十
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="isExport"></param>
+    /// <returns></returns>
+	public async Task<(List<SystemDicData> acceptTypes, object items, DataTable data)> AcceptTypeTop10List(ReportPagedRequest dto, bool isExport)
+	{
+
+		var dicList = _systemDicDataRepository.Queryable().Where(x => x.DicTypeCode == "AcceptType").OrderBy(x => x.Sort).MergeTable();
+		var IsCenter = _sessionContext.OrgIsCenter;
+
+		var hotspotList = _hotspotRepository.Queryable().Where(x => SqlFunc.Length(x.Id) == 2)
+			.Select(x => new
+			{
+				HotspotId = x.Id,
+				HotspotName = x.HotSpotFullName,
+			}).MergeTable();
+
+		var orderList = _orderRepository.Queryable()
+			.WhereIF(dto.StartTime.HasValue, x => x.CreationTime >= dto.StartTime)
+			.WhereIF(dto.EndTime.HasValue, x => x.CreationTime <= dto.EndTime)
+			.WhereIF(IsCenter == false, x => x.ActualHandleOrgCode.StartsWith(_sessionContext.RequiredOrgId))
+			.Select(x => new
+			{
+				HotspotId = x.HotspotId.Substring(0, 2),
+				AcceptTypeCode = x.AcceptTypeCode,
+			}).MergeTable();
+
+		var hotListAndOrder = hotspotList.LeftJoin(orderList, (it, o) => it.HotspotId == o.HotspotId)
+			.GroupBy((it, o) => new
+			{
+				it.HotspotId,
+				it.HotspotName,
+				AcceptTypeCode = o.AcceptTypeCode,
+			})
+			.OrderBy((it, o) => it.HotspotId)
+			.Select((it, o) => new
+			{
+				HotspotId = it.HotspotId,
+				HotspotName = it.HotspotName,
+				AcceptTypeCode = o.AcceptTypeCode,
+				Count = SqlFunc.AggregateCount(it.HotspotId)
+			}).MergeTable();
+
+		var returnList = await dicList.LeftJoin(hotListAndOrder, (pp, dd) => pp.DicDataValue == dd.AcceptTypeCode)
+			.GroupBy((pp, dd) => new
+			{
+				HotspotId = dd.HotspotId,
+				HotspotName = dd.HotspotName,
+				AcceptTypeCode = pp.DicDataValue,
+				AcceptType = pp.DicDataName,
+			})
+			.OrderBy((pp, dd) => dd.HotspotId)
+			.Select((pp, dd) => new
+			{
+				HotspotId = dd.HotspotId,
+				HotspotName = dd.HotspotName,
+				AcceptTypeCode = pp.DicDataValue,
+				AcceptType = pp.DicDataName,
+				Count = SqlFunc.AggregateSum(dd.Count)
+			}).ToPivotTableAsync(q => q.AcceptType, q => new { q.HotspotName }, q => q.Sum(x => x.Count));
+		DataColumn totalColumn = new DataColumn("有效受理量", typeof(int));
+		returnList.Columns.Add(totalColumn);
+
+		returnList.Columns["HotspotName"].ColumnName = "省一级热点名称";
+        var titleList = await _systemDicDataRepository.Queryable().Where(x => x.DicTypeCode == "AcceptType").OrderBy(x => x.Sort).ToListAsync();
+		for (int z = 0; z < returnList.Rows.Count; z++)
+		{
+			if (string.IsNullOrEmpty(returnList.Rows[z]["省一级热点名称"].ToString()))
+			{
+				returnList.Rows.Remove(returnList.Rows[z]);
+			}
+			else
+			{
+				int num = 0;
+				var colTotal = returnList.Columns.Count - 1;
+				for (int i = 1; i < colTotal; i++)
+				{
+					num += int.Parse(returnList.Rows[z][i].ToString());
+				}
+				returnList.Rows[z]["有效受理量"] = num;
+			}
+		}
+		returnList.Columns["有效受理量"].SetOrdinal(1);
+		DataTable list = new DataTable();
+		if (returnList.Rows.Count > 0)
+			list = returnList.Select("", "有效受理量 DESC").Take(10).CopyToDataTable();
+		if (isExport)
+		{
+			return (new List<SystemDicData>(), null, list);
+		}
+		var listDy = ToDynamicList(list);
+		return (titleList, listDy, list);
+	}
+
+	public static List<dynamic> ToDynamicList(DataTable dataTable)
+	{
+		var list = new List<dynamic>();
+
+		foreach (DataRow row in dataTable.Rows)
+		{
+			dynamic expando = new ExpandoObject();
+			var expandoDic = (IDictionary<string, object>)expando;
+
+			foreach (DataColumn column in dataTable.Columns)
+			{
+				expandoDic.Add(column.ColumnName, row[column]);
+			}
+
+			list.Add(expando);
+		}
+
+		return list;
+	}
+	#endregion
 }

+ 47 - 0
src/Hotline.Repository.SqlSugar/System/SystemLogRepository.cs

@@ -0,0 +1,47 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Share.Tools;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.System;
+public class SystemLogRepository : BaseRepository<SystemLog>, ISystemLogRepository, IScopeDependency
+{
+    public SystemLogRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
+    {
+    }
+
+    public async Task AddAsync(string name, string executeParam = "", string remark = "", string executeUrl = "", int status = 0)
+    {
+        try
+        {
+            var entity = new SystemLog
+            {
+                Name = name,
+                ExecuteParam = executeParam,
+                ExecuteUrl = executeUrl,
+                Remark = remark,
+                Status = status
+            };
+            if (executeUrl.IsNullOrEmpty())
+            {
+                try
+                {
+                    entity.ExecuteUrl = new StackTrace().GetFrame(1).GetMethod().Name;
+                }
+                catch { }
+            }
+            await AddAsync(entity);
+        }
+        catch
+        {
+            // ignore
+        }
+    }
+}

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

@@ -34,6 +34,16 @@ public class NextStepsDto
     /// </summary>
     public EBusinessType CurrentStepBusinessType { get; set; }
 
+    /// <summary>
+    /// 模板配置节点类型
+    /// </summary>
+    public EStepType CurrentStepType { get; set; }
+
+    /// <summary>
+    /// 办理对象类型
+    /// </summary>
+    public EHandlerType CurrentHandlerType { get; set; }
+    
     /// <summary>
     /// 当前办理节点部门等级(非部门等级办理时无效)
     /// </summary>

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

@@ -2,6 +2,7 @@
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Requests;
 using Microsoft.VisualBasic;
+using System.Data;
 using XF.Utility.EnumExtensions;
 
 namespace Hotline.Share.Dtos.Order
@@ -92,8 +93,13 @@ namespace Hotline.Share.Dtos.Order
 		public int Num { get; set; }
 		public bool Sublevel { get; set; }
 
-		List<HotspotDataLsitVo> Children { get; set; }
-	}
+		public List<HotspotDataLsitVo> Children { get; set; }
+
+		public int ChainNum { get; set; }
+
+		public string ChainRate { get; set; }
+
+    }
 
 
 	public class AcceptTypeTop10Volod {

+ 41 - 1
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -187,7 +187,7 @@ namespace Hotline.Share.Dtos.Order
         /// 实际办理节点签收时间
         /// </summary>
         public DateTime? ActualHandleStepAcceptTime { get; set; }
-        
+
         public string ActualStepAcceptText => ActualHandleStepAcceptTime.HasValue ? "已签收" : "未签收";
 
         /// <summary>
@@ -269,11 +269,21 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public bool? RealIsContacted { get; set; }
 
+        /// <summary>
+        /// 已与市民沟通
+        /// </summary>
+        public string RealIsContactedTxt => RealIsContacted.HasValue && RealIsContacted.Value ? "已与市民沟通" : string.Empty;
+
         /// <summary>
         /// 已与市民现场沟通
         /// </summary>
         public bool? RealContactLocale { get; set; }
 
+        /// <summary>
+        /// 已与市民现场沟通
+        /// </summary>
+        public string RealContactLocaleTxt => RealContactLocale.HasValue && RealContactLocale.Value ? "已与市民现场沟通" : string.Empty;
+
         #endregion
 
         #region 当前办理节点信息(指派时赋值)
@@ -530,6 +540,36 @@ namespace Hotline.Share.Dtos.Order
 
         public string IsUrgentText => IsUrgent ? "紧急" : "";
 
+        /// <summary>
+        /// 工单办理时 勾选的 是否紧急
+        /// </summary>
+        public string IsStepUrgenText => IsStepUrgent ? "紧急" : "";
+
+        /// <summary>
+        /// 工单办理时勾选的 是否紧急
+        /// </summary>
+        public bool IsStepUrgent { get; set; }
+
+        /// <summary>
+        /// 是否推诿
+        /// </summary>
+        public bool IsEvasive { get; set; }
+
+        /// <summary>
+        /// 是否推诿
+        /// </summary>
+        public string IsEvasiveTxt => IsEvasive ? "推诿" : "";
+
+        /// <summary>
+        /// 是否不积极
+        /// </summary>
+        public bool IsInactively { get; set; }
+
+        /// <summary>
+        /// 是否不积极
+        /// </summary>
+        public string IsInactivelyTxt => IsInactively ? "不积极" : "";
+
         /// <summary>
         /// 发布范围
         /// </summary>

+ 3 - 2
src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs

@@ -89,9 +89,10 @@ namespace Hotline.Share.Dtos.Order
         public string? OtherRemark { get; set; }
 
         /// <summary>
-        /// 是否紧急
+        /// 禅道_task_59
+        /// 在办理的时候勾选的是否紧急
         /// </summary>
-        public bool? IsUrgent { get; set; }
+        public bool? IsStepUrgent { get; set; }
 
         /// <summary>
         /// 是否推诿

+ 128 - 0
src/Hotline.Share/Dtos/WebPortal/GetCaseReultSendModel.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.WebPortal
+{
+    public class GetCaseReultSendModel
+    {
+        /// <summary>
+        /// 答复单位
+        /// </summary>
+        [JsonPropertyName("DEPT_NAME")]
+        public string GCRS_DEPT_NAME { get; set; }
+
+        /// <summary>
+        /// 答复时间
+        /// </summary>
+        [JsonPropertyName("FINISH_TIME")]
+        public string? GCRS_FINISH_TIME { get; set; }
+
+        /// <summary>
+        /// 答复人员
+        /// </summary>
+        [JsonPropertyName("FINISH_NAME")]
+        public string GCRS_FINISH_NAME { get; set; }
+
+        /// <summary>
+        /// 办理情况
+        /// </summary>
+        [JsonPropertyName("FINISH_NOTE")]
+        public string GCRS_FINISH_NOTE { get; set; }
+
+        /// <summary>
+        /// 办理操作
+        /// </summary>
+        [JsonPropertyName("FINISH_TYPE")]
+        public string GCRS_FINISH_TYPE { get; set; }
+
+        /// <summary>
+        /// 办理单位
+        /// </summary>
+        [JsonPropertyName("END_DEPT")]
+        public string GCRS_END_DEPT { get; set; }
+
+        /// <summary>
+        /// 办理人员
+        /// </summary>
+        [JsonPropertyName("END_NAME")]
+        public string GCRS_END_NAME { get; set; }
+
+        /// <summary>
+        /// 联系时间
+        /// </summary>
+        [JsonPropertyName("CONCACT_TIME")]
+        public string? GCRS_CONCACT_TIME { get; set; }
+
+        /// <summary>
+        /// 联系方式
+        /// </summary>
+        [JsonPropertyName("CONCACT_TYPE")]
+        public string GCRS_CONCACT_TYPE { get; set; }
+
+        /// <summary>
+        /// 签收时间
+        /// </summary>
+        [JsonPropertyName("SIGN_TIME")]
+        public string? GCRS_SIGN_TIME { get; set; }
+
+        /// <summary>
+        /// 反馈时间
+        /// </summary>
+        [JsonPropertyName("FDBACKTIME")]
+        public string? GCRS_FDBACKTIME { get; set; }
+
+        /// <summary>
+        /// 交办时间
+        /// </summary>
+        [JsonPropertyName("SEND_TIME")]
+        public string? GCRS_SEND_TIME { get; set; }
+
+        /// <summary>
+        /// 反馈意见
+        /// </summary>
+        [JsonPropertyName("FDBACK")]
+        public string GCRS_FDBACK { get; set; }
+
+        /// <summary>
+        /// 办理时长
+        /// </summary>
+        [JsonPropertyName("HANDLETIME_LONG")]
+        public decimal? GCRS_HANDLETIME_LONG { get; set; }
+
+        /// <summary>
+        /// 任务单关联 guid
+        /// </summary>
+        [JsonPropertyName("TROWGUID")]
+        public string GCRS_TROWGUID { get; set; }
+
+        /// <summary>
+        /// 退回类型
+        /// </summary>
+        [JsonPropertyName("BACKTYPE")]
+        public string GCRS_BACKTYPE { get; set; }
+
+        /// <summary>
+        /// 服务工单编号
+        /// </summary>
+        [JsonPropertyName("CASE_SERIAL")]
+        public string GCRS_CASE_SERIAL { get; set; }
+
+        /// <summary>
+        /// 行政区划代码
+        /// </summary>
+        [JsonPropertyName("AREA_CODE")]
+        public string GCRS_AREA_CODE { get; set; }
+
+        /// <summary>
+        /// 材料标识
+        /// </summary>
+        [JsonPropertyName("CLIENG_GUID")]
+        public string GCRS_CLIENG_GUID { get; set; }
+    }
+}

+ 5 - 0
src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs

@@ -20,5 +20,10 @@ namespace Hotline.Caching.Interfaces
         /// </summary>
         string DefaultVisitEmployeeId { get; }
         int FixedQueryCount { get; }
+
+        /// <summary>
+        /// 自动发布中心直办归档工单
+        /// </summary>
+        bool AutomaticPublishOrder { get; }
     }
 }

+ 32 - 1
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -39,7 +39,7 @@ namespace Hotline.Caching.Services
         public int EffectiveTimes
             => int.Parse(GetSetting(SettingConstants.EffectiveTimes)?.SettingValue[0]);
 
-        public int ConnectByeTimes 
+        public int ConnectByeTimes
             => int.Parse(GetSetting(SettingConstants.ConnectByeTimes)?.SettingValue[0]);
 
         public int NoConnectByeTimes => int.Parse(GetSetting(SettingConstants.NoConnectByeTimes)?.SettingValue[0]);
@@ -55,5 +55,36 @@ namespace Hotline.Caching.Services
         public string DefaultVisitEmployeeId => GetSetting(SettingConstants.DefaultVisitEmployeeId)?.SettingValue[0].Trim().ToString();
 
         public int FixedQueryCount => int.Parse(GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0]);
+
+        public bool AutomaticPublishOrder
+        {
+            get
+            {
+
+                try
+                {
+                    var value = GetSetting(SettingConstants.AutomaticPublishOrder)?.SettingValue[0];
+                    if (value == null) return false;
+                    if (value.Trim() == "true")
+                    {
+                        return true;
+                    }
+                }
+                catch (UserFriendlyException e)
+                {
+                    if (e.Message.Contains("无效系统设置"))
+                    {
+                        _systemSettingRepository.AddAsync(new SystemSetting 
+                        {
+                            Code = SettingConstants.AutomaticPublishOrder,
+                            SettingName = "自动发布中心直办归档工单",
+                            SettingValue = ["false"],
+                            Remark = "用于中心直办件归档后默认自动发布, 开启就自动发布.true 或者 false"
+                        });
+                    }
+                }
+                return false;
+            }
+        }
     }
 }

+ 28 - 28
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -128,40 +128,40 @@ public partial class Workflow : CreationEntity
     [SugarColumn(Length = 8000)]
     public string ActualOpinion { get; set; } = "办理中...";
 
-    /// <summary>
-    /// 真实办理人姓名(手动填写)
-    /// </summary>
-    public string? RealHandlerName { get; set; }
+    ///// <summary>
+    ///// 真实办理人姓名(手动填写)
+    ///// </summary>
+    //public string? RealHandlerName { get; set; }
 
-    /// <summary>
-    /// 真实办理人电话(手动填写)
-    /// </summary>
-    public string? RealHandlerPhone { get; set; }
+    ///// <summary>
+    ///// 真实办理人电话(手动填写)
+    ///// </summary>
+    //public string? RealHandlerPhone { get; set; }
 
-    /// <summary>
-    /// 沟通方式(手动填写)
-    /// </summary>
-    public ERealCommunicationMode? RealCommunicationMode { get; set; }
+    ///// <summary>
+    ///// 沟通方式(手动填写)
+    ///// </summary>
+    //public ERealCommunicationMode? RealCommunicationMode { get; set; }
 
-    /// <summary>
-    /// 沟通时间(手动填写)
-    /// </summary>
-    public DateTime? RealCommunicationTime { get; set; }
+    ///// <summary>
+    ///// 沟通时间(手动填写)
+    ///// </summary>
+    //public DateTime? RealCommunicationTime { get; set; }
 
-    /// <summary>
-    /// 沟通地点(手动填写)
-    /// </summary>
-    public string? RealCommunicationAddress { get; set; }
+    ///// <summary>
+    ///// 沟通地点(手动填写)
+    ///// </summary>
+    //public string? RealCommunicationAddress { get; set; }
 
-    /// <summary>
-    /// 已与市民沟通
-    /// </summary>
-    public bool? RealIsContacted { get; set; }
+    ///// <summary>
+    ///// 已与市民沟通
+    ///// </summary>
+    //public bool? RealIsContacted { get; set; }
 
-    /// <summary>
-    /// 已与市民现场沟通
-    /// </summary>
-    public bool? RealContactLocale { get; set; }
+    ///// <summary>
+    ///// 已与市民现场沟通
+    ///// </summary>
+    //public bool? RealContactLocale { get; set; }
     #endregion
 
     #region 当前办理节点信息(指派时赋值)

+ 2 - 2
src/Hotline/Orders/IOrderDomainService.cs

@@ -102,7 +102,7 @@ namespace Hotline.Orders
         /// </summary>
         /// <returns></returns>
         Task SendOverTimeSms(CancellationToken cancellationToken);
-
-
+        Task OrderPublishAsync(Order order, CancellationToken cancellationToken);
+        Task OrderAutomaticPublishAsync(Order order, CancellationToken cancellationToken);
     }
 }

+ 30 - 4
src/Hotline/Orders/Order.cs

@@ -1,5 +1,6 @@
 using Hotline.CallCenter.Calls;
 using Hotline.FlowEngine.Workflows;
+using Hotline.Settings;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos.File;
 using Hotline.Share.Enums.FlowEngine;
@@ -11,6 +12,7 @@ using System.ComponentModel;
 using XF.Domain.Exceptions;
 using XF.Domain.Extensions;
 using XF.Domain.Repository;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Orders
 {
@@ -964,10 +966,18 @@ namespace Hotline.Orders
 
         /// <summary>
         /// 是否紧急
+        /// 在创单的时候勾选的是否紧急
         /// </summary>
         [SugarColumn(DefaultValue = "f", ColumnDescription = "是否紧急")]
         public bool IsUrgent { get; set; }
 
+        /// <summary>
+        /// 是否紧急
+        /// 在办理的时候勾选的是否紧急
+        /// </summary>
+        [SugarColumn(DefaultValue = "f", ColumnDescription = "办理勾选是否紧急")]
+        public bool IsStepUrgent { get; set; }
+
         /// <summary>
         /// 是否推诿
         /// </summary>
@@ -1039,7 +1049,8 @@ namespace Hotline.Orders
 		/// </summary>
 		[SugarColumn(ColumnDescription = "话务提醒是否转办")]
 		public bool? IsForwarded { get; set; }
-	}
+
+    }
 
     public partial class Order
     {
@@ -1351,10 +1362,25 @@ namespace Hotline.Orders
             }
         }
 
-        #endregion
-    }
+        /// <summary>
+        /// 自动发布条件检测
+        /// </summary>
+        /// <returns></returns>
+        /// <exception cref="NotImplementedException"></exception>
+        public string AutoPublishCheck()
+        {
+            if (CounterSignType != null)
+                return "会签工单自动发布失败;";
+            if (IsProvince)
+                return "省工单自动发布失败;";
+            if (Status != EOrderStatus.Filed)
+                return "工单状态非 已归档, " + Status.GetDescription();
+            return "";
+        }
+    #endregion
+}
 
-    public class UnsignedOrder
+public class UnsignedOrder
     {
         public Order Order { get; set; }
 

+ 205 - 2
src/Hotline/Orders/OrderDomainService.cs

@@ -24,6 +24,15 @@ using SqlSugar;
 using Hotline.Push.Notifies;
 using Hotline.Share.Enums.Push;
 using MediatR;
+using Hotline.Authentications;
+using Hotline.ContingencyManagement.Notifies;
+using Hotline.EventBus;
+using Hotline.Share.Enums.FlowEngine;
+using Mapster;
+using Microsoft.AspNetCore.Builder.Extensions;
+using Hotline.Configurations;
+using Microsoft.Extensions.Options;
+using Hotline.Share.Tools;
 
 namespace Hotline.Orders;
 
@@ -38,16 +47,20 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
     private readonly ITypedCache<CacheOrderNO> _cacheOrderNo;
     private readonly ISessionContext _sessionContext;
     private readonly ICapPublisher _capPublisher;
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
     private readonly IMapper _mapper;
     private readonly ILogger<OrderDomainService> _logger;
     private readonly IFileRepository _fileRepository;
     private readonly IRepository<Scheduling> _schedulingRepository;
+    private readonly Publisher _publisher;
+    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
     private readonly IRepository<User> _userRepository;
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     private readonly IWorkflowDomainService _workflowDomainService;
     private readonly IRepository<Hotspot> _hotspotRepository;
     private readonly IMediator _mediator;
-
+    private readonly IRepository<WorkflowStep> _workflowStepRepository;
+    private readonly ISystemLogRepository _systemLogRepository;
 
     public OrderDomainService(
         IOrderRepository orderRepository,
@@ -68,7 +81,11 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         IRepository<Scheduling> schedulingRepository,
         IWorkflowDomainService workflowDomainService,
         IRepository<Hotspot> hotspotRepository,
-        IMediator mediator)
+        IMediator mediator,
+        Publisher publisher,
+        IRepository<OrderVisitDetail> orderVisitDetailRepository,
+        IRepository<WorkflowStep> workflowStepRepository,
+        ISystemLogRepository systemLogRepository)
     {
         _orderRepository = orderRepository;
         _orderRedoRepository = orderRedoRepository;
@@ -88,6 +105,190 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         _workflowDomainService = workflowDomainService;
         _hotspotRepository = hotspotRepository;
         _mediator = mediator;
+        _publisher = publisher;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _workflowStepRepository = workflowStepRepository;
+        _systemLogRepository = systemLogRepository;
+    }
+
+    /// <summary>
+    /// 归档后自动发布
+    /// </summary>
+    /// <param name="order"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    public async Task OrderAutomaticPublishAsync(Order order, CancellationToken cancellationToken)
+    {
+        var name = "中心直办件归档后默认自动发布";
+        try
+        {
+            if (_systemSettingCacheManager.AutomaticPublishOrder == false)
+            {
+                return;
+            }
+            var checkResult = order.AutoPublishCheck();
+            if (checkResult.NotNullOrEmpty())
+            {
+                await _systemLogRepository.AddAsync(name, order.Id, checkResult);
+                return;
+            }
+
+            if (order.ProcessType != EProcessType.Zhiban)
+            {
+                await _systemLogRepository.AddAsync(name, order.Id, "非中心直办件");
+                return;
+            }
+
+            await OrderPublishAsync(order, cancellationToken);
+        }
+        catch (Exception e)
+        {
+            await _systemLogRepository.AddAsync(name, order.Id, $"系统异常: {e.Message}");
+        }
+    }
+
+    public async Task OrderPublishAsync(Order order, CancellationToken cancellationToken)
+    {
+        OrderPublish orderPublish = new()
+        {
+            OrderId = order.Id,
+            No = order.No,
+            PublishState = false, //当前写死为false
+            ArrangeTitle = order.Title,
+            ArrangeContent = order.Content,
+            ArrangeOpinion = order.FileOpinion,
+            ProPublishState = false,
+            FeedBackPhone = order.Contact,
+            CreatorName = _sessionContext.UserName
+        };
+        await _orderPublishRepository.AddAsync(orderPublish, cancellationToken);
+        order.Publish(orderPublish.PublishState);
+        await _orderRepository.UpdateAsync(order, cancellationToken);
+        //推省上
+        var publishPublishOrder = orderPublish.Adapt<PublishPublishOrderDto>();
+        publishPublishOrder.Order = order.Adapt<OrderDto>();
+        //查询实际办理附件
+        if (!string.IsNullOrEmpty(order.ActualHandleStepId)) 
+        {
+            var actualHandleStep = await _workflowStepRepository.GetAsync(order.ActualHandleStepId, cancellationToken);
+            publishPublishOrder.FileJsons = actualHandleStep?.FileJson;
+        }
+
+        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder, cancellationToken: cancellationToken);
+
+        //推应急管理局
+        //是否开启
+        var isOpenContingencyManagement =
+            _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenContingencyManagement)?.SettingValue[0];
+        if (isOpenContingencyManagement == "true")
+            await _publisher.PublishAsync(new ContingencyManagementNotify(order, order.Title, order.Content, order.ActualOpinion),
+                PublishStrategy.ParallelWhenAll, cancellationToken);
+
+        var orderVisit = new OrderVisit
+        {
+            No = order.No,
+            OrderId = order.Id,
+            VisitState = EVisitState.WaitForVisit,
+            PublishTime = DateTime.Now,
+            IsCanHandle = true,
+            EmployeeId = _sessionContext.RequiredUserId
+        };
+        if (!order.IsProvince)
+        {
+            orderVisit.EmployeeId = _sessionContext.RequiredUserId;
+        }
+
+        if (_appOptions.Value.IsZiGong)
+        {
+            orderVisit.EmployeeId = string.Empty;
+        }
+
+        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null } && !order.IsProvince)
+        {
+            orderVisit.VisitState = EVisitState.Visited;
+            orderVisit.VisitTime = DateTime.Now;
+            orderVisit.VisitType = EVisitType.OtherVisit;
+            orderVisit.NowEvaluate = new Kv() { Key = "4", Value = "满意" };
+            if (_appOptions.Value.IsZiGong)
+            {
+                // 根据禅道 自贡需求 Id_361, 第一条, 3小条需求;
+                // 直办件归档后自动回访量需统计在“胡玲”的默认回访量中;
+                orderVisit.EmployeeId = _systemSettingCacheManager.DefaultVisitEmployeeId;
+            }
+        }
+
+        if (order.CounterSignType != ECounterSignType.Center)
+        {
+            orderVisit.IsCanAiVisit = true;
+        }
+
+        string visitId = await _orderVisitRepository.AddAsync(orderVisit);
+
+        //新增回访信息
+        var visitedDetail = new List<OrderVisitDetail>();
+
+        var seatDetail = new OrderVisitDetail();
+        seatDetail.VisitId = visitId;
+        seatDetail.VisitTarget = EVisitTarget.Seat;
+
+
+        var orgDetail = new OrderVisitDetail();
+        orgDetail.VisitId = visitId;
+        orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
+        orgDetail.VisitOrgName = order.ActualHandleOrgName;
+        orgDetail.VisitTarget = EVisitTarget.Org;
+        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null, IsProvince: false })
+        {
+            var satisfy = new Kv() { Key = "4", Value = "满意" };
+            orgDetail.OrgProcessingResults = satisfy;
+            //orgDetail.OrgHandledAttitude = satisfy;
+        }
+
+        visitedDetail.Add(orgDetail);
+
+        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null })
+        {
+            seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
+            seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
+            order.Visited("4", "满意");
+            order.Status = EOrderStatus.Visited;
+            await _orderRepository.UpdateAsync(order, cancellationToken);
+        }
+
+        visitedDetail.Add(seatDetail);
+        await _orderVisitDetailRepository.AddRangeAsync(visitedDetail, cancellationToken);
+
+        if (order.IsProvince == false && orderVisit.VisitState == EVisitState.Visited)
+        {
+            //推省上
+            await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
+                new PublishVisitDto()
+                {
+                    Order = order.Adapt<OrderDto>(),
+                    No = orderVisit.No,
+                    VisitType = orderVisit.VisitType,
+                    VisitName = orderVisit.CreatorName,
+                    VisitTime = orderVisit.VisitTime,
+                    VisitRemark = orderVisit.NowEvaluate?.Value,
+                    AreaCode = order.AreaCode!,
+                    SubjectResultSatifyCode = orderVisit.NowEvaluate?.Key,
+                    FirstSatisfactionCode = orderVisit.NowEvaluate?.Key,
+                    ClientGuid = ""
+                }, cancellationToken: cancellationToken);
+        }
+
+        //推门户
+        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto()
+        {
+            Id = orderVisit.Id,
+            Order = order.Adapt<OrderDto>(),
+            OrderVisitDetails = orderVisit.OrderVisitDetails.Adapt<List<VisitDetailDto>>(),
+            VisitName = _sessionContext.UserName,
+            VisitTime = orderVisit.VisitTime,
+            VisitType = orderVisit.VisitType,
+            VisitState = orderVisit.VisitState,
+            PublishTime = orderVisit.PublishTime,
+        }, cancellationToken: cancellationToken);
     }
 
     public async Task<Order> GetOrderAsync(string? orderId, bool withHotspot = false, bool withAcceptor = false,
@@ -328,6 +529,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         }
     }
     #endregion
+
     #region  工单校验- 交通类工单
 
     /// <summary>
@@ -541,6 +743,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
         return $"{today:yyyyMMdd}{count:000000}";
     }
 
+
     #endregion
 }
 

+ 21 - 0
src/Hotline/Settings/ISystemLogRepository.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Settings;
+public interface ISystemLogRepository : IRepository<SystemLog>
+{
+    /// <summary>
+    /// 添加操作日志
+    /// </summary>
+    /// <param name="name">方法</param>
+    /// <param name="executeParam">入参</param>
+    /// <param name="executeUrl">地址</param>
+    /// <param name="remark">备注</param>
+    /// <param name="status">状态(0失败 1成功)</param>
+    /// <returns></returns>
+    Task AddAsync(string name, string executeParam = "", string remark = "", string executeUrl = "", int status = 0);
+}

+ 3 - 3
src/Hotline/Settings/SettingConstants.cs

@@ -565,10 +565,10 @@ namespace Hotline.Settings
         /// 上传文件格式显示
         /// </summary>
         public const string FileExt = "FileExt";
-        
+
         /// <summary>
-        /// 是否自动填写汇总节点信息(将前面的办理意见填写至汇总节点)
+        /// 自动发布中心直办归档工单
         /// </summary>
-        public const string IsAutoFillSummaryOpinion = "IsAutoFillSummaryOpinion";
+        public const string AutomaticPublishOrder = "AutomaticPublishOrder";
     }
 }