Parcourir la source

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

TANG JIANG il y a 1 an
Parent
commit
e43e1a23e5

+ 12 - 8
src/Hotline.Ai.Jths/AiJthsStartupExtensions.cs

@@ -8,13 +8,17 @@ using Microsoft.Extensions.DependencyInjection;
 
 namespace Hotline.Ai.Jths
 {
-    public static class AiJthsStartupExtensions
-    {
-        public static IServiceCollection AddAiJths(this IServiceCollection services)
-        {
-            services.AddSingleton<IAiQualityService, AiQualityService>();
+	public static class AiJthsStartupExtensions
+	{
+		public static IServiceCollection AddAiJths(this IServiceCollection services, string baseUrl)
+		{
+			services.AddSingleton<IAiQualityService, AiQualityService>(_ => new AiQualityService(baseUrl));
 
-            return services;
-        }
-    }
+			return services;
+		}
+	}
+	public class AiQualityConfig
+	{
+		public string Url { get; set; }
+	}
 }

+ 33 - 2
src/Hotline.Ai.Jths/AiQualityService.cs

@@ -5,14 +5,24 @@ using Hotline.Share.Dtos.Quality;
 using Hotline.CallCenter.Calls;
 using Hotline.Orders;
 using Newtonsoft.Json;
+using System.Text;
+using System.Security.Cryptography;
 
 namespace Hotline.Ai.Jths
 {
     public class AiQualityService : IAiQualityService
 	{
 		private readonly RestClient _client;
+		private readonly string _baseUrl;
 
-		public async Task CreateAiOrderQualityTask(Hotline.Quality.Quality model, TrCallRecord call, Order order, CancellationToken cancellationToken)
+		public AiQualityService(string baseUrl)
+        {
+            _client = new RestClient();
+            _baseUrl = baseUrl;
+
+		}
+
+        public async Task CreateAiOrderQualityTask(Hotline.Quality.Quality model, TrCallRecord call, Order order, CancellationToken cancellationToken)
 		{
 			AiQualityDto  aiQuality = new AiQualityDto
 			{
@@ -26,7 +36,7 @@ namespace Hotline.Ai.Jths
 			};
 			var data =JsonConvert.SerializeObject(aiQuality);
 			//todo  缺少地址
-			await ExecuteAsync("......./routeinfo/api", Method.Post, data, cancellationToken);
+			await ExecuteAsync(_baseUrl+"/routeinfo/api", Method.Post, data, cancellationToken);
 		}
 
 		public async Task<ApiResponse<TResponse>> ExecuteAsync<TRequest, TResponse>(string path, Method httpMethod,
@@ -59,6 +69,12 @@ namespace Hotline.Ai.Jths
 			where TRequest : class
 		{
 			var req = new RestRequest(path, httpMethod);
+			req.AddHeader("content-type", "application/json");
+			req.AddHeader("token", "");
+			req.AddHeader("version", "");
+			var appkey = MD5Encrypt(request.ToString());
+			req.AddHeader("appkey", appkey);
+			req.AddHeader("signType", "md5");
 			if (httpMethod is Method.Get)
 			{
 				req.AddObject(request);
@@ -78,5 +94,20 @@ namespace Hotline.Ai.Jths
 				throw new HttpRequestException($"智能质检平台错误,Error: {e.Message}");
 			}
 		}
+
+		/// <summary>
+		/// MD5加密
+		/// </summary>
+		/// <param name="input">需要加密的字符串</param>
+		/// <returns></returns>
+		private static string MD5Encrypt(string? input)
+		{
+			using var md5 = MD5.Create();
+			var t = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
+			var sb = new StringBuilder(32);
+			for (var i = 0; i < t.Length; i++)
+				sb.Append(t[i].ToString("x").PadLeft(2, '0'));
+			return sb.ToString();
+		}
 	}
 }

+ 5 - 0
src/Hotline.Ai.Jths/Hotline.Ai.Jths.csproj

@@ -9,10 +9,15 @@
   <ItemGroup>
     <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
     <PackageReference Include="RestSharp" Version="110.2.0" />
+    <PackageReference Include="Fw.Utility.UnifyResponse" Version="1.0.0" />
   </ItemGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\Hotline\Hotline.csproj" />
   </ItemGroup>
 
+  <ItemGroup>
+    <Compile Remove="IJthsClient.cs" />
+  </ItemGroup>
+
 </Project>

+ 8 - 0
src/Hotline.Api/Controllers/Bi/BiCallController.cs

@@ -0,0 +1,8 @@
+namespace Hotline.Api.Controllers.Bi;
+
+/// <summary>
+/// 话务报表
+/// </summary>
+public class BiCallController : BaseController
+{
+}

+ 10 - 0
src/Hotline.Api/Controllers/IPPbxController.cs

@@ -325,6 +325,16 @@ namespace Hotline.Api.Controllers
 
 
 
+        #endregion
+
+        #region Bi
+
+        [HttpGet("bi/calls")]
+        public async Task BiQueryCallsAsync()
+        {
+            throw new NotImplementedException();
+        }
+
         #endregion
 
         #endregion

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

@@ -1705,7 +1705,7 @@ public class OrderController : BaseController
 
     #endregion
 
-    #region 工单办理klooooooooooooooooooooooooooooooooooooooooooooooooo,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+    #region 工单办理
 
     /// <summary>
     /// 工单列表
@@ -1965,18 +1965,23 @@ public class OrderController : BaseController
     /// 查询工单办理下一步可选节点(带推荐部门)
     /// </summary>
     [HttpGet("nextsteps/{orderId}")]
-    public async Task<NextStepsWithRecommendDto> GetNextStepsWithRecommendAsync(string orderId)
+    public async Task<NextStepsDto<RecommendStepOption>> GetNextStepsWithRecommendAsync(string orderId)
     {
         var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted);
         if (string.IsNullOrEmpty(order.WorkflowId))
             throw new UserFriendlyException("该工单无关联流程id");
         var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, HttpContext.RequestAborted);
