瀏覽代碼

Merge branch 'release' of http://110.188.24.182:10023/Fengwo/hotline into release

田爽 7 月之前
父節點
當前提交
82c87fa807
共有 24 個文件被更改,包括 427 次插入140 次删除
  1. 1 1
      src/Hotline.Api/Controllers/AiController.cs
  2. 13 4
      src/Hotline.Api/Controllers/KnowledgeController.cs
  3. 52 62
      src/Hotline.Api/Controllers/OrderController.cs
  4. 8 8
      src/Hotline.Api/StartupHelper.cs
  5. 17 17
      src/Hotline.Api/config/appsettings.Development.json
  6. 44 0
      src/Hotline.Application.Tests/Repository/CallNativeRepositoryTest.cs
  7. 8 5
      src/Hotline.Application/Bulletin/BulletinApplication.cs
  8. 7 3
      src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs
  9. 1 0
      src/Hotline.Application/Mappers/OrderMapperConfigs.cs
  10. 1 0
      src/Hotline.Application/Orders/OrderApplication.cs
  11. 73 0
      src/Hotline.Application/Subscribers/CallSubscriber.cs
  12. 18 14
      src/Hotline.Application/Subscribers/DatasharingSubscriber.cs
  13. 59 0
      src/Hotline.Repository.SqlSugar/CallCenter/CallNativeRepository.cs
  14. 5 11
      src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs
  15. 4 0
      src/Hotline.Share/Dtos/Order/QueryOrderDto.cs
  16. 6 1
      src/Hotline.Share/Mq/EventNames.Call.cs
  17. 1 2
      src/Hotline.Share/Mq/EventNames.Order.cs
  18. 38 0
      src/Hotline.Share/Tools/RetryHelper.cs
  19. 7 1
      src/Hotline/CallCenter/Calls/CallNative.cs
  20. 8 8
      src/Hotline/CallCenter/Calls/CallSatisfaction.cs
  21. 29 0
      src/Hotline/CallCenter/Calls/ICallNativeRepository.cs
  22. 2 1
      src/Hotline/Orders/IOrderVisitRepository.cs
  23. 24 1
      src/Hotline/Settings/SettingConstants.cs
  24. 1 1
      src/Hotline/Settings/TimeLimitDomain/ExpireTimeLimitBase.cs

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

@@ -1021,7 +1021,7 @@ namespace Hotline.Api.Controllers
                 .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType)//受理类型
                 .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.No.Contains(dto.No)) //工单编码
                 .WhereIF(!string.IsNullOrEmpty(dto.Title),x=> x.Order.Title.Contains(dto.Title))
-                .Where(x=> SqlFunc.Length(x.Order.Contact.Length)>6)
+                .Where(x=> !string.IsNullOrEmpty(x.Order.Contact) && SqlFunc.Length(x.Order.Contact)>6)
                 .ToListAsync();
             return _mapper.Map<IReadOnlyList<OrderVisitDto>>(items);
         }

+ 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)
             //{

+ 52 - 62
src/Hotline.Api/Controllers/OrderController.cs

@@ -7,6 +7,7 @@ using Hotline.Application.Orders;
 using Hotline.Application.Quality;
 using Hotline.Caching.Interfaces;
 using Hotline.Caching.Services;
+using Hotline.CallCenter.Calls;
 using Hotline.Configurations;
 using Hotline.ContingencyManagement.Notifies;
 using Hotline.EventBus;
@@ -21,6 +22,7 @@ using Hotline.OrderTranspond;
 using Hotline.Permissions;
 using Hotline.Push.FWMessage;
 using Hotline.Push.Notifies;
+using Hotline.Repository.SqlSugar.CallCenter;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Repository.SqlSugar.Ts;
 using Hotline.SeedData;
@@ -63,6 +65,7 @@ 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;
 
@@ -127,6 +130,7 @@ public class OrderController : BaseController
     private readonly IRepository<ExternalCitizens> _externalCitizensRepository;
     private readonly IRepository<OrderModifyingRecords> _orderModifyingRecordsRepository;
     private readonly ICallApplication _callApplication;
+    private readonly ICallNativeRepository _callNativeRepository;
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
     private readonly IOrderSendBackAuditApplication _orderSendBackAuditApplication;
     private readonly Publisher _publisher;
@@ -135,7 +139,7 @@ public class OrderController : BaseController
     private readonly IRepository<OrderPushType> _orderPushTypeRepository;
     private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
