Explorar el Código

Merge branch 'release' of http://git.12345lm.cn/Fengwo/hotline into release

Dun.Jason hace 7 meses
padre
commit
8c6db43876
Se han modificado 46 ficheros con 606 adiciones y 253 borrados
  1. 1 1
      src/Hotline.Api/Controllers/HotSpotController.cs
  2. 13 4
      src/Hotline.Api/Controllers/KnowledgeController.cs
  3. 21 8
      src/Hotline.Api/Controllers/OrderController.cs
  4. 3 2
      src/Hotline.Api/Controllers/OrderProvinceZmhdController.cs
  5. 9 0
      src/Hotline.Api/Controllers/ProvinceStatisticsController.cs
  6. 1 1
      src/Hotline.Api/Controllers/TestController.cs
  7. 12 0
      src/Hotline.Application.Contracts/Validators/Order/AddOrderDtoValidator.cs
  8. 17 1
      src/Hotline.Application.Tests/Application/OrderApplicationTest.cs
  9. 103 0
      src/Hotline.Application.Tests/Domain/OrderVisitDomainServiceTest.cs
  10. 0 20
      src/Hotline.Application.Tests/Repository/CallNativeRepositoryTest.cs
  11. 4 41
      src/Hotline.Application.Tests/Repository/OrderVisitRepositoryTest.cs
  12. 8 5
      src/Hotline.Application/Bulletin/BulletinApplication.cs
  13. 44 0
      src/Hotline.Application/CallCenter/CallNativeApplication.cs
  14. 13 0
      src/Hotline.Application/CallCenter/ICallNativeApplication.cs
  15. 1 1
      src/Hotline.Application/Handlers/FlowEngine/WorkflowNextHandler.cs
  16. 28 0
      src/Hotline.Application/Handlers/Order/OrderVisitSmsHandler.cs
  17. 10 6
      src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs
  18. 2 0
      src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs
  19. 9 0
      src/Hotline.Application/Mappers/MapperConfigs.cs
  20. 0 1
      src/Hotline.Application/Subscribers/CallSubscriber.cs
  21. 1 30
      src/Hotline.Repository.SqlSugar/CallCenter/CallNativeRepository.cs
  22. 0 73
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs
  23. 5 0
      src/Hotline.Share/Dtos/Order/OrderProvinceZmhdDto.cs
  24. 11 0
      src/Hotline.Share/Dtos/Order/PublishedDto.cs
  25. 4 1
      src/Hotline.Share/Dtos/Order/SendBackDto.cs
  26. 10 0
      src/Hotline.Share/Dtos/ProvinceStatistics/QueryProvinceSendBackDto.cs
  27. 2 0
      src/Hotline.Share/Dtos/Push/MessageDto.cs
  28. 1 1
      src/Hotline.Share/Hotline.Share.csproj
  29. 2 2
      src/Hotline.Share/Tools/TaskExtensions.cs
  30. 1 1
      src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs
  31. 3 0
      src/Hotline/Caching/Services/SysDicDataCacheManager.cs
  32. 38 7
      src/Hotline/CallCenter/Calls/CallDomainService.cs
  33. 9 0
      src/Hotline/CallCenter/Calls/ICallDomainService.cs
  34. 0 15
      src/Hotline/CallCenter/Calls/ICallNativeRepository.cs
  35. 20 0
      src/Hotline/Orders/IOrderVisitDomainService.cs
  36. 0 7
      src/Hotline/Orders/IOrderVisitRepository.cs
  37. 6 0
      src/Hotline/Orders/OrderPublish.cs
  38. 5 1
      src/Hotline/Orders/OrderSendBackAudit.cs
  39. 17 0
      src/Hotline/Orders/OrderVisitDetail.cs
  40. 150 0
      src/Hotline/Orders/OrderVisitDomainService.cs
  41. 9 12
      src/Hotline/Push/FWMessage/PushDomainService.cs
  42. 6 0
      src/Hotline/Push/Notifies/PushMessageNotify.cs
  43. 3 10
      src/Hotline/Settings/SettingConstants.cs
  44. 1 1
      src/Hotline/Settings/TimeLimitDomain/ExpireTimeLimitBase.cs
  45. 1 1
      src/Hotline/Settings/TimeLimitDomain/ICalcExpireTime.cs
  46. 2 0
      src/XingTang.Sdk/XingtangSatisfaction.cs

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

@@ -216,7 +216,7 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <param name="dto"></param>
         /// <returns></returns>
-        [HttpPost("event/modify-event")]
+        [HttpPut("event/modify-event")]
         public async Task ModifyEventCategory([FromBody] ModifyEventCategoryDto dto)
         {
             var model = await _eventCategoryRepository.GetAsync(dto.Id, HttpContext.RequestAborted);

+ 13 - 4
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -1,5 +1,6 @@
 using DotNetCore.CAP;
 using Hotline.Api.Filter;
+using Hotline.Application.Bulletin;
 using Hotline.Application.FlowEngine;
 using Hotline.Application.Knowledge;
 using Hotline.File;
@@ -21,6 +22,7 @@ using Hotline.Users;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore.Metadata.Internal;
 using SqlSugar;
 using System.Threading;
 using XF.Domain.Authentications;
@@ -57,9 +59,10 @@ namespace Hotline.Api.Controllers
         private readonly IFileRepository _fileRepository;
         private readonly ICapPublisher _capPublisher;
         private readonly IRepository<KnowledgeRelationType> _knowledgeRelationTypeRepository;
+        private readonly IBulletinApplication _bulletinApplication;
 
 
-		public KnowledgeController(
+        public KnowledgeController(
            IKnowledgeRepository knowledgeRepository,
            ISessionContext sessionContext,
            IKnowledgeDomainService knowledgeDomainService,
@@ -81,7 +84,8 @@ namespace Hotline.Api.Controllers
            ISystemOrganizeRepository systemOrganizeRepository,
            IFileRepository fileRepository,
            ICapPublisher capPublisher,
-           IRepository<KnowledgeRelationType> knowledgeRelationTypeRepository
+           IRepository<KnowledgeRelationType> knowledgeRelationTypeRepository,
+            IBulletinApplication bulletinApplication
 		   )
         {
             _knowledgeRepository = knowledgeRepository;
@@ -106,8 +110,8 @@ namespace Hotline.Api.Controllers
             _fileRepository = fileRepository;
             _capPublisher = capPublisher;
             _knowledgeRelationTypeRepository = knowledgeRelationTypeRepository;
-
-		}
+            _bulletinApplication= bulletinApplication;
+        }
 
         #endregion
 
@@ -362,6 +366,8 @@ namespace Hotline.Api.Controllers
                 throw UserFriendlyException.SameMessage("知识查询失败!");
 
             var knowledgeInfoDto = _mapper.Map<KnowledgeInfoDto>(know);
+            if (knowledgeInfoDto != null && !string.IsNullOrEmpty(knowledgeInfoDto.Content))
+                knowledgeInfoDto.Content = _bulletinApplication.GetSiteUrls(knowledgeInfoDto.Content);
             //分类
             //var type = await _knowledgeTypeRepository.GetAsync(know.KnowledgeTypeId, HttpContext.RequestAborted);
             //if (type != null)
@@ -396,6 +402,9 @@ namespace Hotline.Api.Controllers
             //转化
             var knowledgeShowInfoDto = _mapper.Map<KnowledgeInfoDto>(knowledge);
 
+            if (knowledgeShowInfoDto != null && !string.IsNullOrEmpty(knowledgeShowInfoDto.Content))
+                knowledgeShowInfoDto.Content = _bulletinApplication.GetSiteUrls(knowledgeShowInfoDto.Content);
+
             //var type = await _knowledgeTypeRepository.GetAsync(knowledge.KnowledgeTypeId, HttpContext.RequestAborted);
             //if (type != null)
             //{

+ 21 - 8
src/Hotline.Api/Controllers/OrderController.cs

@@ -65,7 +65,6 @@ using XF.Domain.Cache;
 using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
-using XF.Domain.Repository.Extensions;
 using XF.Utility.EnumExtensions;
 using static NPOI.SS.Format.CellNumberFormatter;
 
@@ -134,6 +133,7 @@ public class OrderController : BaseController
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
     private readonly IOrderSendBackAuditApplication _orderSendBackAuditApplication;
     private readonly Publisher _publisher;
+    private readonly ICallNativeApplication _callNativeApplication;
     private readonly IOrderAnalysisApplication _orderAnalysisApplication;
     private readonly ICalcExpireTime _expireTime;
     private readonly IRepository<OrderPushType> _orderPushTypeRepository;
@@ -200,7 +200,8 @@ public class OrderController : BaseController
         ICalcExpireTime expireTime,
         IRepository<OrderPushType> orderPushTypeRepository,
         IOptions<CityBaseConfiguration> cityBaseConfiguration,
-        ICallNativeRepository callNativeRepository)
+        ICallNativeRepository callNativeRepository,
+        ICallNativeApplication callNativeApplication)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -263,6 +264,7 @@ public class OrderController : BaseController
         _orderPushTypeRepository = orderPushTypeRepository;
         _cityBaseConfiguration = cityBaseConfiguration;
         _callNativeRepository = callNativeRepository;