-        var rsp = _mapper.Map<NextStepsWithRecommendDto>(dto);
-        var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted);
-        if (org is null) return rsp;
-        
-        rsp.RecommendOrgId = org.Id;
-        rsp.RecommendOrgName = org.Name;
+        var rsp = _mapper.Map<NextStepsDto<RecommendStepOption>>(dto);
+        foreach (var step in rsp.Steps)
+        {
+            if (dto.CurrentStepBusinessType is not EBusinessType.Send ||
+                step.BusinessType is not EBusinessType.Department) continue;
+            var org = await _organizeRepository.GetAsync(d => d.Id == order.AreaCode, HttpContext.RequestAborted);
+            if (org is null) continue;
+            step.RecommendOrgId = org.Id;
+            step.RecommendOrgName = org.Name;
+        }
+
         return rsp;
     }
 

+ 39 - 0
src/Hotline.Api/Controllers/QualityController.cs

@@ -19,6 +19,7 @@ using System.Xml.Linq;
 using System.Threading;
 using Hotline.CallCenter.Calls;
 using Hotline.Application.Quality;
+using Microsoft.AspNetCore.Authorization;
 
 namespace Hotline.Api.Controllers
 {
@@ -531,5 +532,43 @@ namespace Hotline.Api.Controllers
 			};
 			return rsp;
 		}
+
+		/// <summary>
+		/// 智能质检结果返回接收
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[AllowAnonymous]
+		[HttpPost("AiResult")]
+		public async Task AiResult([FromBody] AiQualityResultDto dto) 
+		{
+			try
+			{
+				var quality = await _qualitey.GetAsync(dto.source_data.customer_id);
+				if (quality is { State: EQualityState.Apply }) 
+				{
+					List<QualityDetail> details = new List<QualityDetail>();
+                    foreach (var item in dto.analysis_data.score_items)
+                    {
+						QualityDetail detail = new QualityDetail
+						{
+							QualityId = quality.Id,
+							Second = 0,
+							Name = item.name,
+							//Content = item.name,
+							Grade = item.score
+						};
+						details.Add(detail);
+					}
+					await _qualiteyDetail.AddRangeAsync(details);
+                }
+			}
+			catch (Exception e)
+			{
+				Console.WriteLine(e);
+				throw;
+			}
+			
+		}
 	}
 }

+ 14 - 15
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -52,7 +52,7 @@ public class WorkflowController : BaseController
     private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
     private readonly IFileRepository _fileRepository;
 
-	public WorkflowController(
+    public WorkflowController(
         IDefinitionDomainService definitionDomainService,
         IRepository<WorkflowDefinition> definitionRepository,
         IWorkflowApplication workflowApplication,
@@ -70,7 +70,7 @@ public class WorkflowController : BaseController
         IMapper mapper,
         ISystemDicDataCacheManager systemDicDataCacheManager,
         IFileRepository fileRepository
-	)
+    )
     {
         _definitionDomainService = definitionDomainService;
         _definitionRepository = definitionRepository;
@@ -89,8 +89,7 @@ public class WorkflowController : BaseController
         _workflowCountersignRepository = workflowCountersignRepository;
         _systemDicDataCacheManager = systemDicDataCacheManager;
         _fileRepository = fileRepository;
-
-	}
+    }
 
     /// <summary>
     /// 分页查询最新版本号的模板
@@ -333,7 +332,7 @@ public class WorkflowController : BaseController
     /// <param name="workflowId"></param>
     /// <returns></returns>
     [HttpGet("{workflowId}/recall")]
-    public async Task<RecallStepsDto> GetRecallSteps(string workflowId)
+    public async Task<NextStepsDto<RecallStepOption>> GetRecallSteps(string workflowId)
     {
         return await _workflowApplication.GetRecallStepsAsync(workflowId, HttpContext.RequestAborted);
     }
@@ -458,7 +457,7 @@ public class WorkflowController : BaseController
     public async Task<WorkflowDto> GetWorkflowTraces(string workflowId)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, cancellationToken: HttpContext.RequestAborted);
-		workflow.Traces = await _workflowTraceRepository.Queryable()
+        workflow.Traces = await _workflowTraceRepository.Queryable()
             .Where(d => d.WorkflowId == workflow.Id)
             .OrderBy(d => d.CreationTime)
             .ToTreeAsync(d => d.Traces, d => d.ParentId, null);