-	public OrderController(
+    public OrderController(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         IWorkflowApplication workflowApplication,
@@ -195,7 +199,8 @@ public class OrderController : BaseController
         IOrderAnalysisApplication orderAnalysisApplication,
         ICalcExpireTime expireTime,
         IRepository<OrderPushType> orderPushTypeRepository,
-        IOptions<CityBaseConfiguration> cityBaseConfiguration)
+        IOptions<CityBaseConfiguration> cityBaseConfiguration,
+        ICallNativeRepository callNativeRepository)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -257,7 +262,8 @@ public class OrderController : BaseController
         _expireTime = expireTime;
         _orderPushTypeRepository = orderPushTypeRepository;
         _cityBaseConfiguration = cityBaseConfiguration;
-	}
+        _callNativeRepository = callNativeRepository;
+    }
     #endregion 
 
     #region 工单发布
@@ -386,7 +392,7 @@ public class OrderController : BaseController
                     orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
                     orgDetail.VisitOrgName = order.ActualHandleOrgName;
                     orgDetail.VisitTarget = EVisitTarget.Org;
-                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null , IsProvince: false })
+                    if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null, IsProvince: false })
                     {
                         var satisfy = new Kv() { Key = "4", Value = "满意" };
                         orgDetail.OrgProcessingResults = satisfy;
@@ -548,7 +554,7 @@ public class OrderController : BaseController
             visitedDetail.Add(orgDetail);
         }
 
-        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null,IsProvince:false })
+        if (order is { ProcessType: EProcessType.Zhiban, CounterSignType: null, IsProvince: false })
         {
             seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied;
             seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied;
@@ -930,6 +936,12 @@ public class OrderController : BaseController
                 VisitTime = m.VisitTime
             }).ToListAsync();
 
+        var seat = orderVisit.OrderVisitDetails.FirstOrDefault(m => m.VisitTarget == EVisitTarget.Seat);
+        if (orderVisit.VisitState == EVisitState.WaitForVisit)
+        {   // 如果是待回访, 就取用户电话评价时评价的内容;
+            var callNative = await _callNativeRepository.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId);
+            seat.VoiceEvaluate = callNative;
+        }
         return new
         {
             OrderVisitModel = _mapper.Map<OrderVisitDto>(orderVisit),
@@ -1012,38 +1024,42 @@ public class OrderController : BaseController
             .Where(m => m.VisitId == visit.VisitId)
             .ToListAsync();
                 var seatDetail = details.First(m => m.VisitTarget == EVisitTarget.Seat);
+                var seatDetailDto = new VisitDetailDto()
+                {
+                    Id = seatDetail.Id,
+                    VisitId = visit.VisitId,
+                    VisitContent = dto.SeatVisitContent,
+                    SeatEvaluate = dto.SeatEvaluate,
+                    VisitTarget = EVisitTarget.Seat,
+                };
+                if (seatDetail.VoiceEvaluate == null)
+                    seatDetailDto.VoiceEvaluate = EVoiceEvaluate.DefaultSatisfied;
+
                 var visitDto = new VisitDto
                 {
                     Id = visit.VisitId,
                     IsPutThrough = true,
                     IsAgain = false,
-                    VisitDetails = new List<VisitDetailDto>
-                    {
-                new()
-                {
-                Id = seatDetail.Id,
-                VisitId = visit.VisitId,
-                VisitContent = dto.SeatVisitContent,
-                SeatEvaluate = dto.SeatEvaluate,
-                                VisitTarget = EVisitTarget.Seat
-                }
-                    }
+                    VisitDetails = new List<VisitDetailDto>()
                 };
+                visitDto.VisitDetails.Add(seatDetailDto);
 
                 var orgDetails = details.Where(m => m.VisitTarget == EVisitTarget.Org).ToList();
                 foreach (var orgDetail in orgDetails)
                 {
                     visitDto.VisitDetails.Add(
-            new()
-            {
-                Id = orgDetail.Id,
-                VisitId = visit.VisitId,
-                VisitContent = dto.OrgVisitContent,
-                VisitTarget = EVisitTarget.Org,
-                OrgNoSatisfiedReason = dto.OrgNoSatisfiedReason,
-                OrgProcessingResults = dto.OrgProcessingResults,
-                OrgHandledAttitude = dto.OrgHandledAttitude
-            });
+                new()
+                {
+                    Id = orgDetail.Id,
+                    VisitId = visit.VisitId,
+                    VisitContent = dto.OrgVisitContent,
+                    VisitTarget = EVisitTarget.Org,
+                    OrgNoSatisfiedReason = dto.OrgNoSatisfiedReason,
+                    OrgProcessingResults = dto.OrgProcessingResults,
+                    OrgHandledAttitude = dto.OrgHandledAttitude,
+                    VisitOrgName = orgDetail.VisitOrgName,
+                    VisitOrgCode = orgDetail.VisitOrgCode,
+                });
                 }
                 await _orderApplication.SaveOrderVisit(visitDto, HttpContext.RequestAborted);
                 outDto.CompleteCount += 1;