+        _callNativeApplication = callNativeApplication;
     }
     #endregion 
 
@@ -939,7 +941,7 @@ public class OrderController : BaseController
         var seat = orderVisit.OrderVisitDetails.FirstOrDefault(m => m.VisitTarget == EVisitTarget.Seat);
         if (orderVisit.VisitState == EVisitState.WaitForVisit)
         {   // 如果是待回访, 就取用户电话评价时评价的内容;
-            var callNative = await _callNativeRepository.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId);
+            var callNative = await _callNativeApplication.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId);
             seat.VoiceEvaluate = callNative;
         }
         return new
@@ -3230,7 +3232,7 @@ public class OrderController : BaseController
             var pushTypeAny = await _orderPushTypeRepository.AnyAsync(x => x.OrderId == order.Id);
             if (pushTypeAny)
                 await _orderPushTypeRepository.RemoveAsync(x => x.OrderId == order.Id);
-            order.OrderPushTypes.ForEach(x => x.OrderId = order.Id);
+            dto.OrderPushTypes.ForEach(x => x.OrderId = order.Id);
             var orderPushTypes = _mapper.Map<List<OrderPushType>>(dto.OrderPushTypes);
             await _orderPushTypeRepository.AddRangeAsync(orderPushTypes);
             var pushTypes = dto.OrderPushTypes.Select(x => x.PushType);
@@ -4056,7 +4058,10 @@ public class OrderController : BaseController
             Status = order.Status,
             TraceId = currentStep.Id
         };
-        if (_appOptions.Value.IsZiGong && prevStep.BusinessType == EBusinessType.Send)
+        audit.InitId();
+		if (dto.Files.Any())
+	        audit.FileJson = await _fileRepository.AddFileAsync(dto.Files, audit.Id, "", HttpContext.RequestAborted);
+		if (_appOptions.Value.IsZiGong && prevStep.BusinessType == EBusinessType.Send)
         {
             // 平均派单
             var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]);
@@ -4284,12 +4289,20 @@ public class OrderController : BaseController
     /// <param name="id"></param>
     /// <returns></returns>
     [HttpGet("order_previous/{id}")]
-    public async Task<OrderSendBackAudit> OrderSendBackEntity(string id)
+    public async Task<SendBackDto> OrderSendBackEntity(string id)
     {
-        return await _orderSendBackAuditRepository.Queryable()
+        var res =  await _orderSendBackAuditRepository.Queryable()
             .Includes(x => x.Order)
             .FirstAsync(x => x.Id == id);
-    }
+        var resDto = _mapper.Map<SendBackDto>(res);
+        if (res.FileJson != null && res.FileJson.Any())
+        {
+	        var ids = res.FileJson.Select(x => x.Id).ToList();
+	        var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+	        resDto.Files = files.Where(x => x.Classify == "退回附件" && string.IsNullOrEmpty(x.FlowKey)).ToList();
+        }
+        return resDto;
+	}
 
     /// <summary>
     /// 列表页面基础数据

+ 3 - 2
src/Hotline.Api/Controllers/OrderProvinceZmhdController.cs

@@ -48,9 +48,10 @@ namespace Hotline.Api.Controllers
         {
             RefAsync<int> total = 0;
             var items = await _orderRepository.Queryable()
-                .Where(p => p.SourceChannelCode == "SZMHD" && p.IsProvince == false && p.Status >= EOrderStatus.Filed && p.Source == ESource.ProvinceStraight)
+                .Where(p => p.SourceChannelCode == "SZMHD"  && p.Status >= EOrderStatus.Filed && p.Source == ESource.ProvinceStraight)
                 .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
-                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ReceiveProvinceNo == dto.ProvinceNo)
+                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo == dto.ProvinceNo)
+                 .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                 .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.StartsWith(dto.Title!))
                 .WhereIF(!string.IsNullOrEmpty(dto.AnswerOu), p => p.ActualHandleOrgName == dto.AnswerOu)
                 .WhereIF(!string.IsNullOrEmpty(dto.AuditFirstName), p => p.AuditFirstName == dto.AuditFirstName)

+ 9 - 0
src/Hotline.Api/Controllers/ProvinceStatisticsController.cs

@@ -70,6 +70,7 @@ namespace Hotline.Api.Controllers
                            .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), p => p.CreatorName == dto.ApplyUserName)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.CreationTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.CreationTime <= dto.ApplyEndTime.Value)
@@ -127,6 +128,7 @@ namespace Hotline.Api.Controllers
                            .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), p => p.EmployeeName == dto.ApplyUserName)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.ApplyDelayTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.ApplyDelayTime <= dto.ApplyEndTime.Value)
@@ -192,6 +194,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(!string.IsNullOrEmpty(dto.ApplyUserName), p => p.CreatorName == dto.ApplyUserName)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.CreationTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.CreationTime <= dto.ApplyEndTime.Value)
@@ -248,6 +251,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.RevokeTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.RevokeTime <= dto.ApplyEndTime.Value)
                            .OrderByDescending(x => x.RevokeTime)
@@ -284,6 +288,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.WarnDate >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.WarnDate <= dto.ApplyEndTime.Value)
                            .OrderByDescending(x => x.WarnDate)
@@ -320,6 +325,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.RemindTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.RemindTime <= dto.ApplyEndTime.Value)
                            .OrderByDescending(x => x.RemindTime)
@@ -356,6 +362,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.SupplyTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.SupplyTime <= dto.ApplyEndTime.Value)
                            .OrderByDescending(x => x.SupplyTime)
@@ -392,6 +399,7 @@ namespace Hotline.Api.Controllers
                           .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.Order.No == dto.No)
                            .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Order.Title == dto.Title)
                            .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.Order.ProvinceNo == dto.ProvinceNo)
+                           .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.Order.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                            .WhereIF(dto.ApplyStartTime.HasValue, p => p.SuperviseTime >= dto.ApplyStartTime.Value)
                            .WhereIF(dto.ApplyEndTime.HasValue, p => p.SuperviseTime <= dto.ApplyEndTime.Value)
                            .WhereIF(!string.IsNullOrEmpty(dto.OrgName), p => p.OrgName.Contains(dto.OrgName))
@@ -432,6 +440,7 @@ namespace Hotline.Api.Controllers
                .WhereIF(!string.IsNullOrEmpty(dto.No), p => p.No == dto.No)
                .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title == dto.Title)
                .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo == dto.ProvinceNo)
+               .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), p => p.ReceiveProvinceNo == dto.ReceiveProvinceNo)
                .WhereIF(dto.ApplyStartTime.HasValue, p => p.CreationTime >= dto.ApplyStartTime.Value)
                .WhereIF(dto.ApplyEndTime.HasValue, p => p.CreationTime <= dto.ApplyEndTime.Value)
                .OrderByDescending(p => p.CreationTime)

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

@@ -697,7 +697,7 @@ ICallApplication callApplication,
         //return users.Id;
         var b = _cityBaseConfiguration.Value;
 
-		var a = await _expireTime.WorkDay_ZG(DateTime.Now);
+		var a = await _expireTime.GetWorkDay(DateTime.Now);
         return string.Empty;
 	}
 

+ 12 - 0
src/Hotline.Application.Contracts/Validators/Order/AddOrderDtoValidator.cs

@@ -0,0 +1,12 @@
+using FluentValidation;
+using Hotline.Share.Dtos.Order;
+
+namespace Hotline.Application.Contracts.Validators.Order;
+
+public class AddOrderDtoValidator : AbstractValidator<AddOrderDto>
+{
+    public AddOrderDtoValidator()
+    {
+        RuleFor(d => d.Content).NotEmpty().WithMessage("请填写工单内容");
+    }
+}

+ 17 - 1
src/Hotline.Application.Tests/Application/OrderApplicationTest.cs

@@ -1,7 +1,10 @@
 using Hotline.Application.Orders;
 using Hotline.Orders;
+using Hotline.Push.FWMessage;
+using Hotline.Push.Notifies;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Order;
+using Mapster;
 using Shouldly;
 using System;
 using System.Collections.Generic;
