瀏覽代碼

Merge branch 'fix/bug_1119' into test

qinchaoyue 5 月之前
父節點
當前提交
33837aeb7d

+ 3 - 0
src/Hotline.Application.Tests/Application/SystemSettingCacheManagerTest.cs

@@ -33,5 +33,8 @@ public class SystemSettingCacheManagerTest
         delaySecond.ShouldBe(172800);
         var delaySecondEntity = _systemSettingRepository.GetAsync("08dc0681-a6d2-4ce7-877d-db65f846d523");
         delaySecondEntity.ShouldNotBeNull("DefaultVisitSmsDelaySecond 系统设置为NULL");
+
+        _systemSettingCacheManager.CallSyncPushEnable.ShouldBeTrue();
+
     }
 }

+ 43 - 6
src/Hotline.Application.Tests/Domain/OrderVisitDomainServiceTest.cs

@@ -1,4 +1,8 @@
-using Hotline.EventBus;
+using Hotline.Api.Controllers;
+using Hotline.Application.Tests.Mock;
+using Hotline.EventBus;
+using Hotline.Identity.Accounts;
+using Hotline.Identity.Roles;
 using Hotline.Orders;
 using Hotline.Push.FWMessage;
 using Hotline.Push.Notifies;
@@ -7,29 +11,34 @@ using Hotline.Share.Dtos.Push;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Push;
 using Hotline.Share.Tools;
+using Hotline.Users;
 using Mapster;
+using Microsoft.Extensions.DependencyInjection;
 using Shouldly;
 using XF.Domain.Repository;
 
 namespace Hotline.Application.Tests.Domain;
-public class OrderVisitDomainServiceTest
+public class OrderVisitDomainServiceTest : TestBase
 {
     private readonly IOrderVisitDomainService _orderVisitDomainService;
     private readonly IOrderVisitRepository _orderVisitRepository;
     private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
     private readonly Publisher _publisher;
     private readonly IOrderRepository _orderRepository;
+    private readonly OrderServiceMock _orderServiceMock;
 
-
-    public OrderVisitDomainServiceTest(IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher, IOrderRepository orderRepository)
+    public OrderVisitDomainServiceTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher, IOrderRepository orderRepository, OrderServiceMock orderServiceMock) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository)
     {
         _orderVisitDomainService = orderVisitDomainService;
         _orderVisitRepository = orderVisitRepository;
         _orderVisitDetailRepository = orderVisitDetailRepository;
         _publisher = publisher;
         _orderRepository = orderRepository;
+        _orderServiceMock = orderServiceMock;
     }
 
+
+
     //[Fact]
     public async Task UpdateSmsReplyDefault_Test()
     {
@@ -95,6 +104,17 @@ public class OrderVisitDomainServiceTest
     [InlineData("非常不满意", "SMSUnsatisfied", "2", "不满意")]
     public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey, string orgResuktValue)
     {
+        SetZuoXi();
+        var order = _orderServiceMock.CreateOrder()
+            .办理到一级部门()
+            .办理到二级部门(Set一级部门)
+            .办理一级部门汇总(Set二级部门)
+            .办理到归档(Set一级部门)
+            .发布工单(SetZuoXi)
+            .发送回访短信(SetZuoXi)
+            .GetCreateResult();
+        order.Id.ShouldNotBeNull();
+
         var visit = await _orderVisitRepository.Queryable()
             .Includes(m => m.Order)
             .Where(m => m.VisitState == EVisitState.SMSVisiting)
@@ -108,21 +128,38 @@ public class OrderVisitDomainServiceTest
         await _orderVisitDomainService.UpdateSmsReplyAsync(message);
         visit = _orderVisitRepository.Get(visit.Id);
         visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
+        visit.NowEvaluate.ShouldNotBeNull();
         visit.NowEvaluate.Key.ShouldBe(orgResuktKey);
         visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
-
+        var orderEntity = await _orderRepository.GetAsync(order.Id);
+        orderEntity.ShouldNotBeNull();
         if (content == "4" || content == "5" || content == "不满意" || content == "非常不满意")
+        {
             visit.VisitType.ShouldBeNull();
+            orderEntity.Status.ShouldNotBe(EOrderStatus.Visited);
+        }
+        else 
+        {
+            orderEntity.Status.ShouldBe(EOrderStatus.Visited);
+        }
 
         await _orderVisitDetailRepository.Queryable()
             .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
             .FirstAsync()
-            .Then(async org =>
+            .Then(org =>
             {
+                org.OrgProcessingResults.ShouldNotBeNull();
                 org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
                 org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
+
+                orderEntity.OrgProcessingResults.ShouldNotBeNull();
+                orderEntity.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
+                orderEntity.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
+
+                org.OrgHandledAttitude.ShouldNotBeNull();
                 org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
                 org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
+                return Task.CompletedTask;
             });
     }
 

+ 45 - 1
src/Hotline.Application.Tests/Mock/OrderServiceMock.cs

@@ -6,6 +6,9 @@ using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Tools;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Mvc.RazorPages;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -20,11 +23,17 @@ public class OrderServiceMock
     private CreateOrderOutDto CreateOrderOutDto;
     private AddOrderDto AddOrderDto;
     private readonly IRepository<Order> _orderRepository;
+    private readonly IOrderVisitRepository _orderVisitRepository;
 
-    public OrderServiceMock(OrderController orderController, IRepository<Order> orderRepository)
+    public OrderServiceMock(OrderController orderController, IRepository<Order> orderRepository, IOrderVisitRepository orderVisitRepository)
     {
         _orderController = orderController;
+        _orderController.ControllerContext = new ControllerContext
+        {
+            HttpContext = new DefaultHttpContext()
+        };
         _orderRepository = orderRepository;
+        _orderVisitRepository = orderVisitRepository;
     }
 
     public OrderServiceMock CreateOrder(string callId = "")
@@ -237,4 +246,39 @@ public class OrderServiceMock
         _orderController.Handle(handleDto).GetAwaiter().GetResult();
         return this;
     }