@@ -2670,8 +2686,10 @@ public class OrderController : BaseController
     [HttpGet("fixed")]
     public async Task<IReadOnlyList<OrderDto>> QueryFixed([FromQuery] QueryOrderFixedDto dto)
     {
+        var hasSetting = Int32.TryParse(
+             _systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0], out var queryCount);
         var query = _orderApplication.QueryOrders(dto);
-        var orders = await query.ToFixedListAsync(dto.QueryIndex, cancellationToken: HttpContext.RequestAborted);
+        var orders = await query.ToFixedListAsync(dto.QueryIndex, hasSetting ? queryCount : null, HttpContext.RequestAborted);
         return _mapper.Map<IReadOnlyList<OrderDto>>(orders);
     }
 
@@ -2679,7 +2697,7 @@ public class OrderController : BaseController
     /// 查询总数
     /// </summary>
     [HttpGet("count")]
-    public async Task<int> Count([FromQuery] QueryOrderFixedDto dto)
+    public async Task<int> Count([FromQuery] QueryOrderDto dto)
     {
         var query = _orderApplication.QueryOrders(dto);
         return await query.CountAsync(HttpContext.RequestAborted);
@@ -3252,7 +3270,6 @@ public class OrderController : BaseController
         ExpiredTimeWithConfig expiredTimeConfig;
         if (dto.Workflow.NextHandlers.Any(d => d.Key == _cityBaseConfiguration.Value.CityProvince.OrgId || d.Key == _cityBaseConfiguration.Value.CityProvinceAssign.OrgId))
         {
-            // var timeResult = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 45, 80, 50);
             var timeResult = await _expireTime.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 45, 80, 50);
             expiredTimeConfig = new ExpiredTimeWithConfig
             {
@@ -3264,18 +3281,6 @@ public class OrderController : BaseController
                 NearlyExpiredTimeOne = timeResult.NearlyExpiredTimeOne,
             };
         }
-        //else if (dto.Workflow.FlowDirection == EFlowDirection.CenterToCenter)
-        //{
-        // var timeResult = _timeLimitDomainService.CalcEndTime(DateTime.Now, ETimeType.WorkDay, 1, 0);
-        // expiredTimeConfig = new ExpiredTimeWithConfig
-        // {
-        //  Count = 1,
-        //  TimeType = ETimeType.WorkDay,
-        //  TimeText = "1个工作日",
-        //  ExpiredTime = timeResult.EndTime,
-        //  NearlyExpiredTime = timeResult.NearlyExpiredTime
-        // };
-        //}
         else
         {
             if (_appOptions.Value.IsZiGong)
@@ -3316,21 +3321,6 @@ public class OrderController : BaseController
         }
         //开启流程处理事件,处理市州互转
         await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
-        //{
-        //    var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted);
-        //    var orderDto = _mapper.Map<OrderDto>(order);
-        //    await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderTranspondCity, orderDto);
-        //    //保存本地数据
-        //    TranspondCityRawData cityRawData = new TranspondCityRawData
-        //    {
-        //        OrderCode = order.No,
-        //        TransferOutTime = DateTime.Now,
-        //        CityName = order.TranspondCityName,
-        //        Direction = ETranspondDirection.Out
-        //    };
-
-        //    await _transpondCityRawDataRepository.AddAsync(cityRawData, HttpContext.RequestAborted);
-        //}
     }
 
     /// <summary>
