diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs index 13cdaf64..1cdfed66 100644 --- a/ZR.Admin.WebApi/Program.cs +++ b/ZR.Admin.WebApi/Program.cs @@ -12,9 +12,12 @@ using ZR.Admin.WebApi.Hubs; using ZR.Admin.WebApi.Middleware; using ZR.Common.Cache; using ZR.Common.MqttHelper; +using ZR.Service.mes.andon; using ZR.Service.mqtt; var builder = WebApplication.CreateBuilder(args); +//后台定时任务 +builder.Services.AddHostedService(); // Add services to the container. builder.Services.AddControllers(); //配置中心 diff --git a/ZR.Service/mes/andon/AndonAlarmRecordService.cs b/ZR.Service/mes/andon/AndonAlarmRecordService.cs index ba521570..a78ff08a 100644 --- a/ZR.Service/mes/andon/AndonAlarmRecordService.cs +++ b/ZR.Service/mes/andon/AndonAlarmRecordService.cs @@ -1,9 +1,11 @@ +using Aliyun.OSS; using Infrastructure.Attribute; using Infrastructure.Model; using JinianNet.JNTemplate.Parsers; using SqlSugar; using SqlSugar.Extensions; using System; +using System.Linq; using ZR.Model; using ZR.Model.MES.andon; using ZR.Model.MES.andon.Dto; @@ -259,6 +261,7 @@ namespace ZR.Service.mes.andon andonAlarmRecordProcess.UpdatedName = parm.UserName; andonAlarmRecordProcess.UpdatedTime = DateTime.Now; int iResult = andonAlarmRecordProcessService.Insert(andonAlarmRecordProcess); + //报警给领导 return ApiResult.Success("成功", andonAlarmRecordProcess); } else @@ -271,5 +274,158 @@ namespace ZR.Service.mes.andon return ApiResult.Error(500, ex.Message); } } + + + /// + /// 查询一小时内生成的所有未处理报警记录,自动进行超时报警(分批次处理,每批500条) + /// + /// ApiResult + public ApiResult AlarmReportAuto() + { + // 定义批次大小,可配置化(便于后续调整) + const int BatchSize = 500; + var currentTime = DateTime.Now; + var startTime = currentTime.AddHours(-1); + var endTime = currentTime; + + try + { + var alarmLevelMap = andonAlarmLevelService.Queryable() + .Where(level => !string.IsNullOrWhiteSpace(level.LevelName) && level.HandleTimeout.HasValue) + .ToDictionary( + level => (object)level.LevelName.Trim(), + level => (object)Convert.ToInt32(level.HandleTimeout.Value) + ); + + var queryData = Queryable() + .Where(x => + (x.Status == "待响应" || x.Status == "及时响应" || x.Status == "超时响应") + && x.CreatedTime >= startTime + && x.CreatedTime <= endTime) + .ToList(); + + if (!queryData.Any()) + { + return ApiResult.Success("无需要处理的报警数据"); + } + + var totalCount = queryData.Count; + var batchCount = (int)Math.Ceiling((double)totalCount / BatchSize); + var allProcessRecords = new List(); + var batchUpdateList = new List(); + + for (int batchIndex = 0; batchIndex < batchCount; batchIndex++) + { + try + { + var currentBatch = queryData.Skip(batchIndex * BatchSize).Take(BatchSize).ToList(); + batchUpdateList.Clear(); + + foreach (var item in currentBatch) + { + if (string.IsNullOrWhiteSpace(item.AlarmLevel)) continue; + var alarmLevelKey = item.AlarmLevel?.Trim() ?? ""; + int timeoutMinutes = 0; + if (alarmLevelMap.TryGetValue(alarmLevelKey, out object value)) + { + timeoutMinutes = (int)value; + } + + if (timeoutMinutes <= 0) continue; + var createdTime = item.CreatedTime.ObjToDate(); + var timeoutTime = createdTime.AddMinutes(timeoutMinutes); + var isTimeout = currentTime > timeoutTime; + + if (isTimeout) + { + UpdateAlarmItemStatus(item, currentTime); + batchUpdateList.Add(item); + + var processRecord = CreateAlarmProcessRecord(item, currentTime); + allProcessRecords.Add(processRecord); + } + } + + if (batchUpdateList.Any()) + { + UpdateAndonAlarmRecordBatch(batchUpdateList); + } + + Console.WriteLine($"批次 {batchIndex + 1}/{batchCount} 处理完成,本批更新 {batchUpdateList.Count} 条报警记录"); + } + catch (Exception batchEx) + { + Console.WriteLine($"批次 {batchIndex + 1} 处理失败:{batchEx.Message}"); + continue; + } + } + + if (allProcessRecords.Any()) + { + var processBatchCount = (int)Math.Ceiling((double)allProcessRecords.Count / BatchSize); + for (int pBatchIndex = 0; pBatchIndex < processBatchCount; pBatchIndex++) + { + var processBatch = allProcessRecords.Skip(pBatchIndex * BatchSize).Take(BatchSize).ToList(); + andonAlarmRecordProcessService.Insert(processBatch); + } + } + + // 报警给领导,手表 + return ApiResult.Success($"成功处理 {totalCount} 条报警记录,其中超时上报 {allProcessRecords.Count} 条"); + } + catch (Exception ex) + { + Console.WriteLine($"自动超时报警处理失败:{ex.ToString()}"); // 记录完整异常栈,便于排查 + return ApiResult.Error(500, "自动超时报警处理异常,请查看日志"); + } + } + + #region 辅助方法 + /// + /// 更新报警记录的超时状态 + /// + /// 报警记录 + /// 操作时间 + private void UpdateAlarmItemStatus(AndonAlarmRecord alarmItem, DateTime operateTime) + { + alarmItem.Status = "超时上报"; + alarmItem.UpdatedBy = "admin"; + alarmItem.UpdatedTime = operateTime; + } + + /// + /// 创建报警处理记录 + /// + /// 报警记录 + /// 操作时间 + /// 处理记录实体 + private AndonAlarmRecordProcess CreateAlarmProcessRecord(AndonAlarmRecord alarmItem, DateTime operateTime) + { + return new AndonAlarmRecordProcess + { + AlarmCode = alarmItem.AlarmCode, + Operate = "超时上报", + CreatedBy = "admin", + CreatedName = "admin", + CreatedTime = operateTime, + UpdatedBy = "admin", + UpdatedName = "admin", + UpdatedTime = operateTime + }; + } + + /// + /// 批量更新报警记录 + /// + /// 待更新的报警记录列表 + private void UpdateAndonAlarmRecordBatch(List alarmItems) + { + if (alarmItems == null || !alarmItems.Any()) return; + var alarmRepo = new BaseRepository(); + alarmRepo.Context.Updateable(alarmItems) + .UpdateColumns(t => new { t.Status, t.UpdatedBy, t.UpdatedTime }) + .ExecuteCommand(); + } + #endregion } } \ No newline at end of file diff --git a/ZR.Service/mes/andon/ScheduledBackgroundService.cs b/ZR.Service/mes/andon/ScheduledBackgroundService.cs index 92d6eff2..04c02d90 100644 --- a/ZR.Service/mes/andon/ScheduledBackgroundService.cs +++ b/ZR.Service/mes/andon/ScheduledBackgroundService.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using ZR.Service.mes.andon.Iservice; namespace ZR.Service.mes.andon { @@ -14,7 +15,7 @@ namespace ZR.Service.mes.andon { private readonly ILogger _logger; private readonly IServiceScopeFactory _scopeFactory; - private readonly TimeSpan _interval = TimeSpan.FromMinutes(5); + private readonly TimeSpan _interval = TimeSpan.FromMinutes(1); public ScheduledBackgroundService( ILogger logger, @@ -35,15 +36,16 @@ namespace ZR.Service.mes.andon { try { - _logger.LogInformation($"开始执行定时任务: {DateTime.Now:HH:mm:ss}"); - - //// 使用 Scope 获取 Scoped 服务 - //using (var scope = _scopeFactory.CreateScope()) - //{ - // var myService = scope.ServiceProvider.GetRequiredService(); - // await myService.ProcessDataAsync(); - //} - + _logger.LogInformation($"开始执行安灯超时上报定时任务: {DateTime.Now:HH:mm:ss}"); + // 核心:创建作用域,获取Scoped服务 + using (var scope = _scopeFactory.CreateScope()) + { + // 获取你的报警业务服务(Scoped生命周期) + var alarmService = scope.ServiceProvider.GetRequiredService(); + // 执行你的自动超时上报逻辑 + var result = alarmService.AlarmReportAuto(); + _logger.LogInformation($"定时任务执行完成,结果:{result.Msg}"); + } _logger.LogInformation($"定时任务完成"); } catch (Exception ex) @@ -52,9 +54,12 @@ namespace ZR.Service.mes.andon } // 等待指定间隔 - await Task.Delay(_interval, stoppingToken); + // Task.Delay增加取消令牌检查,避免任务卡住 + if (!stoppingToken.IsCancellationRequested) + { + await Task.Delay(_interval, stoppingToken); + } } - _logger.LogInformation("定时后台服务停止"); } }