@@ -466,15 +465,16 @@ public class WorkflowController : BaseController
         var workflowDto = _mapper.Map<WorkflowDto>(workflow);
         if (workflowDto.Traces.Any())
         {
-	        foreach (var item in workflowDto.Traces)
-	        {
-		        if (item.FileJson != null && item.FileJson.Any())
-		        {
-					var files = await _fileRepository.Queryable().Where(x => x.FlowKey == item.StepId).ToListAsync();
-					if (files.Any()) item.Files = _mapper.Map<List<FileDto>>(files);
-				}
-			}
+            foreach (var item in workflowDto.Traces)
+            {
+                if (item.FileJson != null && item.FileJson.Any())
+                {
+                    var files = await _fileRepository.Queryable().Where(x => x.FlowKey == item.StepId).ToListAsync();
+                    if (files.Any()) item.Files = _mapper.Map<List<FileDto>>(files);
+                }
+            }
         }
+
         return workflowDto;
     }
 
@@ -619,6 +619,5 @@ public class WorkflowController : BaseController
         }).ToList();
 
         return new PagedDto<WorkflowCountersignDto>(total, dtos);
-
     }
 }

+ 2 - 2
src/Hotline.Api/StartupExtensions.cs

@@ -96,8 +96,8 @@ internal static class StartupExtensions
         var trConfig = configuration.GetRequiredSection("Tr").Get<TrConfiguration>();
         services.AddTrSdk(trConfig.Address, trConfig.Username, trConfig.Password);
 
-        //jths
-        services.AddAiJths();
+		//jths 
+		services.AddAiJths(configuration.GetSection("AiQuality").Get<AiQualityConfig>().Url);
 
         //sqlsugar
         services.AddSqlSugar(configuration);

+ 61 - 58
src/Hotline.Api/config/appsettings.Development.json

@@ -136,69 +136,72 @@
       "DownloadUrlAddress": "file/downloadfile",
       "Source": "数据共享系统"
     },