@@ -15,11 +18,14 @@ public class OrderApplicationTest
 {
     private readonly IOrderApplication _orderApplication;
     private readonly IRepository<OrderVisit> _orderVisitRepository;
+    private readonly IRepository<Message> _messageRepository;
 
-    public OrderApplicationTest(IOrderApplication orderApplication, IRepository<OrderVisit> orderVisitRepository)
+
+    public OrderApplicationTest(IOrderApplication orderApplication, IRepository<OrderVisit> orderVisitRepository, IRepository<Message> messageRepository)
     {
         _orderApplication = orderApplication;
         _orderVisitRepository = orderVisitRepository;
+        _messageRepository = messageRepository;
     }
 
     [Theory]
@@ -46,4 +52,14 @@ public class OrderApplicationTest
         visit.VisitState.ShouldBe(EVisitState.SMSVisiting);
         visit.VisitType.ShouldBe(EVisitType.SmsVisit);
     }
+
+    [Fact]
+    public async Task MapConfig_Test()
+    {
+        var data = await _messageRepository.Queryable().OrderByDescending(m => m.CreationTime)
+            .FirstAsync();
+        var m = data.Adapt<ReceiveMessageNotify>();
+        m.NotifyDto.Name.ShouldBe(data.Name);
+        m.NotifyDto.PushBusiness.ShouldBe(data.PushBusiness);
+    }
 }

+ 103 - 0
src/Hotline.Application.Tests/Domain/OrderVisitDomainServiceTest.cs

@@ -0,0 +1,103 @@
+using Hotline.EventBus;
+using Hotline.Orders;
+using Hotline.Push.FWMessage;
+using Hotline.Push.Notifies;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Push;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Enums.Push;
+using Hotline.Share.Tools;
+using Mapster;
+using Shouldly;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Domain;
+public class OrderVisitDomainServiceTest
+{
+    private readonly IOrderVisitDomainService _orderVisitDomainService;
+    private readonly IOrderVisitRepository _orderVisitRepository;
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly Publisher _publisher;
+
+    public OrderVisitDomainServiceTest(IOrderVisitDomainService orderVisitDomainService, IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, Publisher publisher)
+    {
+        _orderVisitDomainService = orderVisitDomainService;
+        _orderVisitRepository = orderVisitRepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _publisher = publisher;
+    }
+
+    [Fact]
+    public async Task OnSmsUpdate_Test()
+    {
+        var data = new Message() { IsSmsReply = true, SmsReplyContent = "1", PushBusiness = EPushBusiness.VisitSms };
+        await _publisher.PublishAsync(data.Adapt<ReceiveMessageNotify>(), PublishStrategy.ParallelNoWait, new CancellationToken());
+    }
+
+    [Theory]
+    [InlineData("4", "SMSUnsatisfied", "2", "不满意")]
+    [InlineData("1", "Visited", "5", "非常满意")]
+    [InlineData("非常满意", "Visited", "5", "非常满意")]
+    [InlineData("满意", "Visited", "4", "满意")]
+    [InlineData("一般", "Visited", "4", "满意")]
+    [InlineData("不满意", "SMSUnsatisfied", "2", "不满意")]
+    [InlineData("非常不满意", "SMSUnsatisfied", "2", "不满意")]
+    public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey, string orgResuktValue)
+    {
+        var visit = await _orderVisitRepository.Queryable()
+            .Where(m => m.VisitState == EVisitState.SMSVisiting)
+            .OrderByDescending(m => m.CreationTime)
+            .FirstAsync();
+        visit.ShouldNotBeNull("缺少测试数据");
+
+        var message = new MessageDto { ExternalId = visit.Id, IsSmsReply = true, SmsReplyContent = content };
+        var dto = new PushReceiveMessageDto();
+        await _orderVisitDomainService.UpdateSmsReplyAsync(message);
+        visit = _orderVisitRepository.Get(visit.Id);
+        visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
+        visit.NowEvaluate.Key.ShouldBe(orgResuktKey);
+        visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
+
+        if (content == "4" || content == "5" || content == "不满意" || content == "非常不满意")
+            visit.VisitType.ShouldBeNull();
+
+        await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
+            .FirstAsync()
+            .Then(async org =>
+            {
+                org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
+                org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
+                org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
+                org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
+            });
+    }
+
+    [Theory]
+    [InlineData("1", "非常满意", "Visited", "VerySatisfied", "VerySatisfied", "非常满意|5")]
+    [InlineData("2", "满意", "Visited", "Satisfied", "Satisfied", "满意|4")]
+    [InlineData("3", "一般", "Visited", "Normal", "Normal", "满意|4")]
+    [InlineData("4", "不满意", "SMSUnsatisfied", "NoSatisfied", "NoSatisfied", "不满意|2")]
+    [InlineData("5", "非常不满意", "SMSUnsatisfied", "NoSatisfied", "VeryNoSatisfied", "不满意|2")]
+    [InlineData("默认满意", "默认满意", "Visited", "DefaultSatisfied", "DefaultSatisfied", "满意|4")]
+    public void GetVisitEvaluateByReplyTxt_Test(string replyTxt, string assertReplyTxt, string visitState, string seatEvaluate, string voiceEvaluate, string kv)
+    {
+        var replyString = _orderVisitDomainService.GetVisitEvaluateByReplyTxt<string>(replyTxt);
+        replyString.ShouldBe(assertReplyTxt);
+
+        var visitStateEnum = _orderVisitDomainService.GetVisitEvaluateByReplyTxt<EVisitState>(replyTxt);
+        visitStateEnum.ShouldBe(visitState.ToEnum<EVisitState>());
+
+        var seatEvaluateEnum = _orderVisitDomainService.GetVisitEvaluateByReplyTxt<ESeatEvaluate>(replyTxt);
+        seatEvaluateEnum.ShouldBe(seatEvaluate.ToEnum<ESeatEvaluate>());
+
+        var voiceEvaluateEnum = _orderVisitDomainService.GetVisitEvaluateByReplyTxt<EVoiceEvaluate>(replyTxt);
+        voiceEvaluateEnum.ShouldBe(voiceEvaluate.ToEnum<EVoiceEvaluate>());
+
+        var kvResult = _orderVisitDomainService.GetVisitEvaluateByReplyTxt<Kv>(replyTxt);
+        var sp = kv.Split('|');
+        var kV = new Kv(sp[1].ToString(), sp[0].ToString());
+        kvResult.Key.ShouldBe(kV.Key);
+        kvResult.Value.ShouldBe(kV.Value);
+    }
+}

+ 0 - 20
src/Hotline.Application.Tests/Repository/CallNativeRepositoryTest.cs

@@ -21,24 +21,4 @@ public class CallNativeRepositoryTest
         _callNativeRepository = callNativeRepository;
         _orderRepository = orderRepository;
     }
-
-    [Theory]
-    [InlineData("", "DefaultSatisfied")]
-    [InlineData("1", "VerySatisfied")]
-    [InlineData("2", "Satisfied")]
-    [InlineData("3", "Normal")]
-    [InlineData("4", "NoSatisfied")]
-    [InlineData("5", "VeryNoSatisfied")]
-    public async Task GetReplyVoiceOrDefaultByOrderId_Test(string replyTxt, string enumString)
-    {
-        var order = await _orderRepository.Queryable()
-            .OrderByDescending(m => m.CreationTime)
-            .Where(m => m.CallId != "")
-            .FirstAsync();
-
-        await _callNativeRepository.UpdateReplyTxtAsync(order.CallId, replyTxt);
-
-        var result = await _callNativeRepository.GetReplyVoiceOrDefaultByOrderIdAsync(order.Id);
-        result.ShouldBe(enumString.ToEnum<EVoiceEvaluate>());
-    }
 }

+ 4 - 41
src/Hotline.Application.Tests/Repository/OrderVisitRepositoryTest.cs