+
+    public OrderServiceMock 发布工单(Action aciton = null)
+    {
+        aciton?.Invoke();
+        var baseData = _orderController.PublishOrderPageBase(CreateOrderOutDto.Id).GetAwaiter().GetResult();
+        var inDto = new PublishOrderDto
+        { 
+            Id = CreateOrderOutDto.Id,
+            PublishState = false,
+            ArrangeTitle = baseData.OrderTitle,
+            ArrangeContent = baseData.Content,
+            ArrangeOpinion = baseData.ActualOpinion,
+            IdNames = [baseData.ActualHandleOrgName],
+            ProPublishState = false,
+            Resolve = true
+        };
+
+        _orderController.PublishOrder(inDto).GetAwaiter().GetResult();
+        return this;
+    }
+
+    public OrderServiceMock 发送回访短信(Action aciton = null)
+    {
+        aciton?.Invoke();
+        var id = _orderVisitRepository.Queryable()
+            .Where(m => m.No == CreateOrderOutDto.No)
+            .Select(m => m.Id)
+            .First();
+        var inDto = new VisitSmsInDto
+        {
+            Ids = [id]
+        };
+        _orderController.VisitPushSMSAsync(inDto).GetAwaiter().GetResult();
+        return this;
+    }
 }

+ 15 - 6
src/Hotline.Application/CallCenter/DefaultCallApplication.cs

@@ -516,15 +516,22 @@ public abstract class DefaultCallApplication : ICallApplication
             .Where(m => m.CallNo == callNo)
             .ToListAsync(cancellationToken);
 
-        // 只有一条通话记录, 不处理
-        if (callNative.Count < 2) return;
-
         var call = callNative.Where(m => m.Direction == ECallDirection.In)
             .OrderByDescending(m => m.Duration)
             .First();
 
+        // 只有一条通话记录, 不处理
         // 需要更新的callId 和 order.callId 相同, 不处理
-        if (callId == call.Id) return;
+        if (callNative.Count < 2 || callId == call.Id)
+        {
+            // 推省上
+            await _capPublisher.PublishAsync(EventNames.HotlineCallConnectWithOrder, new PublishCallRecrodDto()
+            {
+                Order = _orderRepository.GetAsync(orderId, cancellationToken).Adapt<OrderDto>(),
+                TrCallRecordDto = call.Adapt<TrCallDto>()
+            }, cancellationToken: cancellationToken);
+            return;
+        }
 
         await _orderRepository.Updateable()
             .SetColumns(m => m.CallId == call.Id)