+    //110对接
+    "PoliceDS": {
+      //1、非警情分流推送服务_宜宾市
+      //   receive-工单受理
+      //   http://10.12.185.168:8001/service/api/ds/110To12345/chainAlarm
+      "token1_token": "b8aae0a998f5b79c9a35aecb888e1a58",
+      "token1_dcsm": "c9bc4e718d1917a9a68add90fecbe5bb60920e5ab85d9ecb6a6167db4352f42b8ae21ac67a6e2aab48b4c99cd9f93ec5fb017e202df969a91f74456c14e8770a",
+      "token1_sm2_public": "BS/H9JVlRdo8vbsZYQLTkeGGZBVjdkX+VJ82CX7n6i4NubmynRIaxvzoSsEAhbbvTDGm2DS96l95nK6Dkd0UZg==",
+      "token1_sm2_private": "GbjU4GFk0yaa/wTdzxeh5BOh8VNlqvnTcb7EUtDVvOY=",
+      "token1_sm4": "BKrW/v4jeRgsFg3HSbxEKnDi6rPceW0AdRiaa1rhEwAnraf8MnHdXzUQoQ7+zyjfghaK5G+zDz+wW+Ob27Jgxt91HkVmyL6+SjqV9ZnqNeGFgTBkQrHDySGz6jHKa12Sv7PZs8pjc716he3NNHZAkCI=",
+      "token1_sm4_mw": "4034d80c19bbd01d",
 
-      //110对接
-      "PoliceDS": {
-        //1、非警情分流推送服务_宜宾市
-        //   receive-工单受理
-        //   http://10.12.185.168:8001/service/api/ds/110To12345/chainAlarm
-        "token1_token": "b8aae0a998f5b79c9a35aecb888e1a58",
-        "token1_dcsm": "c9bc4e718d1917a9a68add90fecbe5bb60920e5ab85d9ecb6a6167db4352f42b8ae21ac67a6e2aab48b4c99cd9f93ec5fb017e202df969a91f74456c14e8770a",
-        "token1_sm2_public": "BS/H9JVlRdo8vbsZYQLTkeGGZBVjdkX+VJ82CX7n6i4NubmynRIaxvzoSsEAhbbvTDGm2DS96l95nK6Dkd0UZg==",
-        "token1_sm2_private": "GbjU4GFk0yaa/wTdzxeh5BOh8VNlqvnTcb7EUtDVvOY=",
-        "token1_sm4": "BKrW/v4jeRgsFg3HSbxEKnDi6rPceW0AdRiaa1rhEwAnraf8MnHdXzUQoQ7+zyjfghaK5G+zDz+wW+Ob27Jgxt91HkVmyL6+SjqV9ZnqNeGFgTBkQrHDySGz6jHKa12Sv7PZs8pjc716he3NNHZAkCI=",
-        "token1_sm4_mw": "4034d80c19bbd01d",
+      //4、警务警情分流推送服务_宜宾市
+      //   receive-工单办结
+      //   http://10.12.185.168:8001/service/api/ds/110To12345/chainDeal
+      "token4_token": "8806bfba29b997853bdb059a9ba9a3ae",
+      "token4_dcsm": "f5dce079e0f4acd6b6627b89fb5e72af5fa5775d3ee3b8c7876f546c5ebe723888df4a70c09f9aa5e096bb342d73e0c4793c851a7a8035e8683b07430f132bd3",
+      "token4_sm2_public": "P2IVWpFx38GQTDV3hgrxjlOdfPhLQNW2LyvAKmYqMz9UYHCtm/l3K73UIouMXs4jcmZjXyItepvKFv44g3YnXA==",
+      "token4_sm2_private": "yxIkRALHoOTxpiZ/jrvCDQatcR7k11Xhps7c92peU9w=",
+      "token4_sm4": "BCD88AXnIfMxe8PrUcubSbFRr07cOuDDEPzy754W3CzhOqjcpAcu1B9B6U46jyM4hEFPqkx+SS1PUAfRlG5tzYD1Z8SKsJTBUDGR6bTMRvCc+C/aps+IcRBfzjjRchtT1c5iok4CfiT4LoK5cmOHKKU=",
+      "token4_sm4_mw": "d731ff1282dda792",
 
-        //4、警务警情分流推送服务_宜宾市
-        //   receive-工单办结
-        //   http://10.12.185.168:8001/service/api/ds/110To12345/chainDeal
-        "token4_token": "8806bfba29b997853bdb059a9ba9a3ae",
-        "token4_dcsm": "f5dce079e0f4acd6b6627b89fb5e72af5fa5775d3ee3b8c7876f546c5ebe723888df4a70c09f9aa5e096bb342d73e0c4793c851a7a8035e8683b07430f132bd3",
-        "token4_sm2_public": "P2IVWpFx38GQTDV3hgrxjlOdfPhLQNW2LyvAKmYqMz9UYHCtm/l3K73UIouMXs4jcmZjXyItepvKFv44g3YnXA==",
-        "token4_sm2_private": "yxIkRALHoOTxpiZ/jrvCDQatcR7k11Xhps7c92peU9w=",
-        "token4_sm4": "BCD88AXnIfMxe8PrUcubSbFRr07cOuDDEPzy754W3CzhOqjcpAcu1B9B6U46jyM4hEFPqkx+SS1PUAfRlG5tzYD1Z8SKsJTBUDGR6bTMRvCc+C/aps+IcRBfzjjRchtT1c5iok4CfiT4LoK5cmOHKKU=",
-        "token4_sm4_mw": "d731ff1282dda792",
+      //3、警务警情分流查询服务_宜宾市
+      //   send-工单受理
+      //   http://10.12.185.168:8001/service/api/ds/12345To110/chainAlarm
+      "token3_token": "b76ba1896c4880998a86b829cf79888a",
+      "token3_dcsm": "3cccc86e021c0ff7827537053ec1b6e4a57cbb49b77c9492257123703c5a6b711000f0842c035fe6d33eb2a947915af53a1ef501916ec7128bff9514d6184e2c",
+      "token3_sm2_public": "qaao4Xh8/eyYGeVOj1K8D7p3+OriP55azWDAbYVoZelMdluNrJuQWM2qPn+hjTHTBnIMAVK2HlHBx4oGfCxGdA==",
+      "token3_sm2_private": "8bSYM8P3b4I94qGt3XVx3bQddNCy/xVKo7o1b5LI4/M=",
+      "token3_sm4": "BIDhFaEu5NILR7byg/JfaPlJEm4dYWC+u9J1IqhtYeYY1AktOxp7cZWqfk/mWjw72pYGT7YRENCULbjZ2bxVG6UUv2pYukZWtYog34Vicu5IgC8ti4VpED9eGzGgtKJ/CT0KtAnjQPQL0PsVbCjTY5M=",
+      "token3_sm4_mw": "bbeb56d247354360",
 
-        //3、警务警情分流查询服务_宜宾市
-        //   send-工单受理
-        //   http://10.12.185.168:8001/service/api/ds/12345To110/chainAlarm
-        "token3_token": "b76ba1896c4880998a86b829cf79888a",
-        "token3_dcsm": "3cccc86e021c0ff7827537053ec1b6e4a57cbb49b77c9492257123703c5a6b711000f0842c035fe6d33eb2a947915af53a1ef501916ec7128bff9514d6184e2c",
-        "token3_sm2_public": "qaao4Xh8/eyYGeVOj1K8D7p3+OriP55azWDAbYVoZelMdluNrJuQWM2qPn+hjTHTBnIMAVK2HlHBx4oGfCxGdA==",
-        "token3_sm2_private": "8bSYM8P3b4I94qGt3XVx3bQddNCy/xVKo7o1b5LI4/M=",
-        "token3_sm4": "BIDhFaEu5NILR7byg/JfaPlJEm4dYWC+u9J1IqhtYeYY1AktOxp7cZWqfk/mWjw72pYGT7YRENCULbjZ2bxVG6UUv2pYukZWtYog34Vicu5IgC8ti4VpED9eGzGgtKJ/CT0KtAnjQPQL0PsVbCjTY5M=",
-        "token3_sm4_mw": "bbeb56d247354360",
+      //2、非警情分流查询服务_宜宾市
+      //   send-工单办结
+      //   http://10.12.185.168:8001/service/api/ds/12345To110/chainDeal
+      "token2_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token2_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token2_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token2_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token2_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token2_sm4_mw": "2938d7acb2754a09",
 
-        //2、非警情分流查询服务_宜宾市
-        //   send-工单办结
-        //   http://10.12.185.168:8001/service/api/ds/12345To110/chainDeal
-        "token2_token": "1fbbac1b09b89d11bc569168aabb3c8b",
-        "token2_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
-        "token2_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
-        "token2_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
-        "token2_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
-        "token2_sm4_mw": "2938d7acb2754a09",
+      //5、从公安网侧获取12345政务服务热线平台知识库列表
+      //   send-知识库列表
+      //   http://10.12.185.168:8001/service/api/ds/get_knowledge_info
+      "token5_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token5_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token5_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token5_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token5_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token5_sm4_mw": "2938d7acb2754a09",
 
-        //5、从公安网侧获取12345政务服务热线平台知识库列表
-        //   send-知识库列表
-        //   http://10.12.185.168:8001/service/api/ds/get_knowledge_info
-        "token5_token": "1fbbac1b09b89d11bc569168aabb3c8b",
-        "token5_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
-        "token5_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
-        "token5_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
-        "token5_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
-        "token5_sm4_mw": "2938d7acb2754a09",
-
-        //6、从公安网侧获取12345政务服务热线平台知识内容
-        //   send-知识库内容
-        //   http://10.12.185.168:8001/service/api/ds/get_knowledge_content
-        "token6_token": "1fbbac1b09b89d11bc569168aabb3c8b",
-        "token6_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
-        "token6_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
-        "token6_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
-        "token6_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
-        "token6_sm4_mw": "2938d7acb2754a09"
-      }
+      //6、从公安网侧获取12345政务服务热线平台知识内容
+      //   send-知识库内容
+      //   http://10.12.185.168:8001/service/api/ds/get_knowledge_content
+      "token6_token": "1fbbac1b09b89d11bc569168aabb3c8b",
+      "token6_dcsm": "3873c1b1ff0ce3b8120d63509d3b85169cda4856b0a0d89625a4744641a343951d8ced868bd5c7fc60826403bd6314a02e5a26ba8808dae5a9d9f851555338d0",
+      "token6_sm2_public": "VgjJ7FfA23vY3Hr1pVrdbi3MZt7X0k/nMf9kwEyyC32CXgT2ccWBlxf3kGPXLO56HSBoo9IA7sSEG3eJYVQmLw==",
+      "token6_sm2_private": "QNTPy2nPBe2JY308G0LHO4r42iomDWcdedf81FapkWA=",
+      "token6_sm4": "BKNpLwBCT2MvXwhLRcZ6FoMm4GaXs6LXqVmEa5hMJ3d9G+vC/5j7xtQh9HRKIfSfXkDQI0EQS7UR4inEXks/AnKsLYGhmhRjyzM7AGpEsujr2vJTwcwIWpBmpuc7k0uBQ34bN+kopafIo5UVyk7rIek=",
+      "token6_sm4_mw": "2938d7acb2754a09"
+    },
+    //智能质检
+    "AiQuality": {
+      "Url": ""
     }