@@ -10,56 +10,19 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 using XF.Domain.Repository;
-using XF.Domain.Repository.Extensions;
 
 namespace Hotline.Application.Tests.Repository;
 public class OrderVisitRepositoryTest
 {
     private readonly IOrderVisitRepository _orderVisitRepository;
     private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly IOrderVisitDomainService _orderVisitDomainService;
 
-    public OrderVisitRepositoryTest(IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository)
+    public OrderVisitRepositoryTest(IOrderVisitRepository orderVisitRepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, IOrderVisitDomainService orderVisitDomainService)
     {
         _orderVisitRepository = orderVisitRepository;
         _orderVisitDetailRepository = orderVisitDetailRepository;
+        _orderVisitDomainService = orderVisitDomainService;
     }
 
-    [Theory]
-    [InlineData("4", "SMSUnsatisfied", "2" , "不满意")]
-    [InlineData("1", "Visited", "5", "非常满意")]
-    [InlineData("非常满意", "Visited", "5", "非常满意")]
-    [InlineData("满意", "Visited", "4", "满意")]
-    [InlineData("一般", "Visited", "4", "满意")]
-    [InlineData("不满意", "SMSUnsatisfied", "2", "不满意")]
-    [InlineData("非常不满意", "SMSUnsatisfied", "2", "不满意")]
-    public async Task UpdateSmsReply_Test(string content, string visitState, string orgResuktKey,  string orgResuktValue)
-    {
-        var visit = await _orderVisitRepository.Queryable()
-            .Where(m => m.VisitState == EVisitState.SMSVisiting)
-            .OrderByDescending(m => m.CreationTime)
-            .FirstAsync();
-        visit.ShouldNotBeNull("缺少测试数据");
-
-        var message = new Message { ExternalId = visit.Id, IsSmsReply = true, SmsReplyContent = content };
-        var dto = new PushReceiveMessageDto();
-        await _orderVisitRepository.UpdateSmsReplyAsync(dto, message);
-        visit = _orderVisitRepository.Get(visit.Id);
-        visit.VisitState.ShouldBe(visitState.ToEnum<EVisitState>());
-        visit.NowEvaluate.Key.ShouldBe(orgResuktKey);
-        visit.NowEvaluate.Value.ShouldBe(orgResuktValue);
-
-        if (content == "4" || content == "5" || content == "不满意" || content == "非常不满意")
-            visit.VisitType.ShouldBeNull();
-
-        await _orderVisitDetailRepository.Queryable()
-            .Where(m => m.VisitId == visit.Id && m.VisitTarget == EVisitTarget.Org)
-            .FirstAsync()
-            .Then(async org =>
-            {
-                org.OrgProcessingResults.Key.ShouldBe(orgResuktKey);
-                org.OrgProcessingResults.Value.ShouldBe(orgResuktValue);
-                org.OrgHandledAttitude.Key.ShouldBe(orgResuktKey);
-                org.OrgHandledAttitude.Value.ShouldBe(orgResuktValue);
-            });
-    }
-}
+  }

+ 8 - 5
src/Hotline.Application/Bulletin/BulletinApplication.cs

@@ -1,4 +1,6 @@
-using Hotline.Configurations;
+using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
+using Hotline.Settings;
 using Microsoft.Extensions.Options;
 using System.Text;
 using System.Text.RegularExpressions;
@@ -9,10 +11,13 @@ namespace Hotline.Application.Bulletin
     public class BulletinApplication : IBulletinApplication, IScopeDependency
     {
         private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+        private readonly ISystemSettingCacheManager _systemSettingCacheManager;
 
-        public BulletinApplication(IOptionsSnapshot<AppConfiguration> appOptions)
+        public BulletinApplication(IOptionsSnapshot<AppConfiguration> appOptions,
+                 ISystemSettingCacheManager systemSettingCacheManager)
         {
             _appOptions = appOptions;
+            _systemSettingCacheManager= systemSettingCacheManager; 
         }
 
         /// <summary>
@@ -37,9 +42,7 @@ namespace Hotline.Application.Bulletin
             // 搜索匹配的字符串
             MatchCollection matchesvideo = regvideo.Matches(sHtmlText);
 
-
-            // 获取服务器地址配置 
-            string strSiteUrl = _appOptions.Value.OldFilesUrls;
+            var strSiteUrl = _systemSettingCacheManager.GetSetting(SettingConstants.OldFilesUrls)?.SettingValue[0];
          
             // 取得匹配项列表 视频
             foreach (Match match in matchesvideo)

+ 44 - 0
src/Hotline.Application/CallCenter/CallNativeApplication.cs

@@ -0,0 +1,44 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.CallCenter;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+
+namespace Hotline.Application.CallCenter;
+public class CallNativeApplication : ICallNativeApplication, IScopeDependency
+{
+    private readonly ICallNativeRepository _callNativeRepository;
+    private readonly ICallDomainService _callDomainService;
+    private readonly IOrderVisitDomainService _orderVisitDomainService;
+
+    public CallNativeApplication(ICallNativeRepository callNativeRepository, IOrderVisitDomainService orderVisitDomainService, ICallDomainService callDomainService)
+    {
+        _callNativeRepository = callNativeRepository;
+        _orderVisitDomainService = orderVisitDomainService;
+        _callDomainService = callDomainService;
+    }
+
+    /// <summary>
+    /// 根据 OrderId 返回用户电话评价枚举
+    /// 默认返回 默认满意
+    /// </summary>
+    /// <param name="orderId"></param>
+    /// <returns></returns>
+    public async Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId)
+    {
+        var callNative = await _callDomainService.GetByOrderIdAsync(orderId);
+        if (callNative is null || callNative.ReplyTxt.IsNullOrEmpty())
+            return EVoiceEvaluate.DefaultSatisfied;
+
+        try
+        {
+            return _orderVisitDomainService.GetVisitEvaluateByReplyTxt<EVoiceEvaluate>(callNative.ReplyTxt!.Trim());
+        }
+        catch (UserFriendlyException)
+        {
+            return EVoiceEvaluate.DefaultSatisfied;
+        }
+    }
+}

+ 13 - 0
src/Hotline.Application/CallCenter/ICallNativeApplication.cs

@@ -0,0 +1,13 @@
+using Hotline.Share.Enums.Order;
+
+namespace Hotline.Application.CallCenter;
+public interface  ICallNativeApplication
+{
+    /// <summary>
+    /// 根据 OrderId 返回用户电话评价枚举
+    /// 默认返回 默认满意
+    /// </summary>
+    /// <param name="orderId"></param>
+    /// <returns></returns>
+    Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId);
+}

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

@@ -158,7 +158,7 @@ public class WorkflowNextHandler : INotificationHandler<NextStepNotify>
                     //    expiredTimeChanged = true;
                     //}
                     if (data.FlowDirection is EFlowDirection.CenterToOrg)
-                        order.SendBackAuditEndTime = await _expireTime.WorkDay_ZG(DateTime.Now);
+                        order.SendBackAuditEndTime = await _expireTime.GetWorkDay(DateTime.Now);
 					await _orderRepository.Updateable(order).ExecuteCommandAsync(cancellationToken);
                     //await _orderRepository.UpdateAsync(order, cancellationToken);
 

+ 28 - 0
src/Hotline.Application/Handlers/Order/OrderVisitSmsHandler.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
+using Hotline.Orders.Notifications;
+using Hotline.Push.Notifies;
+using Hotline.Share.Enums.Push;
+using MediatR;
+
+namespace Hotline.Application.Handlers.Order;
+public class OrderVisitSmsHandler : INotificationHandler<ReceiveMessageNotify>
+{
+    private readonly IOrderVisitDomainService _orderVisitDomainService;
+
+    public OrderVisitSmsHandler(IOrderVisitDomainService orderVisitDomainService)
+    {
+        _orderVisitDomainService = orderVisitDomainService;
+    }
+
+    public async Task Handle(ReceiveMessageNotify notification, CancellationToken cancellationToken)
+    {
+        if (notification.NotifyDto.PushBusiness == EPushBusiness.VisitSms)
+            await _orderVisitDomainService.UpdateSmsReplyAsync(notification.NotifyDto);
+    }
+}

+ 10 - 6
src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs

@@ -27,7 +27,9 @@ namespace Hotline.Application.Jobs
         private readonly ILogger<XingTangCallSatisfactionSyncJob> _logger;
         private readonly ICapPublisher _capPublisher;
 
-        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISqlSugarClient db, IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger, ICapPublisher capPublisher)
+        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISqlSugarClient db,
+            IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger,
+            ICapPublisher capPublisher)
         {
             _callRepository = callRepository;
             _db = db;
@@ -49,6 +51,7 @@ namespace Hotline.Application.Jobs
                 .Take(10)
                 .ToListAsync(context.CancellationToken);
 
+            if (!callSatisfactions.Any()) return;
             var occupyCallSatisfactions = new List<XingtangSatisfaction>();
             foreach (var callSatisfaction in callSatisfactions)
             {
@@ -61,19 +64,22 @@ namespace Hotline.Application.Jobs
                     occupyCallSatisfactions.Add(callSatisfaction);
             }
 
+            if (!occupyCallSatisfactions.Any()) return;
             try
             {
                 var callStatisfactions = _mapper.Map<List<CallSatisfaction>>(occupyCallSatisfactions);
                 foreach (var item in callSatisfactions)
                 {
                     var call = _callRepository.Queryable().Where(x => x.CallNo == item.CallNo).FirstAsync();
-                    if(call != null)
+                    if (call != null)
                     {
                         item.Id = call.Id;
                     }
                 }
+
                 await _callSatisfactionRepository.AddRangeAsync(callStatisfactions, context.CancellationToken);
-                await _capPublisher.PublishAsync(EventNames.HotlineCallSatisfactionAdd, callStatisfactions, cancellationToken: context.CancellationToken);
+                await _capPublisher.PublishAsync(EventNames.HotlineCallSatisfactionAdd, callStatisfactions,
+                    cancellationToken: context.CancellationToken);
             }
             catch (Exception e)
             {
@@ -87,8 +93,6 @@ namespace Hotline.Application.Jobs
                     .UpdateColumns(d => new { d.IsSync })
                     .ExecuteCommandAsync(context.CancellationToken);
             }
-
-
         }
     }