@@ -535,10 +542,12 @@ public abstract class DefaultCallApplication : ICallApplication
             .SetColumns(m => m.CallId == call.Id)
             .Where(m => m.Id == callNo)
             .ExecuteCommandAsync(cancellationToken);
+
         // 推省上
-        await _capPublisher.PublishAsync(EventNames.HotlineCallConnectWithOrder, new PublishCallRecrodDto() {
+        await _capPublisher.PublishAsync(EventNames.HotlineCallConnectWithOrder, new PublishCallRecrodDto()
+        {
             Order = _orderRepository.GetAsync(orderId, cancellationToken).Adapt<OrderDto>(),
-            TrCallRecordDto = call.Adapt<TrCallDto>() 
+            TrCallRecordDto = call.Adapt<TrCallDto>()
         }, cancellationToken: cancellationToken);
         _systemLogRepository.Add("延迟更新工单通话", orderId, $"原CallId: {callId}, 更新CallId: {call.Id}", status: 1);
     }

+ 24 - 4
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -15,6 +15,7 @@ using Hotline.Share.Dtos.TrCallCenter;
 using Hotline.Share.Enums.CallCenter;
 using System.Dynamic;
 using Hotline.Share.Dtos.CallCenter;
+using Hotline.Caching.Interfaces;
 
 namespace Hotline.Application.Jobs
 {
@@ -30,6 +31,7 @@ namespace Hotline.Application.Jobs
         private readonly IMapper _mapper;
         private readonly ILogger<XingTangCallsSyncJob> _logger;
         private readonly ISqlSugarClient _db;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
         public XingTangCallsSyncJob(
             ISugarUnitOfWork<XingTangDbContext> uow,
@@ -38,7 +40,8 @@ namespace Hotline.Application.Jobs
             ICallApplication callApplication,
             ICapPublisher capPublisher,
             IMapper mapper,
-            ILogger<XingTangCallsSyncJob> logger)
+            ILogger<XingTangCallsSyncJob> logger,
+            ISystemSettingCacheManager systemSettingCacheManager)
         {
             _callRepository = callRepository;
             _userRepository = userRepository;
@@ -47,6 +50,7 @@ namespace Hotline.Application.Jobs
             _mapper = mapper;
             _logger = logger;
             _db = uow.Db;
+            _systemSettingCacheManager = systemSettingCacheManager;
         }
 
         public async Task Execute(IJobExecutionContext context)
@@ -117,10 +121,26 @@ namespace Hotline.Application.Jobs
                 await _callRepository.AddRangeAsync(calls, context.CancellationToken);
 
                 //推省上
-                if (calls.Any())
+                // 开关
+                var enable = true;
+                try
                 {
-                    var callIns = _mapper.Map<List<CallNativeDto>>(calls);
-                    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallAdd, callIns);
+                    enable = _systemSettingCacheManager.CallSyncPushEnable;
+                }
+                catch (Exception e)
+                {
+                    enable = true;
+                }
+                if (enable == true)
+                {
+                    if (calls.Any())
+                    {
+                        var callIns = _mapper.Map<List<CallNativeDto>>(calls);
+                        await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineCallAdd, callIns);
+                    }
+                }
+                else {
+                    _logger.LogError("重要事件! 通话记录同步时推省上功能已被 [关闭] !!");
                 }
                 ////todo
                 //var callIns = calls.Where(d => d.Direction == ECallDirection.In).ToList();

+ 8 - 5
src/Hotline.Application/Orders/OrderApplication.cs

@@ -942,6 +942,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, cancellationToken);
         await _orderRepository.UpdateAsync(visit.Order, cancellationToken);
         var orderDto = _mapper.Map<OrderDto>(visit.Order);
+        await _publisher.PublishAsync(new UpdateOrderVisitNotify(visit.Adapt<OrderVisitNotifyDto>()), cancellationToken);
         if (first != null)
         {
             //推省上
@@ -1074,11 +1075,13 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         }
 
         query = query.Includes(x => x.OrderScreens);