+  }
 
 }

+ 4 - 0
src/Hotline.Api/config/appsettings.json

@@ -97,5 +97,9 @@
     "Username": "root",
     "Password": "12345678aa",
     "Ip": "222.213.23.229"
+  },
+  //智能质检
+  "AiQuality": {
+    "Url": ""
   }
 }

+ 6 - 5
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -21,7 +21,7 @@ namespace Hotline.Application.FlowEngine
         /// 流转至下一节点(节点办理)
         /// </summary>
         Task NextAsync(NextWorkflowDto dto, CancellationToken cancellationToken);
-        
+
         /// <summary>
         /// 退回(返回前一节点)
         /// </summary>
@@ -45,7 +45,8 @@ namespace Hotline.Application.FlowEngine
         /// <summary>
         /// 跳转至结束节点(无视流程模板配置直接跳至结束节点)
         /// </summary>
-        Task JumpToEndAsync(string workflowId, string opinion,List<FileDto> file, EReviewResult? reviewResult = EReviewResult.Unknown,
+        Task JumpToEndAsync(string workflowId, string opinion, List<FileDto> file,
+            EReviewResult? reviewResult = EReviewResult.Unknown,
             CancellationToken cancellationToken = default);
 
         /// <summary>
@@ -68,17 +69,17 @@ namespace Hotline.Application.FlowEngine
         /// <summary>
         /// 查询开始流程的下一步待选节点
         /// </summary>
-        Task<NextStepsDto> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken);
+        Task<NextStepsDto<NextStepOption>> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询办理流程的下一步待选节点
         /// </summary>
-        Task<NextStepsDto> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken);
+        Task<NextStepsDto<NextStepOption>> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询撤回可选节点
         /// </summary>
-        Task<RecallStepsDto> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken);
+        Task<NextStepsDto<RecallStepOption>> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken);
 
         /// <summary>
         /// 查询跳转可选节点

+ 10 - 8
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -463,7 +463,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// <summary>
     /// 查询开始流程的下一步待选节点
     /// </summary>