@@ -3686,7 +3676,7 @@ public class OrderController : BaseController
     public async Task<PagedDto<OrderDto>> QueryWaited([FromQuery] QueryOrderWaitedDto dto)
     {
         var isHandled = dto.IsHandled.HasValue && dto.IsHandled.Value;
-       
+
         var isAdmin = _orderDomainService.IsCheckAdmin();
 
         var (total, items) = await _orderRepository
@@ -4815,12 +4805,12 @@ public class OrderController : BaseController
             var orderStatus = EOrderStatus.SendBack;
             var orderStartStatus = EOrderStatus.BackToUnAccept;
 
-			if (_appOptions.Value.IsZiGong)
+            if (_appOptions.Value.IsZiGong)
             {
-	            orderStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.SendBack : EOrderStatus.Special;
-	            orderStartStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.BackToUnAccept : EOrderStatus.SpecialToUnAccept;
-			}
-			var Status = model.StepType == EStepType.Start ? orderStartStatus : orderStatus;
+                orderStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.SendBack : EOrderStatus.Special;
+                orderStartStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.BackToUnAccept : EOrderStatus.SpecialToUnAccept;
+            }
+            var Status = model.StepType == EStepType.Start ? orderStartStatus : orderStatus;
             await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType, ReTransactNum = reTransactNum, Status = Status }).Where(o => o.Id == order.Id)
                 .ExecuteCommandAsync(HttpContext.RequestAborted);
 

+ 8 - 8
src/Hotline.Api/StartupHelper.cs

@@ -313,14 +313,14 @@ namespace Hotline.Api
                             .WithCronSchedule("0/10 * * * * ?")
                         );
 
-                        var getCallSatisfactionJobKey = new JobKey(nameof(XingTangCallSatisfactionSyncJob));
-                        d.AddJob<XingTangCallSatisfactionSyncJob>(getCallSatisfactionJobKey);
-                        d.AddTrigger(t => t
-                            .WithIdentity("get-callsatisfaction-trigger")
-                            .ForJob(getCallSatisfactionJobKey)
-                            .StartNow()
-                            .WithCronSchedule("0/30 * * * * ?")
-                        );
+                        //var getCallSatisfactionJobKey = new JobKey(nameof(XingTangCallSatisfactionSyncJob));
+                        //d.AddJob<XingTangCallSatisfactionSyncJob>(getCallSatisfactionJobKey);
+                        //d.AddTrigger(t => t
+                        //    .WithIdentity("get-callsatisfaction-trigger")
+                        //    .ForJob(getCallSatisfactionJobKey)
+                        //    .StartNow()
+                        //    .WithCronSchedule("0/30 * * * * ?")
+                        //);
 
                         break;
                 }

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

@@ -1,34 +1,34 @@
 {
   "CityBaseConfiguration": {
     "CityProvince": {
-      "UserId": "03aba148-e7b1-cd03-bf00-3a1177930508",
-      "UserName": "省12345平台",
-      "OrgId": "001171",
-      "OrgName": "省12345平台"
+      "UserId": "9fd11bfd-0c39-f1f0-80b1-3a1384977b8e",
+      "UserName": "省12345交办",
+      "OrgId": "001090",
+      "OrgName": "省12345交办"
     },
     "CityProvinceAssign": {
-      "UserId": "",
-      "UserName": "",
-      "OrgId": "001178",
+      "UserId": "9fd11bfd-0c39-f1f0-80b1-3a1384977b8e",
+      "UserName": "省12345交办",
+      "OrgId": "001090",
       "OrgName": "省12345交办"
     },
     "PublicSecurity": {
-      "UserId": "e90501d7-c453-e18a-f1fa-3a1177930699",
+      "UserId": "a5a57c15-fe42-5782-449b-3a1384976aaf",
       "UserName": "市公安局110",
-      "OrgId": "001180",
+      "OrgId": "001096",
       "OrgName": "市公安局110"
     },
     "CityEnterprise": {
-      "UserId": "ce42562c-afc1-764b-1dc8-3a1177930346",
-      "UserName": "联系服务企业",
-      "OrgId": "001181",
-      "OrgName": "联系服务企业"
+      "UserId": "",
+      "UserName": "",
+      "OrgId": "",
+      "OrgName": ""
     },
     "ComprehensiveTreatment": {
-      "UserId": "d4cb7151-41fa-a810-6c1e-3a117792fc0c",
-      "UserName": "综治平台",
-      "OrgId": "001143",
-      "OrgName": "综治平台"
+      "UserId": "",
+      "UserName": "",
+      "OrgId": "",
+      "OrgName": ""
     }
   },
   "AllowedHosts": "*",

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

@@ -0,0 +1,44 @@
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.CallCenter;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Application.Tests.Repository;
+public class CallNativeRepositoryTest
+{
+    private readonly ICallNativeRepository _callNativeRepository;
+    private readonly IRepository<Order> _orderRepository;
+
+    public CallNativeRepositoryTest(ICallNativeRepository callNativeRepository, IRepository<Order> orderRepository)
+    {
+        _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>());
+    }
+}