-        if (!_appOptions.Value.IsYiBin)
-        {
-            query = query.Includes(x => x.OrderVisits.Where(m => m.VisitState == EVisitState.Visited).ToList())
-         .Includes(x => x.OrderVisits.Where(m => m.VisitState == EVisitState.Visited).ToList(), ovd => ovd.OrderVisitDetails);
-        }
+
+        //if (!_appOptions.Value.IsYiBin)
+        //{
+        //    query = query.Includes(x => x.OrderVisits.Where(m => m.VisitState == EVisitState.Visited).ToList())
+        // .Includes(x => x.OrderVisits.Where(m => m.VisitState == EVisitState.Visited).ToList(), ovd => ovd.OrderVisitDetails);
+        //}
+
         query = query
          .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
          .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo.Contains(dto.ProvinceNo)) //省本地编号

+ 40 - 0
src/Hotline.Application/Orders/OrderVisitHandler/OrderVisitUpdateHandler.cs

@@ -0,0 +1,40 @@
+using DotNetCore.CAP;
+using Hotline.Application.Quality;
+using Hotline.Orders;
+using Hotline.Orders.Notifications;
+using Hotline.Share.Dtos.Order;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Quality;
+using Hotline.Users;
+using Mapster;
+using MediatR;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Orders.OrderVisitHandler;
+public class OrderVisitUpdateHandler : INotificationHandler<UpdateOrderVisitNotify>
+{
+    private readonly IOrderRepository _orderRepository;
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+
+    public OrderVisitUpdateHandler(IOrderRepository orderRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository)
+    {
+        _orderRepository = orderRepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+    }
+
+    public async Task Handle(UpdateOrderVisitNotify notification, CancellationToken cancellationToken)
+    {
+        var visit = notification.orderVisit;
+
+        var orgDetail = await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org).FirstAsync(cancellationToken);
+        var seatDetail = await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Seat).FirstAsync(cancellationToken);
+
+        await _orderRepository.Updateable()
+            .SetColumns(m => m.OrgProcessingResults == orgDetail.OrgProcessingResults)
+            .SetColumns(m => m.SeatEvaluate == seatDetail.SeatEvaluate)
+            .Where(m => m.Id == visit.OrderId)
+            .ExecuteCommandAsync(cancellationToken);
+    }
+}

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

@@ -166,6 +166,11 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public double? CenterToOrgHandleDurationWorkday { get; set; }
 
+        /// <summary>
+        /// 第一次评价结果代码
+        /// </summary>
+        public string? FirstVisitResultCode { get; set; }        
+
         #region 实际办理信息(节点,部门,意见)
 
         /// <summary>
@@ -857,57 +862,61 @@ namespace Hotline.Share.Dtos.Order
 
         #region 回访信息
 
+        ///// <summary>
+        ///// 部门满意度
+        ///// </summary>
+        //public Kv? OrgEvaluate { get; set; }
+        //{
+        //    get
+        //    {
+        //        if (this.OrderVisits == null) return null;
+        //        var visitEntity = this.OrderVisits
+        //            .OrderByDescending(m => m.CreationTime)
+        //            .FirstOrDefault();
+        //        if (visitEntity == null) return null;
+        //        return visitEntity.NowEvaluate;
+        //    }
+        //}
+
         /// <summary>
         /// 部门满意度
         /// </summary>
-        public Kv? OrgEvaluate
-        {
-            get
-            {
-                if (this.OrderVisits == null) return null;
-                var visitEntity = this.OrderVisits
-                    .OrderByDescending(m => m.CreationTime)
-                    .FirstOrDefault();
-                if (visitEntity == null) return null;
-                return visitEntity.NowEvaluate;
-            }
-        }
-
+        public Kv? OrgProcessingResults { get; set; }
 
         /// <summary>
         /// 部门满意度
         /// </summary>
-        public string? OrgEvaluateValue
-        {
-            get
-            {
-                if (this.OrderVisits == null) return null;
-                var visitEntity = this.OrderVisits
-                    .OrderByDescending(m => m.CreationTime)
-                    .FirstOrDefault();
-                if (visitEntity == null) return null;
-                var now = visitEntity.NowEvaluate;
-                if (now == null) return null;
-                return now.Value;
-            }
-        }
+        public string? OrgEvaluateValue => OrgProcessingResults != null ? OrgProcessingResults.Value : "";
+        //{
+        //    get
+        //    {
+        //        if (this.OrderVisits == null) return null;
+        //        var visitEntity = this.OrderVisits
+        //            .OrderByDescending(m => m.CreationTime)
+        //            .FirstOrDefault();
+        //        if (visitEntity == null) return null;
+        //        var now = visitEntity.NowEvaluate;
+        //        if (now == null) return null;
+        //        return now.Value;
+        //    }
+        //}
 
         /// <summary>
         /// 坐席满意度
         /// </summary>