-    public async Task<NextStepsDto> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken)
+    public async Task<NextStepsDto<NextStepOption>> GetStartStepsAsync(string moduleCode, CancellationToken cancellationToken)
     {
         var wfModule = await GetWorkflowModuleAsync(moduleCode, cancellationToken);
         var definition = wfModule.Definition;
@@ -489,7 +489,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             //return dto;
             var nextStepOption = await GetDynamicStepAsync(startStepDefine.InstancePolicy.Value,
                 startStepDefine.StepType, startStepDefine.BusinessType, cancellationToken);
-            return new NextStepsDto
+            return new NextStepsDto<NextStepOption>
             {
                 Steps = new List<NextStepOption> { nextStepOption }
             };
@@ -502,7 +502,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         //var steps = firstStepDefines
         //        .Select(d => new NextStepOption { Key = d.Code, Value = d.Name })
         //        .ToList();
-        return new NextStepsDto
+        return new NextStepsDto<NextStepOption>
         {
             Steps = await GetConfigStepsAsync(definition.FlowType, startStepDefine.StepType, startStepDefine.BusinessType,
                 firstStepDefines,
@@ -515,7 +515,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// <summary>
     /// 查询办理流程的下一步待选节点
     /// </summary>
-    public async Task<NextStepsDto> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken)
+    public async Task<NextStepsDto<NextStepOption>> GetNextStepsAsync(string workflowId, CancellationToken cancellationToken)
     {
         var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, true, true,
             cancellationToken: cancellationToken);
@@ -523,12 +523,12 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (currentStep.StepType is EStepType.End)
             throw new UserFriendlyException("结束节点无需办理");
 
-        var dto = new NextStepsDto
+        var dto = new NextStepsDto<NextStepOption>
         {
             CanReject = workflow.IsReviewType() && currentStep.CanReject,
             ExpiredTime = workflow.ExpiredTime,
             CanStartCountersign = currentStep.CanStartCountersign,
-            //RealCommunicationModeOptions = EnumExts.GetDescriptions<ERealCommunicationMode>().ToList(),
+            CurrentStepBusinessType = currentStep.BusinessType,
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList()
         };
 
@@ -596,7 +596,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
     /// <summary>
     /// 查询撤回可选节点及办理对象
     /// </summary>
-    public async Task<RecallStepsDto> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken)
+    public async Task<NextStepsDto<RecallStepOption>> GetRecallStepsAsync(string workflowId, CancellationToken cancellationToken)
     {
         var workflow =
             await _workflowDomainService.GetWorkflowAsync(workflowId, true, true, cancellationToken: cancellationToken);
@@ -607,7 +607,7 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         if (currentStep is null)
             throw new UserFriendlyException("无效当前节点编号");
 
-        var dto = new RecallStepsDto
+        var dto = new NextStepsDto<RecallStepOption>
         {
             TimeTypeOptions = EnumExts.GetDescriptions<ETimeType>().ToList()
         };
@@ -814,6 +814,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         {
             Key = stepDefine.Code,
             Value = stepDefine.Name,
+            StepType = stepDefine.StepType,
+            BusinessType = stepDefine.BusinessType,
             Items = handlers
         };
     }

+ 16 - 6
src/Hotline.Application/Quality/QualityApplication.cs

@@ -21,6 +21,7 @@ namespace Hotline.Application.Quality
         private readonly IAiQualityService _aiQualityService;
         private readonly IOrderRepository _orderRepository;
         private readonly IRepository<TrCallRecord> _trCallRecordRepository;
+        private readonly IRepository<QualityTemplate> _qualityTemplate;
 
 		public QualityApplication(
             ISessionContext sessionContext,
@@ -29,6 +30,7 @@ namespace Hotline.Application.Quality
             IQualityRepository qualityRepository,
             IAiQualityService aiQualityService,
             IRepository<TrCallRecord> trCallRecordRepository,
+            IRepository<QualityTemplate> qualityTemplate,
 			IOrderRepository orderRepository
 		)
         {
@@ -38,6 +40,7 @@ namespace Hotline.Application.Quality
             _qualityRepository = qualityRepository;
             _aiQualityService = aiQualityService;
             _trCallRecordRepository = trCallRecordRepository;
+            _qualityTemplate = qualityTemplate;
 			_orderRepository = orderRepository;
 
 		}
@@ -83,12 +86,19 @@ namespace Hotline.Application.Quality
             }
             //受理智能质检
             if (model.Source == EQualitySource.Accepted) {
-                var order = await _orderRepository.GetAsync(model.OrderId);
-				if (order != null  && !string.IsNullOrEmpty(order.CallId))
-	            {
-		            var call = await _trCallRecordRepository.GetAsync(order.CallId);
-                    await _aiQualityService.CreateAiOrderQualityTask(quality, call, order, cancellationToken);
-                }
+                var teAny = await _qualityTemplate.Queryable()
+                    .LeftJoin<QualityTemplateDetail>((x, d) => x.Id == d.TemplateId)
+                    .LeftJoin<QualityItem>((x, d, i) => d.ItemId == i.Id)
+                    .Where((x, d, i) => i.IsIntelligent == 1).AnyAsync();
+                if (teAny)
+                {
+					var order = await _orderRepository.GetAsync(model.OrderId);
+					if (order != null && !string.IsNullOrEmpty(order.CallId))
+					{
+						var call = await _trCallRecordRepository.GetAsync(order.CallId);
+						await _aiQualityService.CreateAiOrderQualityTask(quality, call, order, cancellationToken);
+					}
+				}
             }
         }
 

+ 44 - 0
src/Hotline.Share/Dtos/FlowEngine/NextStepOption.cs