+ 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)

+ 7 - 3
src/Hotline.Application/Jobs/XingTangCallSatisfactionSyncJob.cs

@@ -1,4 +1,6 @@
-using Hotline.CallCenter.Calls;
+using DotNetCore.CAP;
+using Hotline.CallCenter.Calls;
+using Hotline.Share.Mq;
 using MapsterMapper;
 using Microsoft.Extensions.Logging;
 using Quartz;
@@ -23,14 +25,16 @@ namespace Hotline.Application.Jobs
         private readonly IRepository<CallSatisfaction> _callSatisfactionRepository;
         private readonly IMapper _mapper;
         private readonly ILogger<XingTangCallSatisfactionSyncJob> _logger;
+        private readonly ICapPublisher _capPublisher;
 
-        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISqlSugarClient db, IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger)
+        public XingTangCallSatisfactionSyncJob(IRepository<CallNative> callRepository, ISqlSugarClient db, IRepository<CallSatisfaction> callSatisfactionRepository, IMapper mapper, ILogger<XingTangCallSatisfactionSyncJob> logger, ICapPublisher capPublisher)
         {
             _callRepository = callRepository;
             _db = db;
             _callSatisfactionRepository = callSatisfactionRepository;
             _mapper = mapper;
             _logger = logger;
+            _capPublisher = capPublisher;
         }
 
         public void Dispose()
@@ -69,7 +73,7 @@ namespace Hotline.Application.Jobs
                     }
                 }
                 await _callSatisfactionRepository.AddRangeAsync(callStatisfactions, context.CancellationToken);
-
+                await _capPublisher.PublishAsync(EventNames.HotlineCallSatisfactionAdd, callStatisfactions, cancellationToken: context.CancellationToken);
             }
             catch (Exception e)
             {

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

@@ -107,6 +107,7 @@ public class OrderMapperConfigs : IRegister
             .Ignore(d => d.AcceptorId)
             .Ignore(d => d.AcceptorName)
             .Ignore(d => d.AcceptorStaffNo)
+            .Ignore(d=>d.ExternalId)
             //.AfterMapping((s, d) =>
             //{
             //    //d.UpdateHandlingStatus(s.IsInCountersign);

+ 1 - 0
src/Hotline.Application/Orders/OrderApplication.cs

@@ -825,6 +825,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
             .Includes(x => x.OrderScreens)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!)) //标题
             .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), d => d.ProvinceNo == dto.ProvinceNo) //省本地编号
+             .WhereIF(!string.IsNullOrEmpty(dto.ReceiveProvinceNo), d => d.ReceiveProvinceNo == dto.ReceiveProvinceNo) //省编号
             .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) //工单编码
             .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType)//受理类型
             //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型

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

@@ -0,0 +1,73 @@
+using DotNetCore.CAP;
+using Hotline.CallCenter.Calls;
+using Hotline.Orders;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Mq;
+using Hotline.Share.Tools;
+using Polly;
+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;
+using XF.Domain.Repository.Extensions;
+
+namespace Hotline.Application.Subscribers;
+public class CallSubscriber : ICapSubscribe, ITransientDependency
+{
+    private readonly IRepository<CallNative> _callRepository;
+    private readonly IRepository<Order> _orderRepository;
+    private readonly IRepository<OrderVisit> _orderVisitrepository;
+    private readonly IRepository<OrderVisitDetail> _orderVisitDetailRepository;
+    private readonly IOrderVisitRepository _orderVisitRepository;
+
+    public CallSubscriber(IRepository<CallNative> callRepository, IRepository<Order> orderRepository, IRepository<OrderVisit> orderVisitrepository, IRepository<OrderVisitDetail> orderVisitDetailRepository, IOrderVisitRepository orderVisitRepository)
+    {
+        _callRepository = callRepository;
+        _orderRepository = orderRepository;
+        _orderVisitrepository = orderVisitrepository;
+        _orderVisitDetailRepository = orderVisitDetailRepository;
+        _orderVisitRepository = orderVisitRepository;
+    }
+
+    /// <summary>
+    /// 挂断电话
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    /// <exception cref="UserFriendlyException"></exception>
+    //[CapSubscribe(EventNames.HotlineCallBye)]
+    //public async Task HotlineCallBye(PublishCallRecrodDto dto, CancellationToken cancellationToken)
+    //{
+    //    var callId = await _orderRepository.Queryable()
+    //        .Where(m => m.Id == dto.Order.Id)
+    //        .Select(m => m.CallId)
+    //        .FirstAsync() ??
+    //        throw new UserFriendlyException($"订单Id:{dto.Order.Id} 的 CallId 为空");
+    //    var replyTxt = string.Empty;
+    //    RetryHelper.Retry(() =>
+    //    {
+    //        return false;
+    //    }, 5, 1000);
+    //}
+
+    /// <summary>
+    /// 如果有新的电话回复记录, 就更新回访记录
+    /// </summary>
+    /// <param name="callSatisfactions"></param>
+    /// <param name="cancellationToken"></param>
+    /// <returns></returns>
+    //[CapSubscribe(EventNames.HotlineCallSatisfactionAdd)]
+    //public async Task HotlineCallSatisfactionAdd(List<CallSatisfaction> callSatisfactions, CancellationToken cancellationToken)
+    //{
+    //    foreach (var callSatisfaction in callSatisfactions)
+    //    {
+    //        await _orderVisitRepository.UpdateVoiceReplyAsync(callSatisfaction, cancellationToken);
+    //    }
+    //}
+}