-}
+}

+ 2 - 0
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -56,6 +56,7 @@ namespace Hotline.Application.Jobs
                 .Take(10)
                 .ToListAsync(context.CancellationToken);
 
+            if(!xingtangCalls.Any()) return;
             var occupyCalls = new List<XingtangCall>();
             foreach (var call in xingtangCalls)
             {
@@ -68,6 +69,7 @@ namespace Hotline.Application.Jobs
                     occupyCalls.Add(call);
             }
 
+            if(!occupyCalls.Any()) return;
             try
             {
                 var calls = _mapper.Map<List<CallNative>>(occupyCalls);

+ 9 - 0
src/Hotline.Application/Mappers/MapperConfigs.cs

@@ -2,7 +2,9 @@
 using Hotline.JudicialManagement;
 using Hotline.Orders;
 using Hotline.Push.FWMessage;
+using Hotline.Push.Notifies;
 using Hotline.Settings;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Ai;
 using Hotline.Share.Dtos.CallCenter;
 using Hotline.Share.Dtos.JudicialManagement;
@@ -21,6 +23,13 @@ namespace Hotline.Application.Mappers
     {
         public void Register(TypeAdapterConfig config)
         {
+            config.ForType<SystemDicData, Kv>()
+                .Map(s => s.Key, d => d.DicDataValue)
+                .Map(s => s.Value, d => d.DicDataName);
+
+            config.ForType<Message, ReceiveMessageNotify>()
+                .Map(m => m.NotifyDto, d => d);
+
             config.ForType<Tr.Sdk.Tels.QueryTelResponse, TelOutDto>()
                 .Map(m => m.TelPwd, x => x.Password)
                 .Map(m =>m.Queue, x => x.QueueId);

+ 0 - 1
src/Hotline.Application/Subscribers/CallSubscriber.cs

@@ -14,7 +14,6 @@ using System.Threading.Tasks;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
-using XF.Domain.Repository.Extensions;
 
 namespace Hotline.Application.Subscribers;
 public class CallSubscriber : ICapSubscribe, ITransientDependency

+ 1 - 30
src/Hotline.Repository.SqlSugar/CallCenter/CallNativeRepository.cs

@@ -16,10 +16,8 @@ using XF.Domain.Repository;
 namespace Hotline.Repository.SqlSugar.CallCenter;
 public class CallNativeRepository : BaseRepository<CallNative>, ICallNativeRepository, IScopeDependency
 {
-    private readonly IRepository<Order> _orderRepository;
-    public CallNativeRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IRepository<Order> orderRepository) : base(uow, dataPermissionFilterBuilder)
+    public CallNativeRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder) : base(uow, dataPermissionFilterBuilder)
     {
-        _orderRepository = orderRepository;
     }
 
     public async Task<int> UpdateReplyTxtAsync(string callId, string replyTxt)
@@ -29,31 +27,4 @@ public class CallNativeRepository : BaseRepository<CallNative>, ICallNativeRepos
             .SetColumns(m => m.ReplyTxt, replyTxt)
             .ExecuteCommandAsync();
     }
-
-    public async Task<CallNative?> GetByOrderIdAsync(string orderId)
-    {
-        var callId = await _orderRepository
-            .Queryable()
-            .Where(m => m.Id == orderId)
-            .Select(m => m.CallId)
-            .FirstAsync();
-        if (callId.IsNullOrEmpty())
-            return null;
-        return await GetAsync(callId);
-    }
-
-    public async Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId)
-    {
-        var callNative = await GetByOrderIdAsync(orderId);
-        if (callNative is null || callNative.ReplyTxt.IsNullOrEmpty())
-            return EVoiceEvaluate.DefaultSatisfied;
-
-        var replyTxt = callNative.ReplyTxt.Trim();
-        if (SettingConstants.ReplyToEnumMap.TryGetValue(replyTxt, out var result))
-        {
-            var replySplit = result.Split('|');
-            return replySplit[3].ToEnum<EVoiceEvaluate>();
-        }
-        return EVoiceEvaluate.DefaultSatisfied;
-    }
 }

+ 0 - 73
src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs

@@ -13,7 +13,6 @@ using SqlSugar;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
-using XF.Domain.Repository.Extensions;
 using static System.Runtime.InteropServices.JavaScript.JSType;
 
 namespace Hotline.Repository.SqlSugar.Orders;
@@ -32,76 +31,4 @@ public class OrderVisitRepository : BaseRepository<OrderVisit>, IOrderVisitRepos
         _systemDicDataCacheManager = systemDicDataCacheManager;
     }
 
-    /// <summary>
-    /// 用户回访短信回复更新回访状态
-    /// </summary>
-    /// <param name="dto"></param>
-    /// <param name="data"></param>
-    /// <returns></returns>
-    public async Task UpdateSmsReplyAsync(PushReceiveMessageDto dto, Message data)
-    {
-        _logger.LogInformation($"UpdateSmsReplyAsync 收到通知: {dto.ToJson()}");
-        if (data.IsSmsReply == false || data.SmsReplyContent.IsNullOrEmpty() || data.ExternalId.IsNullOrEmpty()) return;
-
-        var orderVisit = await GetAsync(data.ExternalId)
-             ?? throw new UserFriendlyException($"回访单不存在, visitId: {data.ExternalId} message: {data.ToJson()}");
-
-        if (orderVisit.VisitState == EVisitState.Visited)
-            throw new UserFriendlyException($"回访单已回访. visitId: {data.ExternalId}");
-
-        var replyTxt = data.SmsReplyContent.Trim();
-        var result = string.Empty;
-        if (SettingConstants.ReplyToEnumMap.TryGetValue(replyTxt, out result) == false)
-        {
-            var m = SettingConstants.ReplyToEnumMap.FirstOrDefault(item => item.Value.StartsWith(replyTxt));
-            replyTxt = m.Key;
-            result = m.Value;
-        }
-
-        if (result.IsNullOrEmpty()) throw new UserFriendlyException($"用户回复短信内容异常; reply: {data.SmsReplyContent}");
-        var replySplit = result.Split("|");
-        if (new string[] { "4", "5" }.Contains(replyTxt))
-        {
-            // “短信不满意待回访”状态下,由其他方式再次进行回访,回访方式需更新为最新的回访方式
-            // 故在此置为空
-            orderVisit.VisitType = null;
-        }
-        var visitSatisfaction = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction)
-            .First(m => m.DicDataValue == replySplit[4]);
-        orderVisit.NowEvaluate = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
-
-        orderVisit.VisitTime = DateTime.Now;
-        orderVisit.VisitState = replySplit[1].ToEnum<EVisitState>();
-        await UpdateAsync(orderVisit, ignoreNullColumns: false);
-
-        if (orderVisit.VisitState == EVisitState.Visited)
-        {
-            await _orderRepository.GetAsync(orderVisit.OrderId)
-                .Then(async order =>
-                {
-                    order.Visited(replyTxt, replySplit[0]);
-                    await _orderRepository.UpdateAsync(order);
-                });
-
-        }
-        var detailOrg = await _orderVisitDetailRepository.Queryable()
-            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Org)
-            .ToListAsync();
-        foreach (var item in detailOrg)
-        {
-            item.OrgProcessingResults = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
-            item.OrgHandledAttitude = new Share.Dtos.Kv(visitSatisfaction.DicDataValue, visitSatisfaction.DicDataName);
-            await _orderVisitDetailRepository.UpdateAsync(item);
-        }
-
-        await _orderVisitDetailRepository.Queryable()
-            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Seat)
-            .FirstAsync()
-            .Then(async detailSeat =>
-            {
-                detailSeat.SeatEvaluate ??= replySplit[2].ToEnum<ESeatEvaluate>();
-                detailSeat.VoiceEvaluate ??= replySplit[3].ToEnum<EVoiceEvaluate>();
-                await _orderVisitDetailRepository.UpdateAsync(detailSeat);
-            });
-    }
 }

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

@@ -17,6 +17,11 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? ProvinceNo { get; set; }
 