@@ -0,0 +1,44 @@
+using Hotline.Share.Enums.FlowEngine;
+
+namespace Hotline.Share.Dtos.FlowEngine;
+
+public class NextStepOption : Kv
+{
+    /// <summary>
+    /// 是否回到会签发起节点汇总
+    /// </summary>
+    public bool BackToCountersignEnd { get; set; }
+
+    /// <summary>
+    /// 是否需要填写真实办理人信息
+    /// </summary>
+    public bool InputRealHandler { get; set; }
+
+    /// <summary>
+    /// 流转方向
+    /// </summary>
+    public EFlowDirection? FlowDirection { get; set; }
+
+    /// <summary>
+    /// 模板配置节点类型
+    /// </summary>
+    public EStepType StepType { get; set; }
+
+    /// <summary>
+    /// 模板配置节点业务类型
+    /// </summary>
+    public EBusinessType BusinessType { get; set; }
+
+    /// <summary>
+    /// 节点下可选办理对象
+    /// </summary>
+    public IReadOnlyList<Kv> Items { get; set; }
+}
+
+public class RecallStepOption : NextStepOption
+{
+    /// <summary>
+    /// 该节点原办理对象
+    /// </summary>
+    public Kv Handler { get; set; }
+}

+ 32 - 67
src/Hotline.Share/Dtos/FlowEngine/NextStepsDto.cs

@@ -4,10 +4,7 @@ namespace Hotline.Share.Dtos.FlowEngine;
 
 public class NextStepsDto
 {
-    //public string DefinitionId { get; set; }
-    //public EInstanceMode InstanceMode { get; set; }
-    //public EDynamicPolicy DynamicPolicy { get; set; }
-    public IReadOnlyList<NextStepOption> Steps { get; set; }
+    // public IReadOnlyList<NextStepOption> Steps { get; set; }
     public DateTime? ExpiredTime { get; set; }
 
     /// <summary>
@@ -20,41 +17,17 @@ public class NextStepsDto
     /// </summary>
     public bool CanStartCountersign { get; set; }
 
-    //public IReadOnlyList<KeyValuePair<int, string>> RealCommunicationModeOptions { get; set; }
-    public IReadOnlyList<KeyValuePair<int, string>> TimeTypeOptions { get; set; }
-}
-
-public class NextStepOption : Kv
-{
     /// <summary>
-    /// 是否回到会签发起节点汇总
+    /// 当前办理节点业务类型
     /// </summary>
-    public bool BackToCountersignEnd { get; set; }
+    public EBusinessType CurrentStepBusinessType { get; set; }
 
-    /// <summary>
-    /// 是否需要填写真实办理人信息
-    /// </summary>
-    public bool InputRealHandler { get; set; }
-
-    /// <summary>
-    /// 流转方向
-    /// </summary>
-    public EFlowDirection? FlowDirection { get; set; }
-
-    /// <summary>
-    /// 模板配置节点类型
-    /// </summary>
-    public EStepType StepType { get; set; }
-
-    /// <summary>
-    /// 模板配置节点业务类型
-    /// </summary>
-    public EBusinessType BusinessType { get; set; }
+    public IReadOnlyList<KeyValuePair<int, string>> TimeTypeOptions { get; set; }
+}
 
-    /// <summary>
-    /// 节点下可选办理对象
-    /// </summary>
-    public IReadOnlyList<Kv> Items { get; set; }
+public class NextStepsDto<TSteps> : NextStepsDto
+{
+    public IReadOnlyList<TSteps> Steps { get; set; }
 }
 
 public class GetNextStepItemsDto
@@ -65,35 +38,27 @@ public class GetNextStepItemsDto
     public NextStepOption Step { get; set; }
 }
 
-/// <summary>
-/// 撤回可选节点参数
-/// </summary>
-public class RecallStepsDto
-{
-    public IReadOnlyList<RecallStepOption> Steps { get; set; }
-
-    //public DateTime? ExpiredTime { get; set; }
-
-    /// <summary>
-    /// 是否有否决按钮
-    /// </summary>
-    public bool CanReject { get; set; }
-
-    /// <summary>
-    /// 是否支持发起会签
-    /// </summary>
-    public bool CanStartCountersign { get; set; }
-
-    /// <summary>
-    /// 办理时限时间类型待选参数
-    /// </summary>
-    public IReadOnlyList<KeyValuePair<int, string>> TimeTypeOptions { get; set; }
-}
-
-public class RecallStepOption : NextStepOption
-{
-    /// <summary>
-    /// 该节点原办理对象
-    /// </summary>
-    public Kv Handler { get; set; }
-}
+// /// <summary>
+// /// 撤回可选节点参数
+// /// </summary>
+// public class RecallStepsDto
+// {
+//     public IReadOnlyList<RecallStepOption> Steps { get; set; }
+//
+//     //public DateTime? ExpiredTime { get; set; }
+//
+//     /// <summary>
+//     /// 是否有否决按钮
+//     /// </summary>
+//     public bool CanReject { get; set; }
+//
+//     /// <summary>
+//     /// 是否支持发起会签
+//     /// </summary>
+//     public bool CanStartCountersign { get; set; }
+//
+//     /// <summary>
+//     /// 办理时限时间类型待选参数
+//     /// </summary>
+//     public IReadOnlyList<KeyValuePair<int, string>> TimeTypeOptions { get; set; }
+// }

+ 14 - 1
src/Hotline.Share/Dtos/Order/NextStepsWithRecommendDto.cs