-        public ESeatEvaluate? SeatEvaluate
-        {
-            get
-            {
-                if (this.OrderVisits == null) return null;
-                var visitEntity = this.OrderVisits
-                    .OrderByDescending(m => m.CreationTime)
-                    .FirstOrDefault();
-                if (visitEntity == null) return null;
-                return visitEntity.OrderVisitDetails.Where(m => m.VisitTarget == EVisitTarget.Seat)
-                    .FirstOrDefault()?.SeatEvaluate;
-            }
-        }
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+        //{
+        //    get
+        //    {
+        //        if (this.OrderVisits == null) return null;
+        //        var visitEntity = this.OrderVisits
+        //            .OrderByDescending(m => m.CreationTime)
+        //            .FirstOrDefault();
+        //        if (visitEntity == null) return null;
+        //        return visitEntity.OrderVisitDetails.Where(m => m.VisitTarget == EVisitTarget.Seat)
+        //            .FirstOrDefault()?.SeatEvaluate;
+        //    }
+        //}
 
         public string? SeatEvaluateTxt => SeatEvaluate?.GetDescription();
 
@@ -1621,4 +1630,4 @@ namespace Hotline.Share.Dtos.Order
                                (Status is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept
                                    or EOrderStatus.HandOverToUnAccept);
     }
-}
+}

+ 54 - 8
src/Hotline.Share/Dtos/Order/OrderVisitDto.cs

@@ -295,13 +295,14 @@ namespace Hotline.Share.Dtos.Order
         public string UserId { get; set; }
     }
 
-    public record VisitPutThroughDto { 
-    
+    public record VisitPutThroughDto
+    {
+
         public string id { get; set; }
-	}
+    }
 
 
-	public class VisitSmsInDto
+    public class VisitSmsInDto
     {
         [Required]
         public List<string> Ids { get; set; }
@@ -661,8 +662,8 @@ namespace Hotline.Share.Dtos.Order
         SMSUnsatisfied = 41,
 
         [Description("未接通")]
-		NoPutThrough =51,
-	}
+        NoPutThrough = 51,
+    }
 
 
 
@@ -934,7 +935,7 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public DateTime? ScreenByEndTime { get; set; }
 
-	}
+    }
 
     /// <summary>
     /// 回访详情的历史记录
@@ -1097,7 +1098,6 @@ namespace Hotline.Share.Dtos.Order
 
     }
 
-
     public class OrderVisitProvinceDto
     {
         public string ProvinceNo { get; set; }
@@ -1110,7 +1110,53 @@ namespace Hotline.Share.Dtos.Order
         public string VisitRemark { get; set; }
 
         public Kv VisitResult { get; set; }
+    }
+
+    /// <summary>
+    /// 回访更新事件载荷
+    /// </summary>
+    public class OrderVisitNotifyDto
+    {
+        /// <summary>
+        /// Id
+        /// </summary>
+        public string Id { get; set; }
+
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 回访详情
+        /// </summary>
+        public List<OrderVisitDetailDto> OrderVisitDetails { get; set; }
 
+        /// <summary>
+        /// 回访状态
+        /// </summary>
+        public EVisitState VisitState { get; set; }
 
+        /// <summary>
+        /// 回访方式
+        /// </summary>
+        public EVisitType? VisitType { get; set; }
+
+        /// <summary>
+        /// 回访人
+        /// </summary>
+        public string? EmployeeId { get; set; }
+
+        /// <summary>
+        /// 回访时间
+        /// </summary>
+        public DateTime? VisitTime { get; set; }
+
+        public string CreatorName { get; set; }
+
+        /// <summary>
+        /// 发布时间
+        /// </summary>
+        public DateTime PublishTime { get; set; }
     }
 }

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

@@ -38,5 +38,10 @@ namespace Hotline.Caching.Interfaces
         /// 如果超过这个时间就更新回访为默认满意
         /// </summary>
         int DefaultVisitSmsDelaySecond { get; }
+
+        /// <summary>
+        /// 通话记录同步时推送省上开关
+        /// </summary>
+        bool CallSyncPushEnable { get; }
     }
 }

