Bladeren bron

增强日志记录并添加健康检查功能

在 `GroupsController.cs` 中添加了 `Microsoft.Extensions.Logging` 的引用,修改了方法以增强日志记录功能。移除了 `OASystem.Domain.ViewModels.Statistics` 的引用,并调整了数据处理逻辑,增加了对经济舱和公务舱的审核逻辑。新增了 `ExampleHealthCheck`、`DatabaseHealthCheck` 和 `ApiHealthCheck` 类以实现健康检查功能。在 `OASystem.API.csproj` 中添加了相关的 NuGet 包引用,并在 `Program.cs` 中配置了健康检查服务及其路由和 UI 端点。同时,移除了部分注释代码,清理了代码结构。
Lyyyi 6 dagen geleden
bovenliggende
commit
2184726b69

+ 64 - 114
OASystem/OASystem.Api/Controllers/GroupsController.cs

@@ -4,6 +4,7 @@ using Aspose.Words.Drawing;
 using Aspose.Words.Tables;
 using DiffMatchPatch;
 using Microsoft.AspNetCore.SignalR;
+using Microsoft.Extensions.Logging;
 using NPOI.HSSF.UserModel;
 using NPOI.SS.UserModel;
 using NPOI.SS.Util;
@@ -29,7 +30,6 @@ using OASystem.Domain.Entities.Groups;
 using OASystem.Domain.ViewModels.Financial;
 using OASystem.Domain.ViewModels.Groups;
 using OASystem.Domain.ViewModels.OCR;
-using OASystem.Domain.ViewModels.Statistics;
 using OASystem.Infrastructure.Repositories.CRM;
 using OASystem.Infrastructure.Repositories.Financial;
 using OASystem.Infrastructure.Repositories.Groups;
@@ -40,7 +40,6 @@ using System.Data;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO.Compression;
-using System.Text.Json.Nodes;
 using System.Web;
 using static OASystem.API.OAMethodLib.JWTHelper;
 using static OASystem.Infrastructure.Repositories.Groups.AirTicketResRepository;
@@ -802,7 +801,8 @@ namespace OASystem.API.Controllers
             if (dto.UserId < 1) return Ok(JsonView(false, "员工Id为空"));
             if (dto.PageId < 1) return Ok(JsonView(false, "页面Id为空"));
 
-            PageFunAuthViewBase pageFunAuthView = new PageFunAuthViewBase();
+            PageFunAuthViewBase 
+                pageFunAuthView = new PageFunAuthViewBase();
             #region 页面操作权限验证
             pageFunAuthView = await GeneralMethod.PostUserPageFuncDatas(dto.UserId, dto.PageId);
 
@@ -4256,17 +4256,13 @@ FROM
                 int dataId = groupData.Data.GetType().GetProperty("dataId").GetValue(groupData.Data, null);
 
                 //自动审核
-                var autoAdit = await _feeAuditRep.FeeAutomaticAudit(5, diId, dataId); //机票费用合计方式
-
-                #region 舱位单价方式
-               
-
-
-
-                #endregion
-
-
+                //var autoAdit1 = await _feeAuditRep.FeeAutomaticAudit(5, diId, dataId); //机票费用合计方式
+                (bool status,string auditMsg) = await AirTicketResAutoAudit(diId, dataId); //KIMI-AI识别INIT方式
 
+                _logger.LogInformation("【机票费用自动审核(KIMI-AI识别INIT)】请求参数:{RequstData} 返回结果:是否执行:{IsExecute}; 结果消息:{ResponseMsg};",
+                    $"GroupId:{diId};airId:{dataId};",
+                    status,
+                    auditMsg);
 
                 await AppNoticeLibrary.SendChatMsg_GroupStatus_ApplyFee(ccpId, sign, QiyeWeChatEnum.GuoJiaoLeaderChat);
 
@@ -4297,27 +4293,34 @@ FROM
         /// 机票费用自动审核 AI识别方式
         /// </summary>
         /// <returns></returns>