+        /// <summary>
+        /// 省交办工单编号
+        /// </summary>
+        public string? ReceiveProvinceNo { get; set; }
+        
         /// <summary>
         /// 工单标题
         /// </summary>

+ 11 - 0
src/Hotline.Share/Dtos/Order/PublishedDto.cs

@@ -258,6 +258,11 @@ public class PublishPublishOrderDto
     /// </summary>
     public string Remark { get; set; }
 
+    /// <summary>
+    /// 答复口径
+    /// </summary>
+    public string AnswerContent { get; set; }
+
     #endregion
 }
 
@@ -300,6 +305,7 @@ public class PublishOrderDto
     /// 省是否公开
     /// </summary>
     public bool? ProPublishState { get; set; }
+
     /// <summary>
     /// 反馈人电话
     /// </summary>
@@ -335,6 +341,11 @@ public class PublishOrderDto
     /// </summary>
     public string? Remark { get; set; }
 
+    /// <summary>
+    /// 答复口径
+    /// </summary>
+    public string? AnswerContent { get; set; }
+
     #endregion
 
     /// <summary>

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

@@ -122,7 +122,10 @@ namespace Hotline.Share.Dtos.Order
 		}
 
 		public bool IsReturnAgainShow => ApplyOrgId != "001" && SendBackOrgId == "001";
-
+		/// <summary>
+		/// 附件列表
+		/// </summary>
+		public List<FileDto> Files { get; set; } = new();
 	}
 	public class SendBackBaseDto
 	{

+ 10 - 0
src/Hotline.Share/Dtos/ProvinceStatistics/QueryProvinceSendBackDto.cs

@@ -19,6 +19,11 @@ namespace Hotline.Share.Dtos.ProvinceStatistics
         /// </summary>
         public string? ProvinceNo { get; set; }
 
+        /// <summary>
+        /// 省交办编号
+        /// </summary>
+        public string? ReceiveProvinceNo { get; set; }
+
         /// <summary>
         /// 申请人
         /// </summary>
@@ -60,6 +65,11 @@ namespace Hotline.Share.Dtos.ProvinceStatistics
         /// </summary>
         public string? ProvinceNo { get; set; }
 
+        /// <summary>
+        /// 省交办编号
+        /// </summary>
+        public string? ReceiveProvinceNo { get; set; }
+
         /// <summary>
         /// 督办标题
         /// </summary>

+ 2 - 0
src/Hotline.Share/Dtos/Push/MessageDto.cs

@@ -53,5 +53,7 @@ namespace Hotline.Share.Dtos.Push
         /// 参数
         /// </summary>
         public List<string>? Params { get; set; }
+        public bool IsSmsReply { get; set; }
+        public string? SmsReplyContent { get; set; }
     }
 }

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

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

+ 2 - 2
src/Hotline.Share/Tools/TaskExtensions.cs

@@ -1,4 +1,4 @@
-namespace XF.Domain.Repository.Extensions;
+namespace Hotline.Share.Tools;
 public static class TaskExtensions
 {
     /// <summary>
@@ -18,4 +18,4 @@ public static class TaskExtensions
         }
     }
 }
-  
+

+ 1 - 1
src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs

@@ -10,7 +10,7 @@ namespace Hotline.Caching.Interfaces
     public interface ISystemDicDataCacheManager
     {
         IReadOnlyList<SystemDicData> GetSysDicDataCache(string code);
-
+        IReadOnlyList<SystemDicData> GetVisitSatisfaction();
         void RemoveSysDicDataCache(string code);
     }
 }

+ 3 - 0
src/Hotline/Caching/Services/SysDicDataCacheManager.cs

@@ -26,6 +26,9 @@ namespace Hotline.Caching.Services
             return sysDicDataList;
         }
 
+        public IReadOnlyList<SystemDicData> GetVisitSatisfaction()
+            => GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction);
+
         public void RemoveSysDicDataCache(string code)
         {
             _cacheSysDicData.Remove(code);

+ 38 - 7
src/Hotline/CallCenter/Calls/CallDomainService.cs

@@ -1,7 +1,11 @@
 using Hotline.CallCenter.Configs;
 using Hotline.CallCenter.Devices;
 using Hotline.Configurations;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.CallCenter;
+using Hotline.Share.Enums.Order;
 using Hotline.Share.Requests;
+using Hotline.Share.Tools;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Options;
 using XF.Domain.Dependency;
@@ -15,13 +19,17 @@ namespace Hotline.CallCenter.Calls
         private readonly ICallRepository _callRepository;
         private readonly ICallDetailRepository _callDetailRepository;
         private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;
+        private readonly IOrderRepository _orderRepository;
+        private readonly ICallNativeRepository _callNativeRepository;
 
         public CallDomainService(
             IServiceProvider serviceProvider,
-            ICallRepository callRepository, 
+            ICallRepository callRepository,
             ICallDetailRepository callDetailRepository,
             IOptionsSnapshot<AppConfiguration> appOptions,
-            IOptionsSnapshot<CallCenterConfiguration> callcenterOptions)
+            IOptionsSnapshot<CallCenterConfiguration> callcenterOptions,
+            IOrderRepository orderRepository,
+            ICallNativeRepository callNativeRepository)
         {
             _callRepository = callRepository;
             _callDetailRepository = callDetailRepository;
@@ -30,6 +38,9 @@ namespace Hotline.CallCenter.Calls
             {
                 _newRockDeviceManager = serviceProvider.GetRequiredService<INewRockDeviceManager>();
             }
+
+            _orderRepository = orderRepository;
+            _callNativeRepository = callNativeRepository;
         }
 
         #region 来电
@@ -114,7 +125,7 @@ namespace Hotline.CallCenter.Calls
         /// <param name="request"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task ExtToOuterAsync(ExtToOuterRequest request,CancellationToken cancellationToken)
+        public async Task ExtToOuterAsync(ExtToOuterRequest request, CancellationToken cancellationToken)
         {
             //var callModel = new Call()
             //{
@@ -164,7 +175,7 @@ namespace Hotline.CallCenter.Calls
         /// <param name="request"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task MonitorExt(MonitorExtRequest request,CancellationToken cancellationToken)
+        public async Task MonitorExt(MonitorExtRequest request, CancellationToken cancellationToken)
         {
             await _newRockDeviceManager.MonitorExtAsync(_callcenterOptions.Value.NewRock, request.firstTelNo, request.secondTelNo, cancellationToken);
         }
@@ -178,7 +189,7 @@ namespace Hotline.CallCenter.Calls
         /// <param name="request"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task MonitorExtToTalk(MonitorExtToTalkRequest request,CancellationToken cancellationToken)
+        public async Task MonitorExtToTalk(MonitorExtToTalkRequest request, CancellationToken cancellationToken)
         {
             await _newRockDeviceManager.MonitorExtToTalkAsync(_callcenterOptions.Value.NewRock, request.telNo, cancellationToken);
         }
@@ -192,7 +203,7 @@ namespace Hotline.CallCenter.Calls
         /// <param name="request"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task MonitorExtToListen(MonitorExtToListenRequest request,CancellationToken cancellationToken)
+        public async Task MonitorExtToListen(MonitorExtToListenRequest request, CancellationToken cancellationToken)
         {
             await _newRockDeviceManager.MonitorExtToListenAsync(_callcenterOptions.Value.NewRock, request.telNo, cancellationToken);
         }
@@ -210,12 +221,32 @@ namespace Hotline.CallCenter.Calls
         /// <param name="request"></param>
         /// <param name="cancellationToken"></param>
         /// <returns></returns>
-        public async Task BargeinExt(BargeinExtRequest request,CancellationToken cancellationToken)
+        public async Task BargeinExt(BargeinExtRequest request, CancellationToken cancellationToken)
         {
             await _newRockDeviceManager.BargeinExtAsync(_callcenterOptions.Value.NewRock, request.firstTelNo, request.secondTelNo, cancellationToken);
         }
 
         #endregion
 
+
+        #region 电话评价
+
+        /// <summary>
+        /// 根据OrderId 获取电话评价
+        /// </summary>
+        /// <param name="orderId"></param>
+        /// <returns></returns>
+        public async Task<CallNative?> GetByOrderIdAsync(string orderId)
+        {
+            var callId = await _orderRepository.Queryable()
+                .Where(m => m.Id == orderId)
+                .Select(m => m.CallId)
+                .FirstAsync();
+            if (callId.IsNullOrEmpty())
+                return null;
+            return await _callNativeRepository.GetAsync(callId);
+        }
+
+        #endregion
     }
 }

+ 9 - 0
src/Hotline/CallCenter/Calls/ICallDomainService.cs