@@ -8,7 +8,20 @@ public class NextStepsWithRecommendDto : NextStepsDto
     /// 推荐部门id
     /// </summary>
     public string RecommendOrgId { get; set; }
-    
+
+    /// <summary>
+    /// 推荐部门名称
+    /// </summary>
+    public string RecommendOrgName { get; set; }
+}
+
+public class RecommendStepOption : NextStepOption
+{
+    /// <summary>
+    /// 推荐部门id
+    /// </summary>
+    public string RecommendOrgId { get; set; }
+
     /// <summary>
     /// 推荐部门名称
     /// </summary>

+ 178 - 1
src/Hotline.Share/Dtos/Quality/AiQualityDto.cs

@@ -71,6 +71,183 @@ namespace Hotline.Share.Dtos.Quality
 		/// <summary>
 		/// 扩展字段
 		/// </summary>
-		public string Extend { get; set; } 
+		public string Extend { get; set; }
+	}
+
+	public class AiQualityResultDto
+	{
+		public AiQualitySourceData source_data { get; set; }
+
+		public AiQualityAnalysisData analysis_data { get; set; }
+	}
+	public class AiQualitySourceData
+	{
+		/// <summary>
+		/// 录音PATH地址
+		/// </summary>
+		public string record_path { get; set; }
+
+		/// <summary>
+		/// 录音URL地址
+		/// </summary>
+		public string record_url { get; set; }
+
+		/// <summary>
+		/// 客户id,全局唯一
+		/// </summary>
+		public string customer_id { get; set; }
+
+		/// <summary>
+		/// 录音文件名称
+		/// </summary>
+		public string file_name { get; set; }
+
+		/// <summary>
+		/// 坐席工号
+		/// </summary>
+		public string agent_id { get; set; }
+
+		/// <summary>
+		/// 坐席组的编号
+		/// </summary>
+		public string agent_group_no { get; set; }
+
+		/// <summary>
+		/// 来电号码
+		/// </summary>
+		public string call_number { get; set; }
+
+		/// <summary>
+		/// 通话的来电时间
+		/// </summary>
+		public string call_time { get; set; }
+
+		/// <summary>
+		/// 录音格式,wav、mp3、v3、pcm等
+		/// </summary>
+		public string record_form { get; set; }
+
+		/// <summary>
+		/// 采样率
+		/// </summary>
+		public string sampling_rate { get; set; }
+
+		/// <summary>
+		/// 编码方式
+		/// </summary>
+		public string encoding { get; set; }
+
+		/// <summary>
+		/// 声道数(个)
+		/// </summary>
+		public int sound_channel { get; set; }
+
+		/// <summary>
+		/// 坐席声音存储的声道
+		/// </summary>
+		public int agent_channel { get; set; }
+
+		/// <summary>
+		/// 来电地区
+		/// </summary>
+		public string region { get; set; }
+
+		/// <summary>
+		/// 工单上传时间
+		/// </summary>
+		public string upload_time { get; set; }
+
+		/// <summary>
+		/// 来源,1:平台上传;2:接口上传
+		/// </summary>
+		public string source { get; set; }
+
+		/// <summary>
+		/// 文件大小
+		/// </summary>
+		public string file_size { get; set; }
+
+		/// <summary>
+		/// 文件上传时间
+		/// </summary>
+		public string file_upload_time { get; set; }
+
+		public AiQualityExtended extended_field { get; set; }
+
+	}
+	public class AiQualityExtended
+	{
+		public string field1 { get; set; }
+	}
+	public class AiQualityAnalysisData 
+	{
+		/// <summary>
+		/// 智能质检得分
+		/// </summary>
+		public int quality_score { get; set; }
+
+		/// <summary>
+		/// 智能质检时间
+		/// </summary>
+		public string quality_time { get; set; }
+
+		/// <summary>
+		/// 是否减分[1是0否]
+		/// </summary>
+		public int reduction_flag { get; set; }
+
+		/// <summary>
+		/// 智能质检策略名称
+		/// </summary>
+		public string strategy_name { get; set; }
+
+		/// <summary>
+		/// 智能质检评分规则名称
+		/// </summary>
+		public string score_name { get; set; }
+
+		public List<AiQualityScoreItems> score_items { get; set; }
+	}
+	public class AiQualityScoreItems 
+	{
+		/// <summary>
+		/// 智能评分项名称
+		/// </summary>
+		public string name { get; set; }
+
+		/// <summary>
+		/// 质检方式,1:质检规则;2:智能分类器;
+		/// </summary>
+		public int type { get; set; }
+
+		/// <summary>
+		/// 出现个数
+		/// </summary>
+		public string num { get; set; }
+
+		/// <summary>
+		/// 出现次数
+		/// </summary>
+		public int times { get; set; }
+
+		/// <summary>
+		/// 评分项说明
+		/// </summary>
+		public string description { get; set; }
+
+		/// <summary>
+		/// 分值类型,0:减分;1:加分
+		/// </summary>
+		public int score_type { get; set; }
+
+		/// <summary>
+		/// 分值
+		/// </summary>
+		public int score { get; set; }
+
+		/// <summary>
+		/// 评分项结果评分
+		/// </summary>
+		public int result_score { get; set; }
 	}
 }