+ 18 - 14
src/Hotline.Application/Subscribers/DatasharingSubscriber.cs

@@ -70,7 +70,7 @@ namespace Hotline.Application.Subscribers
         private readonly ISystemDicDataCacheManager _sysDicDataCacheManager;
         private readonly IOptions<CityBaseConfiguration> _cityBaseConfiguration;
 
-		public DataSharingSubscriber(
+        public DataSharingSubscriber(
             IRepository<OrderVisit> orderVisitRepository,
             IMapper mapper,
             IOrderRepository orderRepository,
@@ -132,7 +132,7 @@ namespace Hotline.Application.Subscribers
             _orderPublishRepository = orderPublishRepository;
             _sysDicDataCacheManager = sysDicDataCacheManager;
             _cityBaseConfiguration = cityBaseConfiguration;
-		}
+        }
 
         /// <summary>
         /// 接收工单退回结果
@@ -240,7 +240,8 @@ namespace Hotline.Application.Subscribers
             };
             await _orderRevokeRepository.AddAsync(orderRevoke, cancellationToken);
 
-            var current = SessionContextCreator.CreateSessionContext(dto.Source,_cityBaseConfiguration.Value);
+            //宜宾需求:特提至中心(派单组?),由派单员归档
+            var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
             if (string.IsNullOrEmpty(order?.WorkflowId))
             {
                 var startDto = new StartWorkflowDto
@@ -249,15 +250,18 @@ namespace Hotline.Application.Subscribers
                     Title = order.Title,
                     Opinion = dto.Opinion,
                 };
-                await _workflowApplication.StartToEndAsync(startDto, current, order.Id, order.ExpiredTime,
+                //await _workflowApplication.StartToEndAsync(startDto, current, order.Id, order.ExpiredTime,
+                //    cancellationToken);
+                await _workflowApplication.StartWorkflowAsync(startDto, current, order.Id, order.ExpiredTime,
                     cancellationToken);
             }
             else
             {
                 //await _workflowApplication.HandleToEndAsync(current, order.WorkflowId, dto.Opinion, null,
                 //    cancellationToken: cancellationToken);
-                await _workflowApplication.JumpToEndAsync(current, order.WorkflowId, dto.Opinion, null, order.ExpiredTime,
-                    cancellationToken: cancellationToken);
+                //await _workflowApplication.JumpToEndAsync(current, order.WorkflowId, dto.Opinion, null, order.ExpiredTime,
+                //    cancellationToken: cancellationToken);
+                await _workflowDomainService.RecallToStartStepAsync(order.WorkflowId, dto.Opinion, current, cancellationToken);
             }
         }
 
@@ -417,7 +421,7 @@ namespace Hotline.Application.Subscribers
                             x.Status == EScreenStatus.Approval)
                 .FirstAsync(cancellationToken);
 