@@ -110,5 +110,14 @@ namespace Hotline.CallCenter.Calls
         Task BargeinExt(BargeinExtRequest request, CancellationToken cancellationToken);
 
         #endregion
+
+        #region 电话评价
+        /// <summary>
+        /// 根据OrderId 获取电话评价
+        /// </summary>
+        /// <param name="orderId"></param>
+        /// <returns></returns>
+        Task<CallNative?> GetByOrderIdAsync(string orderId);
+        #endregion
     }
 }

+ 0 - 15
src/Hotline/CallCenter/Calls/ICallNativeRepository.cs

@@ -11,19 +11,4 @@ namespace Hotline.Repository.SqlSugar.CallCenter;
 public interface ICallNativeRepository : IRepository<CallNative>
 {
     Task<int> UpdateReplyTxtAsync(string callId, string replyTxt);
-
-    /// <summary>
-    /// 根据 OrderId 返回用户电话评价枚举
-    /// 默认返回 默认满意
-    /// </summary>
-    /// <param name="orderId"></param>
-    /// <returns></returns>
-    Task<EVoiceEvaluate> GetReplyVoiceOrDefaultByOrderIdAsync(string orderId);
-
-    /// <summary>
-    /// 根据 OrderId 查询实体
-    /// </summary>
-    /// <param name="orderId"></param>
-    /// <returns></returns>
-    Task<CallNative?> GetByOrderIdAsync(string orderId);
 }

+ 20 - 0
src/Hotline/Orders/IOrderVisitDomainService.cs

@@ -0,0 +1,20 @@
+using Hotline.Share.Dtos.Push;
+
+namespace Hotline.Orders;
+public interface IOrderVisitDomainService
+{
+    /// <summary>
+    /// 根据用户短信或电话回复的内容转换成系统中对应的评价
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="replyTxt"></param>
+    /// <returns></returns>
+    T GetVisitEvaluateByReplyTxt<T>(string replyTxt);
+
+    /// <summary>
+    /// 收到用户回复的短信后回填回访信息
+    /// </summary>
+    /// <param name="data"></param>
+    /// <returns></returns>
+    Task UpdateSmsReplyAsync(MessageDto data);
+}

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

@@ -4,11 +4,4 @@ using XF.Domain.Repository;
 namespace Hotline.Orders;
 public interface IOrderVisitRepository : IRepository<OrderVisit>
 {
-    /// <summary>
-    /// 用户回访短信回复更新回访状态
-    /// </summary>
-    /// <param name="dto"></param>
-    /// <param name="data"></param>
-    /// <returns></returns>
-    Task UpdateSmsReplyAsync(Share.Dtos.Push.PushReceiveMessageDto dto, Push.FWMessage.Message data);
 }

+ 6 - 0
src/Hotline/Orders/OrderPublish.cs

@@ -92,6 +92,12 @@ public class OrderPublish : FullStateEntity
     /// 备注
     /// </summary>
     public string? Remark { get; set; }
+
+    /// <summary>
+    /// 答复口径
+    /// </summary>
+    [SugarColumn(ColumnDataType = "varchar(8000)", IsNullable = true)]
+    public string? AnswerContent { get; set; }
     #endregion
 
     public bool? Resolve { get; set; }

+ 5 - 1
src/Hotline/Orders/OrderSendBackAudit.cs

@@ -1,4 +1,5 @@
-using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Enums.Order;
 using SqlSugar;
 using System;
@@ -144,5 +145,8 @@ namespace Hotline.Orders
 		/// </summary>
 		[SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true, ColumnDescription = "流程退回发起用户角色ID")]
 		public List<string> WorkflowRoleIds { get; set; }
+
+		[SugarColumn(ColumnDataType = "json", IsJson = true, IsNullable = true)]
+		public List<FileJson>? FileJson { get; set; }
 	}
 }

+ 17 - 0
src/Hotline/Orders/OrderVisitDetail.cs

@@ -94,5 +94,22 @@ namespace Hotline.Orders
         /// 回访对象类型 10:话务员 20:部门
         /// </summary>
         public EVisitTarget VisitTarget { get; set; }
+
+        /// <summary>
+        /// 短信回访回填
+        /// </summary>
+        /// <param name="visitSatisfactionKv"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        public void ReplyBackfill(Kv visitSatisfactionKv)
+        {
+            this.OrgProcessingResults = visitSatisfactionKv;
+            this.OrgHandledAttitude = visitSatisfactionKv;
+        }
+
+        public void ReplyBackfill(ESeatEvaluate seatEvaluate, EVoiceEvaluate voiceEvaluate)
+        {
+            this.SeatEvaluate ??= seatEvaluate;
+            this.VoiceEvaluate ??= voiceEvaluate;
+        }
     }
 }

+ 150 - 0
src/Hotline/Orders/OrderVisitDomainService.cs

@@ -0,0 +1,150 @@
+using Hotline.Caching.Interfaces;
+using Hotline.Push.FWMessage;
+using Hotline.Settings;
+using Hotline.Share.Dtos;
+using Hotline.Share.Dtos.Push;
+using Hotline.Share.Enums.Order;
+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.Tasks;
+using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders;
+public class OrderVisitDomainService : IOrderVisitDomainService, IScopeDependency
+{
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly ILogger<OrderVisitDomainService> _logger;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+    private readonly IOrderVisitRepository _orderVisitRepository;
+
+
+    public OrderVisitDomainService(IRepository<OrderVisitDetail> orderVisitDetailRepository, ILogger<OrderVisitDomainService> logger, IRepository<Order> orderRepository, ISystemDicDataCacheManager systemDicDataCacheManager, IOrderVisitRepository orderVisitRepository)
+    {
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _logger = logger;
+        _orderRepository = orderRepository;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+        _orderVisitRepository = orderVisitRepository;
+    }
+
+    /// <summary>
+    /// 用户回访短信回复更新回访状态
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="data"></param>
+    /// <returns></returns>
+    public async Task UpdateSmsReplyAsync(MessageDto data)
+    {
+        _logger.LogInformation($"UpdateSmsReplyAsync 收到通知: {data.ToJson()}");
+        if (data.IsSmsReply == false || data.SmsReplyContent.IsNullOrEmpty() || data.ExternalId.IsNullOrEmpty()) return;
+
+        var orderVisit = await _orderVisitRepository.GetAsync(data.ExternalId!)
+             ?? throw new UserFriendlyException($"回访单不存在, visitId: {data.ExternalId} message: {data.ToJson()}");
+
+        if (orderVisit.VisitState == EVisitState.Visited)
+            throw new UserFriendlyException($"回访单已回访. visitId: {data.ExternalId}");
+
+        var replyTxt = data.SmsReplyContent!;
+        if (new string[] { "4", "5" }.Contains(replyTxt))
+        {
+            // “短信不满意待回访”状态下,由其他方式再次进行回访,回访方式需更新为最新的回访方式
+            // 故在此置为空
+            orderVisit.VisitType = null;
+        }
+        var visitSatisfactionKv = GetVisitEvaluateByReplyTxt<Kv>(replyTxt);
+        orderVisit.NowEvaluate = visitSatisfactionKv;
+
+        orderVisit.VisitTime = DateTime.Now;
+        orderVisit.VisitState = GetVisitEvaluateByReplyTxt<EVisitState>(replyTxt);
+        await _orderVisitRepository.UpdateAsync(orderVisit, ignoreNullColumns: false);
+
+        if (orderVisit.VisitState == EVisitState.Visited)
+        {
+            await _orderRepository.GetAsync(orderVisit.OrderId)
+                .Then(async order =>
+                {
+                    order!.Visited(replyTxt, GetVisitEvaluateByReplyTxt<string>(replyTxt));
+                    await _orderRepository.UpdateAsync(order);
+                });
+
+        }
+        var detailOrg = await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Org)
+            .ToListAsync();
+        foreach (var item in detailOrg)
+        {
+            item.ReplyBackfill(visitSatisfactionKv);
+        }
+        await _orderVisitDetailRepository.UpdateRangeAsync(detailOrg);
+
+        await _orderVisitDetailRepository.Queryable()
+            .Where(m => m.VisitId == orderVisit.Id && m.VisitTarget == EVisitTarget.Seat)
+            .FirstAsync()
+            .Then(async detailSeat =>
+            {
+                detailSeat.ReplyBackfill(
+                    GetVisitEvaluateByReplyTxt<ESeatEvaluate>(replyTxt),
+                    GetVisitEvaluateByReplyTxt<EVoiceEvaluate>(replyTxt)
+                    );
+                await _orderVisitDetailRepository.UpdateAsync(detailSeat);
+            });
+    }
+
+    /// <summary>
+    /// 根据用户短信或电话回复的内容转换成系统中对应的评价
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <param name="replyTxt"></param>
+    /// <returns></returns>
+    /// <exception cref="UserFriendlyException"></exception>
+    public T GetVisitEvaluateByReplyTxt<T>(string replyTxt)
+    {
+        Dictionary<string, string> ReplyToEnumMap = new()
+        {
+            { "1", $"非常满意|{EVisitState.Visited}|{ESeatEvaluate.VerySatisfied}|{EVoiceEvaluate.VerySatisfied}|5" },
+            { "2", $"满意|{EVisitState.Visited}|{ESeatEvaluate.Satisfied}|{EVoiceEvaluate.Satisfied}|4"},
+            { "3", $"一般|{EVisitState.Visited}|{ESeatEvaluate.Normal}|{EVoiceEvaluate.Normal}|4"},
+            { "4", $"不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.NoSatisfied}|2"},
+            { "5", $"非常不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.VeryNoSatisfied}|2"},
+            { "默认满意", $"默认满意|{EVisitState.Visited}|{ESeatEvaluate.DefaultSatisfied}|{EVoiceEvaluate.DefaultSatisfied}|4"},
+        };
+        replyTxt = replyTxt.Trim();
+        if (ReplyToEnumMap.TryGetValue(replyTxt, out var result) == false)
+        {
+            var m = ReplyToEnumMap.FirstOrDefault(item => item.Value.StartsWith(replyTxt));
+            replyTxt = m.Key;
+            result = m.Value;
+        }
+
+        if (result.IsNullOrEmpty()) throw new UserFriendlyException($"用户回复内容异常; replyTxt: {replyTxt}");
+        var replySplit = result.Split("|");
+
+        if (typeof(T) == typeof(string))
+            return (T)(replySplit[0] as object);
+
+        if (typeof(T) == typeof(EVisitState))
+            return (T)Enum.Parse(typeof(T), replySplit[1]);
+
+        if (typeof(T) == typeof(ESeatEvaluate))
+            return (T)Enum.Parse(typeof(T), replySplit[2]);
+
+        if (typeof(T) == typeof(EVoiceEvaluate))
+            return (T)Enum.Parse(typeof(T), replySplit[3]);
+
+        if (typeof(T) == typeof(Kv))
+            return _systemDicDataCacheManager.GetVisitSatisfaction()
+           .First(m => m.DicDataValue == replySplit[4]).Adapt<T>();
+
+        return default;
+    }
+}