+ 6 - 0
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -153,5 +153,11 @@ namespace Hotline.Caching.Services
             GetOrDefault<int>("08dc0681-a6d2-4ce7-877d-db65f846d523", SettingConstants.DefaultVisitSmsDelaySecond, "发送回访短信后等候市民回复短信的时间(秒)", 172800,
                 "发送回访短信后等候市民回复短信的时间(秒), 如果超过这个时间就更新回访为默认满意. 默认 172800.");
 
+        /// <summary>
+        /// 通话记录同步时推送省上开关
+        /// </summary>
+        public bool CallSyncPushEnable =>
+            GetOrDefault<bool>("08dc9bed-41da-4074-8289-e753e8fa8ea4", SettingConstants.CallSyncPushEnable, "同步通话记录时推省上开关(默认true)",
+                true, "在同步通话记录时是否推送到省上, 默认开启. true 或者 false");
     }
 }

+ 10 - 0
src/Hotline/Orders/Notifications/UpdateOrderVisitNotify.cs

@@ -0,0 +1,10 @@
+using Hotline.Share.Dtos.Order;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Orders.Notifications;
+public record UpdateOrderVisitNotify(OrderVisitNotifyDto orderVisit) : INotification;

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

@@ -2,6 +2,7 @@
 using Hotline.FlowEngine.Workflows;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.File;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
@@ -1059,6 +1060,19 @@ namespace Hotline.Orders
 		[SugarColumn(ColumnDescription = "话务提醒是否转办")]
 		public bool? IsForwarded { get; set; }
 
+        #region 回访信息
+        /// <summary>
+        /// 话务员评价(话务评价)
+        /// </summary>
+		[SugarColumn(ColumnDescription = "话务员评价")]
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+
+        /// <summary>
+        /// 部门办件结果
+        /// </summary>
+        [SugarColumn(ColumnDataType = "json", ColumnDescription = "部门办件结果", IsJson = true, IsNullable = true)]
+        public Kv? OrgProcessingResults { get; set; }
+        #endregion
     }
 
     public partial class Order

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

@@ -272,6 +272,8 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 
         visitedDetail.Add(seatDetail);
         await _orderVisitDetailRepository.AddRangeAsync(visitedDetail, cancellationToken);
+        await _publisher.PublishAsync(new ContingencyManagementNotify(order, order.Title, order.Content, order.ActualOpinion),
+    PublishStrategy.ParallelWhenAll, cancellationToken);
 
 
         if (order.IsProvince == false && orderVisit.VisitState == EVisitState.Visited)

+ 4 - 1
src/Hotline/Orders/OrderVisitDetail.cs

@@ -4,6 +4,7 @@ using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
 using SqlSugar;
 using XF.Domain.Repository;