-        private async Task<(bool, string)> AirTicketResAutoAudit(int diId,int dataId)
+        private async Task<(bool, string)> AirTicketResAutoAudit(int diId, int dataId)
         {
-            var auditFeeTypeIds = new List<int>() {
-                    457,   //头等舱
-                    458,   //公务舱
+            var ecoTypeIds = new List<int>() {
                     459,   //超经舱
                     460,   //经济舱
                     1430,  //公务舱(实际经济舱)
-                    1431,  //头等舱(实际公务舱)
                     1432,  //头等舱(实际经济舱)
                 };
+            var bizTypeIds = new List<int>() {
+                    457,   //头等舱
+                    458,   //公务舱
+                    1431,  //头等舱(实际公务舱)
+                };
+
+            var auditFeeTypeIds = new List<int>() {};
+            auditFeeTypeIds.AddRange(ecoTypeIds);
+            auditFeeTypeIds.AddRange(bizTypeIds);
 
             int currModule = 85;
             var airInfo = await _sqlSugar.Queryable<Grp_AirTicketReservations>()
                 .InnerJoin<Grp_CreditCardPayment>((x, y) => x.Id == y.CId && y.CTable == currModule && y.IsDel == 0)
                 .Where((x, y) => x.Id == dataId && x.IsDel == 0 && auditFeeTypeIds.Contains(x.CType))
-                .Select((x, y) => new {
+                .Select((x, y) => new
+                {
                     x.Id,
                     CcpId = y.Id,
                     x.FlightsDate,
-                    x.Price,
+                    x.PrePrice,
                     x.CType,
                     x.ClientNum,
                     x.DIId
@@ -4339,6 +4342,7 @@ FROM
 
             //处理 成本详细信息日期为空 填装费用信息 
             var airFeeLabel = new StringBuilder();
+            airFeeLabel.AppendLine("费用成本:");
             for (int i = 0; i < groupCostContents.Count; i++)
             {
                 if (string.IsNullOrEmpty(groupCostContents[i].Date))
@@ -4359,10 +4363,10 @@ FROM
 
                 var item = groupCostContents[i];
                 airFeeLabel.AppendLine($"{item.Date}");
-                airFeeLabel.AppendLine($"{item.ITIN.Replace("\n"," ")}");
+                airFeeLabel.AppendLine($"{item.ITIN.Replace("\n", " ")}");
             }
             airFeeLabel.AppendLine($"注:费用:位置:航班号或者航班时间后面; 组成:经济舱/公务舱;");
-            airFeeLabel.AppendLine($"取出{airInfo.FlightsDate}费用金额,按照经济舱/公务舱格式返回,如果不存在的话则返回0.00/0.00,只返回金额格式文本;不需要其他文字描述;");
+            airFeeLabel.AppendLine($"取出{airInfo.FlightsDate}费用金额,按照经济舱/公务舱格式返回,如果不存在的话则返回0.00/0.00,只返回金额格式文本;不需要其他文字描述;");
 
             //访问Kimi AI 返回价格结果
             var msgs = new List<SeedMessages>()
@@ -4379,10 +4383,46 @@ FROM
             var kimiApiResult_JObject = JObject.Parse(kimiApiResult);
             string clients = kimiApiResult_JObject["content"].ToString();
 
+            decimal ecoPri_kimiAI = 0.00M,
+                    bizPri_kimiAI = 0.00M;
+            //单个价格: 经济舱价格
+            if (decimal.TryParse(clients, out ecoPri_kimiAI)) { }
+            //价格文本包含/:/前经济舱价格 /后公务舱价格
+            if (clients.Contains('/'))
+            {
+                var priArray = clients.Split('/');
+                decimal.TryParse(priArray[0], out ecoPri_kimiAI); //
+                decimal.TryParse(priArray[1], out bizPri_kimiAI); //经济舱价格
+            }
+            else return (false, "价格文本不存在价格或KIMI-AI未识别出价格,不可自动审核!");
 
+            var isAutoAudit = false;
+            //价格验证处理
+            //经济舱
+            if (ecoTypeIds.Contains(airInfo.CType))
+            {
+                if (airInfo.PrePrice <= ecoPri_kimiAI) isAutoAudit = true;
+            }
+            //公务舱
+            else if (bizTypeIds.Contains(airInfo.CType))
+            {
+                if (airInfo.PrePrice <= bizPri_kimiAI) isAutoAudit = true;
+            }
+            else return (false, "该舱位类型不在自动审核范围内,不可自动审核!");
 
+            //是否执行自动审核
+            if (isAutoAudit)
+            {
+                var auditStatus = await _sqlSugar.Updateable<Grp_CreditCardPayment>()
+                    .SetColumns(x => x.IsAuditGM == 3)
+                    .SetColumns(x => x.AuditGMOperate == 4)
+                    .SetColumns(x => x.AuditGMDate == DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))
+                    .Where(x => x.Id == airInfo.CcpId)
+                    .ExecuteCommandAsync();
+                if (auditStatus > 0 ) return (true, "机票自动审核(KIMI-AI识别方式)执行成功!");
+            }
 
-            return (false,"不可自动审核!");
+            return (false, "当前费用超过成本费用,不可自动审核!");
         }
 
         /// <summary>
@@ -4396,7 +4436,7 @@ FROM
         [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
         public async Task<IActionResult> AirTicketResAutoAuditTest(int groupId, int Id)
         {
-            (bool status,string msg) = await AirTicketResAutoAudit(groupId, Id);
+            (bool status, string msg) = await AirTicketResAutoAudit(groupId, Id);
 
             return Ok(JsonView(status, msg));
         }
@@ -25563,96 +25603,6 @@ ORDER BY
         }
         #endregion
 
-        //        /// <summary>
-        //        /// 
-        //        /// </summary>
-        //        /// <param name="_dto"></param>
-        //        /// <returns></returns>
-        //        [HttpPost]
-        //        [ProducesResponseType(typeof(JsonView), StatusCodes.Status200OK)]
-        //        public async Task<IActionResult> Test_DataChange(PostTourClientListDownloadFile _dto)
-        //        {
-        //            _airTicketResRep.ChangeDataBase(DBEnum.OA2014DB);
-
-        //            string sql = string.Format(@" Select * From Visa With(Nolock) ");
-        //            List<OA2014_Visa> list_visa = _airTicketResRep._sqlSugar.SqlQueryable<OA2014_Visa>(sql).ToList();
-
-        //            _airTicketResRep.ChangeDataBase(DBEnum.OA2023DB);
-        //            Dictionary<string, int> dic_psg = new Dictionary<string, int>();
-        //            dic_psg.Add("客人", 974);
-        //            dic_psg.Add("司机", 975);
-        //            dic_psg.Add("导游", 976);
-        //            dic_psg.Add("公司内部人员", 977);
-        //            dic_psg.Add("司机/导游/公司内部人员", 978);
-
-        //            foreach (var item in list_visa)
-        //            {
-        //                Grp_VisaInfo temp = new Grp_VisaInfo();
-
-        //                temp.Id = item.Id;
-        //                temp.DIId = item.DIId;
-        //                temp.VisaClient = item.VisaClient;
-        //                temp.VisaPrice = Convert.ToDecimal(item.VisaPrice);
-        //                temp.VisaCurrency = item.VisaCurrency;
-
-        //                temp.IsThird = item.IsThird;
-        //                if (dic_psg.ContainsKey(item.PassengerType))
-        //                {
-        //                    temp.PassengerType = dic_psg[item.PassengerType];
-        //                }
-        //                else {
-        //                    temp.PassengerType = -1;
-        //                }
-        //                temp.VisaNumber = item.VisaNumber;
-        //                temp.VisaFreeNumber = item.VisaFreeNumber;
-        //                temp.CreateUserId = item.Operators;
-        //                DateTime dt_ct;
-        //                bool b_ct = DateTime.TryParse(item.OperatorsDate, out dt_ct);
-        //                if (b_ct)
-        //                {
-        //                    temp.CreateTime = dt_ct;
-        //                }
-        //                else
-        //                {
-        //                    temp.CreateTime = DateTime.Now;
-        //                }
-        //                temp.DeleteTime = "";
-        //                temp.DeleteUserId = 0;
-        //                temp.Remark = item.Remark;
-        //                if (string.IsNullOrEmpty(temp.Remark)) {
-        //                    temp.Remark = "";
-        //                }
-        //                temp.IsDel = item.IsDel;
-        //                temp.VisaDescription = item.VisaAttachment;
-        //                string sqlInsert = string.Format(@" INSERT INTO [dbo].[Grp_VisaInfo]
-        //([Id]
-        //           ,[DIId]
-        //           ,[VisaClient]
-        //           ,[VisaPrice]
-        //           ,[VisaCurrency]
-        //           ,[IsThird]
-        //           ,[PassengerType]
-        //           ,[VisaNumber]
-        //           ,[VisaFreeNumber]
-        //           ,[CreateUserId]
-        //           ,[CreateTime]
-        //           ,[DeleteTime]
-        //           ,[DeleteUserId]
-        //           ,[Remark]
-        //           ,[IsDel]
-        //           ,[visaDescription])
-        //     VALUES
-        //           ({0},{1},'{2}',{3},{4}
-        //,{5},{6},{7},{8},{9}
-        //,'{10}','{11}',{12},'{13}',{14},'{15}') ",temp.Id,temp.DIId,temp.VisaClient,temp.VisaPrice,temp.VisaCurrency,
-        //temp.IsThird,temp.PassengerType,temp.VisaNumber,temp.VisaNumber,temp.CreateUserId,
-        //temp.CreateTime, temp.DeleteTime, temp.DeleteUserId, temp.Remark,temp.IsDel,temp.VisaDescription
-        //);
-        //               await _airTicketResRep.ExecuteCommandAsync(sqlInsert);
-        //            }
-        //            return Ok(JsonView(true, "操作成功!"));
-        //        }
-
         /// <summary>
         /// 123132123
         /// </summary>

+ 63 - 0
OASystem/OASystem.Api/HealthChecks/ExampleHealthCheck.cs

@@ -0,0 +1,63 @@
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+
+namespace OASystem.API.HealthChecks
+{
+    public class ExampleHealthCheck : IHealthCheck
+    {
+        public Task<HealthCheckResult> CheckHealthAsync(
+            HealthCheckContext context,
+            CancellationToken cancellationToken = default)
+        {
+            // Here you would check the health of your dependencies
+            // For example, check database connection, external services, etc.
+            var isHealthy = true; // Replace with actual health check logic
+
+            if (isHealthy)
+            {
+                return Task.FromResult(
+                    HealthCheckResult.Healthy("A healthy result."));
+            }
+
+            return Task.FromResult(
+                new HealthCheckResult(
+                    context.Registration.FailureStatus, "An unhealthy result."));
+        }
+    }
+
+    public class DatabaseHealthCheck : IHealthCheck
+    {
+        public async Task<HealthCheckResult> CheckHealthAsync(
+            HealthCheckContext context,
+            CancellationToken cancellationToken = default)
+        {
+            try
+            {
+                // 模拟数据库检查
+                await Task.Delay(100, cancellationToken);
+                return HealthCheckResult.Healthy("Database is OK");
+            }
+            catch (Exception ex)
+            {
+                return HealthCheckResult.Unhealthy("Database failure", ex);
+            }
+        }
+    }
+
+    public class ApiHealthCheck : IHealthCheck
+    {
+        private readonly HttpClient _httpClient;
+
+        public ApiHealthCheck(HttpClient httpClient) => _httpClient = httpClient;
+
+        public async Task<HealthCheckResult> CheckHealthAsync(
+            HealthCheckContext context,
+            CancellationToken cancellationToken = default)
+        {
+            var response = await _httpClient.GetAsync("ping", cancellationToken);
+            return response.IsSuccessStatusCode
+                ? HealthCheckResult.Healthy("API is responsive")
+                : HealthCheckResult.Degraded($"API response: {response.StatusCode}");
+        }
+    }
+
+}

+ 4 - 0
OASystem/OASystem.Api/OASystem.API.csproj

@@ -29,6 +29,9 @@
 
   <ItemGroup>
     <PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.23" />
+    <PackageReference Include="AspNetCore.HealthChecks.UI" Version="6.0.1" />
+    <PackageReference Include="AspNetCore.HealthChecks.UI.Client" Version="6.0.2" />
+    <PackageReference Include="AspNetCore.HealthChecks.UI.InMemory.Storage" Version="6.0.2" />
     <PackageReference Include="Aspose.Cells" Version="23.4.0" />
     <PackageReference Include="Autofac" Version="6.4.0" />
     <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="8.0.0" />
@@ -42,6 +45,7 @@
     <PackageReference Include="Flurl.Http" Version="3.2.4" />
     <PackageReference Include="JsonDiffPatch.Net" Version="2.3.0" />
     <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.11" />
+    <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="6.0.0" />
     <PackageReference Include="NodaTime" Version="3.2.0" />
     <PackageReference Include="NPOI" Version="2.7.1" />
     <PackageReference Include="PinYinConverterCore" Version="1.0.2" />

+ 42 - 23
OASystem/OASystem.Api/Program.cs

@@ -1,7 +1,10 @@
+using HealthChecks.UI.Client;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
 using Microsoft.AspNetCore.Http.Connections;
 using Microsoft.AspNetCore.Http.Features;
 using Microsoft.AspNetCore.Server.Kestrel.Core;
 using Microsoft.Extensions.DependencyInjection.Extensions;
+using OASystem.API.HealthChecks;
 using OASystem.API.Middlewares;
 using OASystem.API.OAMethodLib;
 using OASystem.API.OAMethodLib.AMapApi;
@@ -314,6 +317,25 @@ Log.Logger = new LoggerConfiguration()
 builder.Host.UseSerilog();
 #endregion
 
+#region 健康检查服务
+
+//// Add health checks
+//builder.Services.AddHealthChecks()
+//    .AddCheck<ExampleHealthCheck>("example_health_check")
+//    .AddCheck<DatabaseHealthCheck>("database")
+//    .AddCheck<ApiHealthCheck>("external_api",
+//        tags: new[] { "infrastructure" });
+
+//builder.Services.AddHealthChecksUI(options =>
+//{
+//    options.AddHealthCheckEndpoint("API", "/health");
+//    options.AddHealthCheckEndpoint("External Service", "https://other-service/health"); // 外部服务
+//}).AddInMemoryStorage();
+
+//builder.Services.AddEndpointsApiExplorer();
+
+#endregion
+
 #region 引入注册Autofac Module
 builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
 var hostBuilder = builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
@@ -389,24 +411,6 @@ builder.Services.AddSignalR()
 builder.Services.TryAddSingleton(typeof(CommonService));
 #endregion
 
-#region 健康检查服务
-
-//// 
-//builder.Services.AddHealthChecks()
-//    .AddCheck("ExampleHealthCheck", () =>
-//        HealthCheckResult.Healthy("Everything is OK!"), tags: new[] { "example" });
-
-//// 添加 HealthChecks UI 服务
-//builder.Services.AddHealthChecksUI(setup =>
-//{
-//    setup.SetEvaluationTimeInSeconds(60); // 每 60 秒检查一次
-//    setup.MaximumHistoryEntriesPerEndpoint(50); // 每个端点最多保存 50 条历史记录
-//    setup.SetApiMaxActiveRequests(1); // UI API 的最大并发请求数
-//})
-//.AddInMemoryStorage(); // 使用内存存储健康检查结果
-
-#endregion
-
 var app = builder.Build();
 
 //serilog日志 请求中间管道
@@ -534,15 +538,30 @@ app.MapHub<ChatHub>("/ChatHub", options =>
 
 #region 配置健康检查端点
 
-// 配置健康检查端点
 //app.MapHealthChecks("/health", new HealthCheckOptions
 //{
-//    Predicate = _ => true, // 包含所有健康检查
-//    ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse // 使用 UI 的响应格式
+//    ResponseWriter = async (context, report) =>
+//    {
+//        var result = new
+//        {
+//            Status = report.Status.ToString(),
+//            Checks = report.Entries.Select(e => new {
+//                Name = e.Key,
+//                Status = e.Value.Status.ToString(),
+//                Description = e.Value.Description
+//            }),
+//            Duration = report.TotalDuration
+//        };
+//        await context.Response.WriteAsJsonAsync(result);
+//    }
 //});
 
-
-
+//// 健康检查UI仪表板(可视化界面)
+//app.MapHealthChecksUI(options =>
+//{
+//    options.UIPath = "/health-ui"; // 访问路径
+//    options.ApiPath = "/health-ui-api"; // API路径(供UI前端调用)
+//});
 #endregion
 
 app.MapControllerRoute(