-            var current = SessionContextCreator.CreateSessionContext(dto.Source,_cityBaseConfiguration.Value);
+            var current = SessionContextCreator.CreateSessionContext(dto.Source, _cityBaseConfiguration.Value);
             await _workflowApplication.HandleToEndAsync(current,
                 orderScreen.WorkflowId, "省上推送甄别结果", null,
                 dto.ProvinceScreenResult.AuditResult
@@ -550,7 +554,7 @@ namespace Hotline.Application.Subscribers
             {
                 //处理省下行回访
                 var order = await _orderRepository.Queryable().Where(x => x.ReceiveProvinceNo == dto.ProvinceNo).FirstAsync();
-                if (order !=null)
+                if (order != null)
                 {
                     //判断是否有发布数据
                     var orderPublish = await _orderPublishRepository.Queryable()
@@ -606,22 +610,22 @@ namespace Hotline.Application.Subscribers
                     orgDetail.VisitOrgCode = order.ActualHandleOrgCode;
                     orgDetail.VisitOrgName = order.ActualHandleOrgName;
                     orgDetail.VisitTarget = EVisitTarget.Org;
-                    
-                    
+
+
                     orgDetail.OrgProcessingResults = satisfy;
 
                     visitedDetail.Add(orgDetail);
                     //TODO 自贡办件态度
 
 
-                    await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail,cancellationToken);
-                    order.Visited(satisfy.Key,satisfy.Value);
+                    await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail, cancellationToken);
+                    order.Visited(satisfy.Key, satisfy.Value);
                     order.Status = EOrderStatus.Visited;
                     await _orderRepository.UpdateAsync(order, cancellationToken);
 
                 }
-                
-                
+
+
             }
         }
 

+ 59 - 0
src/Hotline.Repository.SqlSugar/CallCenter/CallNativeRepository.cs

@@ -0,0 +1,59 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Orders;
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Settings;
+using Hotline.Share.Enums.Order;
+using Hotline.Share.Tools;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+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)
+    {
+        _orderRepository = orderRepository;
+    }
+
+    public async Task<int> UpdateReplyTxtAsync(string callId, string replyTxt)
+    {
+        return await Updateable()
+            .Where(m => m.Id == callId)
+            .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;
+    }
+}

+ 5 - 11
src/Hotline.Repository.SqlSugar/Orders/OrderVisitRepository.cs

@@ -1,5 +1,6 @@
 using Hotline.Caching.Interfaces;
 using Hotline.Caching.Services;
+using Hotline.CallCenter.Calls;
 using Hotline.Orders;
 using Hotline.Push.FWMessage;
 using Hotline.Repository.SqlSugar.DataPermissions;
@@ -13,6 +14,7 @@ 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;
 public class OrderVisitRepository : BaseRepository<OrderVisit>, IOrderVisitRepository, IScopeDependency
@@ -44,22 +46,14 @@ public class OrderVisitRepository : BaseRepository<OrderVisit>, IOrderVisitRepos
         var orderVisit = await GetAsync(data.ExternalId)
              ?? throw new UserFriendlyException($"回访单不存在, visitId: {data.ExternalId} message: {data.ToJson()}");
 
-        if (orderVisit.VisitState == EVisitState.Visited) 
+        if (orderVisit.VisitState == EVisitState.Visited)
             throw new UserFriendlyException($"回访单已回访. visitId: {data.ExternalId}");
 
-        Dictionary<string, string> dics = 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"},
-        };
         var replyTxt = data.SmsReplyContent.Trim();
         var result = string.Empty;
-        if (dics.TryGetValue(replyTxt, out result) == false)
+        if (SettingConstants.ReplyToEnumMap.TryGetValue(replyTxt, out result) == false)
         {
-            var m = dics.FirstOrDefault(item => item.Value.StartsWith(replyTxt));
+            var m = SettingConstants.ReplyToEnumMap.FirstOrDefault(item => item.Value.StartsWith(replyTxt));
             replyTxt = m.Key;
             result = m.Value;
         }

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

@@ -171,6 +171,10 @@ namespace Hotline.Share.Dtos.Order
         /// </summary>
         public string? ProvinceChannel { get; set; }
 
+        /// <summary>
+        /// 省交办编号
+        /// </summary>
+        public string? ReceiveProvinceNo { get; set; }
     }
 
 

+ 6 - 1
src/Hotline.Share/Mq/EventNames.Call.cs

@@ -5,7 +5,7 @@ public partial class EventNames
     /// <summary>
     /// 挂断电话
     /// </summary>
-    public const string HotlineCallBye= "hotline.call.bye";
+    public const string HotlineCallBye = "hotline.call.bye";
 
     /// <summary>
     /// 通话记录与工单关联
@@ -21,4 +21,9 @@ public partial class EventNames
     /// 通话记录关联工单
     /// </summary>
     public const string HotlineCallNativeConnectOrder = "hotline.callnative.connect.order";
+
+    /// <summary>
+    /// 同步电话回复记录 新增事件
+    /// </summary>
+    public const string HotlineCallSatisfactionAdd = "hotline.call.satisfaction.add";
 }

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