+ 9 - 12
src/Hotline/Push/FWMessage/PushDomainService.cs

@@ -1,8 +1,11 @@
 using DotNetCore.CAP;
+using Hotline.EventBus;
 using Hotline.Orders;
+using Hotline.Push.Notifies;
 using Hotline.Share.Dtos.Push;
 using Hotline.Share.Dtos.SendSms;
 using Hotline.Share.Enums.Push;
+using Mapster;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Http;
@@ -30,6 +33,8 @@ public class PushDomainService : IPushDomainService, IScopeDependency
     private readonly ICapPublisher _capPublisher;
     private readonly ILogger<PushDomainService> _logger;
     private readonly IOrderVisitRepository _orderVisitRepository;
+    private readonly Publisher _publisher;
+
 
     /// <summary>
     /// 
@@ -45,7 +50,8 @@ public class PushDomainService : IPushDomainService, IScopeDependency
         ICapPublisher capPublisher,
         ILogger<PushDomainService> logger
 ,
-        IOrderVisitRepository orderVisitRepository)
+        IOrderVisitRepository orderVisitRepository,
+        Publisher publisher)
     {
         _messageRepository = messageRepository;
         _mapper = mapper;
@@ -53,6 +59,7 @@ public class PushDomainService : IPushDomainService, IScopeDependency
         _capPublisher = capPublisher;
         _logger = logger;
         _orderVisitRepository = orderVisitRepository;
+        _publisher = publisher;
     }
     #endregion
 
@@ -123,7 +130,6 @@ public class PushDomainService : IPushDomainService, IScopeDependency
     /// <returns></returns>
     public async Task PushMsgUpdateStateAsync(PushReceiveMessageDto dto, CancellationToken cancellation)
     {
-        _logger.LogInformation("收到短信通知 PushMsgUpdateStateAsync");
         var data = await _messageRepository.GetAsync(p => p.Id == dto.ExternalId, cancellation);
         if (data != null)
         {
@@ -150,19 +156,10 @@ public class PushDomainService : IPushDomainService, IScopeDependency
                 data.IsSmsReply = dto.IsSmsReply;
                 data.SmsReplyTime = Convert.ToDateTime(dto.SmsReplyTime);
                 data.SmsReplyContent = dto.SmsReplyContent;
-
-                try
-                {
-                    if (data.PushBusiness == EPushBusiness.VisitSms)
-                        await _orderVisitRepository.UpdateSmsReplyAsync(dto, data);
-                }
-                catch (Exception e)
-                {
-                    _logger.LogError("_orderVisitRepository.UpdateSmsReplyAsync: " + e.Message);
-                }           
             }
             data.Reason = dto.Reason;
             await _messageRepository.UpdateAsync(data, cancellation);
+            await _publisher.PublishAsync(data.Adapt<ReceiveMessageNotify>(), PublishStrategy.ParallelNoWait, cancellation);
         }
     }
 

+ 6 - 0
src/Hotline/Push/Notifies/PushMessageNotify.cs

@@ -4,4 +4,10 @@ using MediatR;
 namespace Hotline.Push.Notifies
 {
     public record PushMessageNotify(MessageDto NotifyDto) : INotification;
+
+    /// <summary>
+    /// 收到短信
+    /// </summary>
+    /// <param name="NotifyDto"></param>
+    public record ReceiveMessageNotify(MessageDto NotifyDto) : INotification;
 }

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

@@ -507,15 +507,8 @@ namespace Hotline.Settings
         public const string FixedQueryCount = "FixedQueryCount";
 
         /// <summary>
-        /// 短信回访和电话回访用户回复的内容和系统中各个枚举的对应信息
-        /// </summary>
-        public static readonly Dictionary<string, string> ReplyToEnumMap = new()
-        {
-            { "1", $"非常满意|{EVisitState.Visited}|{ESeatEvaluate.VerySatisfied}|{EVoiceEvaluate.VerySatisfied}|5" },
-            { "2", $"满意|{EVisitState.Visited}|{ESeatEvaluate.Satisfied}|{EVoiceEvaluate.Satisfied}|4"},
-            { "3", $"一般|{EVisitState.Visited}|{ESeatEvaluate.Normal}|{EVoiceEvaluate.Normal}|4"},
-            { "4", $"不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.NoSatisfied}|2"},
-            { "5", $"非常不满意|{EVisitState.SMSUnsatisfied}|{ESeatEvaluate.NoSatisfied}|{EVoiceEvaluate.VeryNoSatisfied}|2"},
-        };
+        /// 旧数据通知公告知识库附件地址	
+        /// </summary>
+        public const string OldFilesUrls = "OldFilesUrls";
     }
 }

+ 1 - 1
src/Hotline/Settings/TimeLimitDomain/ExpireTimeLimitBase.cs

@@ -76,7 +76,7 @@ public abstract class ExpireTimeLimitBase
         return date;
     }
 
-    public virtual async Task<DateTime> WorkDay_ZG(DateTime date)
+    public virtual async Task<DateTime> GetWorkDay(DateTime date)
     {
 	 
 		if (await IsWorkDay(date))

+ 1 - 1
src/Hotline/Settings/TimeLimitDomain/ICalcExpireTime.cs

@@ -27,7 +27,7 @@ public interface ICalcExpireTime
     Task<int> CalcWorkTime(DateTime beginTime, DateTime endTime, bool isCenter);
     Task<int> CalcWorkTimeEx(DateTime beginTime, DateTime endTime, bool isCenter);
     Task<DateTime> WorkDay(DateTime now);
-    Task<DateTime> WorkDay_ZG(DateTime now);
+    Task<DateTime> GetWorkDay(DateTime now);
 
 	Task<TimeResult> CalcEndTime(DateTime beginTime, ETimeType timeType, int timeValue, int Percentage, int PercentageOne);
 

+ 2 - 0
src/XingTang.Sdk/XingtangSatisfaction.cs

@@ -12,11 +12,13 @@ namespace XingTang.Sdk
     {
         [SugarColumn(IsPrimaryKey = true)]
         public int Id { get; set; }
+        
         /// <summary>
         /// 通话ID
         /// </summary>
         [SugarColumn(ColumnName = "callguid")]
         public string CallNo { get; set; }
+        
         /// <summary>
         /// 评价结果
         /// </summary>