+using XF.Utility.EnumExtensions;
 
 namespace Hotline.Orders
 {
@@ -104,6 +105,7 @@ namespace Hotline.Orders
         {
             this.OrgProcessingResults = visitSatisfactionKv;
             this.OrgHandledAttitude = visitSatisfactionKv;
+            this.VisitContent = visitSatisfactionKv.Value;
         }
 
         /// <summary>
@@ -111,9 +113,10 @@ namespace Hotline.Orders
         /// </summary>
         /// <param name="visitSatisfactionKv"></param>
         /// <exception cref="NotImplementedException"></exception>
-        public void ReplyBackfill(ESeatEvaluate seatEvaluate, EVoiceEvaluate voiceEvaluate)
+        public void ReplyBackfill(ESeatEvaluate seatEvaluate)
         {
             this.SeatEvaluate ??= seatEvaluate;
+            VisitContent = seatEvaluate.GetDescription();
         }
 
 		/// <summary>

+ 13 - 27
src/Hotline/Orders/OrderVisitDomainService.cs

@@ -1,27 +1,17 @@
 using DotNetCore.CAP;
 using Hotline.Caching.Interfaces;
-using Hotline.Push.FWMessage;
-using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.Push;
 using Hotline.Share.Enums.Order;
-using Hotline.Share.Enums.Quality;
 using Hotline.Share.Tools;
 using Mapster;
-using Mapster.Utils;
 using Microsoft.Extensions.Logging;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
-using static System.Runtime.InteropServices.JavaScript.JSType;
+using Hotline.EventBus;
+using Hotline.Orders.Notifications;
 
 namespace Hotline.Orders;
 public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependency
@@ -32,8 +22,9 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
     private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
     private readonly IOrderVisitRepository _orderVisitRepository;
     private readonly ICapPublisher _capPublisher;
+    private readonly Publisher _publisher;
 
-    public OrderVisitDomainService(IRepository<OrderVisitDetail> orderVisitDetailRepository, ILogger<OrderVisitDomainService> logger, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderVisitRepository orderVisitRepository, ICapPublisher capPublisher)
+    public OrderVisitDomainService(IRepository<OrderVisitDetail> orderVisitDetailRepository, ILogger<OrderVisitDomainService> logger, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderVisitRepository orderVisitRepository, ICapPublisher capPublisher, Publisher publisher)
     {
         _orderVisitDetailRepository = orderVisitDetailRepository;
         _logger = logger;
@@ -41,6 +32,7 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
         _systemDicDataCacheManager = systemDicDataCacheManager;
         _orderVisitRepository = orderVisitRepository;
         _capPublisher = capPublisher;
+        _publisher = publisher;
     }
 
     /// <summary>
@@ -122,6 +114,7 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
     public async Task UpdateSmsReplyDefaultAsync(MessageDto dto)
     {
         await _orderVisitRepository.Queryable()
+            .Includes(m => m.Order)
             .Where(m => m.Id == dto.ExternalId)
             .Where(m => m.VisitState == EVisitState.SMSVisiting)
             .FirstAsync()
@@ -140,8 +133,9 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
     /// <returns></returns>
     private async Task UpdateSmsReplyAsync(OrderVisit orderVisit, string replyTxt)
     {
+        orderVisit.Order ??= await _orderRepository.GetAsync(orderVisit.OrderId);
         orderVisit.VisitType = EVisitType.SmsVisit;
-        if (new string[] { "4", "5" }.Contains(replyTxt))
+        if (new string[] { "4", "5" , "不满意", "非常不满意" }.Contains(replyTxt))
         {
             // “短信不满意待回访”状态下,由其他方式再次进行回访,回访方式需更新为最新的回访方式
             // 故在此置为空
@@ -178,21 +172,19 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
             .FirstAsync()
             .Then(async detailSeat =>
             {
-                detailSeat.ReplyBackfill(
-                    GetVisitEvaluateByReplyTxt<ESeatEvaluate>(replyTxt),
-                    GetVisitEvaluateByReplyTxt<EVoiceEvaluate>(replyTxt)
-                    );
+                detailSeat.ReplyBackfill(GetVisitEvaluateByReplyTxt<ESeatEvaluate>(replyTxt));
                 await _orderVisitDetailRepository.UpdateAsync(detailSeat);
             });
 
+        await _publisher.PublishAsync(new UpdateOrderVisitNotify(orderVisit.Adapt<OrderVisitNotifyDto>()), cancellationToken: CancellationToken.None);
 
         if (orderVisit.VisitState != EVisitState.Visited) return;
-
+        orderVisit.Order.Visited(visitSatisfactionKv.Key, visitSatisfactionKv.Value);
+        await _orderRepository.UpdateAsync(orderVisit.Order);
         var orderDto = orderVisit.Order.Adapt<OrderDto>();
         var first = detailOrg.First();
-        if (visitSatisfactionKv != null)
+        if (visitSatisfactionKv.Key != null && visitSatisfactionKv.Value != null)
         {
-            orderVisit.Order.Visited(visitSatisfactionKv.Key, visitSatisfactionKv.Value);
             //推省上
             await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited,
                 new PublishVisitDto()
@@ -211,11 +203,5 @@ public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependenc
 
         }
 
-        //if (first != null)
-        //{
-        //    //写入质检
-        //    await _qualityApplication.AddQualityAsync(EQualitySource.Visit, orderVisit.Order.Id, orderVisit.Id,
-        //        CancellationToken.None);
-        //}
     }
 }

+ 5 - 0
src/Hotline/Settings/SettingConstants.cs

@@ -607,5 +607,10 @@ namespace Hotline.Settings
         /// 如果超过这个时间就更新回访为默认满意
         /// </summary>
         public const string DefaultVisitSmsDelaySecond = "DefaultVisitSmsDelaySecond";
+
+        /// <summary>
+        /// 通话记录同步时推送省上开关(默认true)
+        /// </summary>
+        public const string CallSyncPushEnable = "CallSyncPushEnable";
     }
 }