@@ -132,9 +132,8 @@ namespace Hotline.Share.Mq
         /// 批量短信服务
         /// </summary>
         public const string HotlineBatchSmsTask = "hotline.order.batchsmstask";
-
         #endregion
 
-     
+
     }
 }

+ 38 - 0
src/Hotline.Share/Tools/RetryHelper.cs

@@ -0,0 +1,38 @@
+namespace Hotline.Share.Tools;
+
+/// <summary>
+/// 重试操作辅助类
+/// </summary>
+public static class RetryHelper
+{
+    /// <summary>
+    /// 重试
+    /// </summary>
+    /// <param name="func"> 重试方法 </param>
+    /// <param name="times"> 重试次数 (1 与 100 之间的整数) </param>
+    /// <param name="millisecond"> 重试等待毫秒 </param>
+    /// <returns> 是否执行成功 </returns>
+    public static bool Retry(Func<bool> func, int times, int millisecond = 0)
+    {
+        if (times <= 1 && times >= 100)
+        {
+            throw new ArgumentOutOfRangeException("times 参数有误。只能是介于 1 与 100(包含1和100)之间的整数。");
+        }
+
+        while (times > 0)
+        {
+            if (func())
+            {
+                return true;
+            }
+
+            times--;
+            if (millisecond > 0)
+            {
+                Thread.Sleep(millisecond);
+            }
+        }
+
+        return false;
+    }
+}

+ 7 - 1
src/Hotline/CallCenter/Calls/CallNative.cs

@@ -17,7 +17,7 @@ namespace Hotline.CallCenter.Calls
     public class CallNative : CreationEntity
     {
         /// <summary>
-        /// 通话记录编号
+        ///  
         /// </summary>
         [SugarColumn(ColumnDescription = "通话记录编号")]
         public string CallNo { get; set; }
@@ -151,6 +151,12 @@ namespace Hotline.CallCenter.Calls
         [SugarColumn(ColumnDescription = "通话录音")]
         public string AudioFile { get; set; }
 
+        /// <summary>
+        /// 电话回复内容
+        /// </summary>
+        [SugarColumn(ColumnDescription = "电话回复内容")]
+        public string? ReplyTxt { get; set; }
+
         //public string? ExternalId { get; set; }
 
         //public string? OrderNo { get; set; }

+ 8 - 8
src/Hotline/CallCenter/Calls/CallSatisfaction.cs

@@ -1,10 +1,4 @@
-using SqlSugar;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using XF.Domain.Repository;
+using XF.Domain.Repository;
 
 namespace Hotline.CallCenter.Calls
 {
@@ -18,7 +12,13 @@ namespace Hotline.CallCenter.Calls
         public string CallNo { get; set; }
 
         /// <summary>
-        /// 按键结果
+        /// 按键结果值: 1、2、3、4、5
+        /// 自贡:
+        ///     1. 非常满意;
+        ///     2. 满意;
+        ///     3. 一般;
+        ///     4. 不满意;
+        ///     5. 非常不满意;
         /// </summary>
         public string Result { get; set; }
     }

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

@@ -0,0 +1,29 @@
+using Hotline.CallCenter.Calls;
+using Hotline.Share.Enums.Order;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+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);
+}

+ 2 - 1
src/Hotline/Orders/IOrderVisitRepository.cs

@@ -1,4 +1,5 @@
-using XF.Domain.Repository;
+using Hotline.CallCenter.Calls;
+using XF.Domain.Repository;
 
 namespace Hotline.Orders;
 public interface IOrderVisitRepository : IRepository<OrderVisit>

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

@@ -1,4 +1,5 @@
-using Hotline.Users;
+using Hotline.Share.Enums.Order;
+using Hotline.Users;
 
 namespace Hotline.Settings
 {
@@ -499,5 +500,27 @@ namespace Hotline.Settings
         /// 可分配回访角色
         /// </summary>
         public const string OrderVisitRole = "OrderVisitRole";
+
+        /// <summary>
+        /// 定量查询返回数据条数上限
+        /// </summary>
+        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>
+        /// 旧数据通知公告知识库附件地址	
+        /// </summary>
+        public const string OldFilesUrls = "OldFilesUrls";
     }
 }

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

@@ -105,7 +105,7 @@ public abstract class ExpireTimeLimitBase
 		    {
 			    date = date.AddDays(1);
 		    }
-			date = DateTime.Parse(date.ToShortDateString() + "18:00");
+			date = DateTime.Parse(date.ToShortDateString() + " 18:00");
 		}
 	    return date;
     }