SOMS/src/YunDa.Server/YunDa.Server.ISMSTcp/Services/SecondaryCircuitInspectionPlanService.cs

1051 lines
40 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DotNetty.Common.Utilities;
using Jint;
using Jint.Native.Object;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Nito.AsyncEx;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using YunDa.Server.ISMSTcp.Domain;
using YunDa.Server.ISMSTcp.Interfaces;
using YunDa.Server.ISMSTcp.Models;
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection;
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Configurations;
using YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipment;
using YunDa.SOMS.Entities.DataMonitoring.SecondaryCircuitInspection;
using YunDa.Server.ISMSTcp.Helpers;
using Abp.AutoMapper;
namespace YunDa.Server.ISMSTcp.Services
{
//Web服务器设置
public class WebApiSettings
{
public int Port { get; set; }
}
//带执行状态的巡检计划结构体
public class SecondaryCircuitInspectionPlanStateModel
{
//执行时间
public DateTime ExecuteTime { get; set; } = DateTime.MinValue;
public SecondaryCircuitInspectionPlanOutput Plan { get; set; }
public SecondaryCircuitInspectionPlanStateModel()
{
Plan = new SecondaryCircuitInspectionPlanOutput();
}
}
public class SecondaryCircuitInspectionItemOutputEx
{
public int TriggerType { get; set; }
public SecondaryCircuitInspectionItemOutput Item { get; set; }
public SecondaryCircuitInspectionItemOutputEx(int triggerType, SecondaryCircuitInspectionItemOutput item)
{
TriggerType = triggerType;
Item = item;
}
}
public class DeviceDzData
{
public List<DzInfo> UserDz { get; set; }
public List<DzInfo> SysDz { get; set; }
public string DeviceName { get; set; } = string.Empty;
}
public class InspectionResultData
{
public string PresetName { get; set; } = string.Empty;
public int PresetCode { get; set; }
public string TimeStamp { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
}
public class SecondaryCircuitInspectionStoreDataModel
{
//遥测数据
public List<ZzDataResultModel> TelemetryData { get; set; }
//遥信数据
public List<ZzDataResultModel> TeleSignalData { get; set; }
//定值
public List<DeviceDzData> SettingData { get; set; }
//预置位
public List<InspectionResultData> PresetData { get; set; }
//虚点数据
public List<ZzDataResultModel> VariantData { get; set; }
//网关数据
public List<ZzDataResultModel> GatewayData { get; set; }
}
//巡检结果
public class SecondaryCircuitInspectionJsDataModel
{
public int TimeWindowSeconds { get; set; }
public int TimeWindowCount { get; set; }
public TimeWindowTypeEnum TimeWindowType { get; set; }
public SecondaryCircuitInspectionStoreDataModel StoreData { get; set; } = new SecondaryCircuitInspectionStoreDataModel();
public List<SecondaryCircuitInspectionTelemetryConfigOutput> TelemetryConfigs { get; set; }
public List<SecondaryCircuitInspectionTelesignalConfigOutput> TelesignalConfigs { get; set; }
public List<SecondaryCircuitInspectionCameraPresetOutput> CameraPresets { get; set; }
public List<SecondaryCircuitInspectionDeviceConfigOutput> DeviceConfigs { get; set; }
public List<SecondaryCircuitInspectionVariantOutput> VariantConfigs { get; set; }
public List<SecondaryCircuitInspectionGatewayOutput> GatewayConfigs { get; set; }
}
//巡检结果上传Model
public class SecondaryCircuitInspectionResultSaveModel
{
public string SecondaryCircuitInspectionItemId { get; set; } = string.Empty;
public string InspectionPlanId { get; set; } = string.Empty;
public string ExecutionTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
public long ExecutionDurationMs { get; set; }
public int TriggerType { get; set; } //1计划2事件
public string TriggerEventId { get; set; } = string.Empty;
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
public string CalculationProcess { get; set; } = string.Empty; //计算过程
public string VerificationResult { get; set; } = string.Empty; //校验结果
public SecondaryCircuitInspectionJsDataModel Data { get; set; }
public string Remark { get; set; } = string.Empty; //无用
}
//
public class SecondaryCircuitInspectionAiParamModel
{
public string InspectionResultId { get; set; } = string.Empty;
public string InspectionName { get; set; } = string.Empty;
public string InspectionDescription { get; set; } = string.Empty;
public string PlanName => string.Concat(InspectionName, " ", InspectionDescription);
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
public string CalculationProcess { get; set; } = string.Empty; //计算过程
public string VerificationResult { get; set; } = string.Empty; //校验结果
}
public class SecondaryCircuitInspectionAiSaveModel
{
public string InspectionResultId { get; set; } = string.Empty;
public string AiAnalysisResult { get; set; } = string.Empty; // "AI结果状态失败|成功",
public string ResultHandleDescription { get; set; } = string.Empty; //"AI返回的处理结果"
}
//二次回路巡检计划
public class SecondaryCircuitInspectionPlanService
{
private readonly bool _isDebug = false;
private readonly ILogger<SecondaryCircuitInspectionPlanService> _logger;
private readonly IApiEndpoints _apiEndpoints;
private readonly WebApiRequest _webApiRequest;
private readonly WebApiSettings _webApiSettings;
private bool _updatedPlanOk = false;
private Queue<SecondaryCircuitInspectionPlanStateModel> _planList;
private readonly AsyncLock _planLock = new AsyncLock();
private int _planCheckDay = 0;
private readonly Channel<SecondaryCircuitInspectionItemOutputEx> _singlePlanChannel; //巡检计划
private readonly ChannelEx<SecondaryCircuitInspectionAiParamModel, string> _aiChannel; //Ai调用
//巡检事件
private Queue<SecondaryCircuitEventDrivenConfigOutput> _eventPlanList;
private readonly AsyncLock _eventPlanLock = new AsyncLock();
private bool _getEventPlanListOk = false;
public SecondaryCircuitInspectionPlanService(
ILogger<SecondaryCircuitInspectionPlanService> logger,
IApiEndpoints apiEndpoints,
WebApiRequest webApiRequest,
IOptions<WebApiSettings> webApiOptions
)
{
_apiEndpoints = apiEndpoints ?? throw new ArgumentNullException(nameof(apiEndpoints));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_webApiRequest = webApiRequest ?? throw new ArgumentNullException(nameof(webApiRequest));
_webApiSettings = webApiOptions.Value;
_planList = new Queue<SecondaryCircuitInspectionPlanStateModel>();
_singlePlanChannel = Channel.CreateUnbounded<SecondaryCircuitInspectionItemOutputEx>();
_aiChannel = new ChannelEx<SecondaryCircuitInspectionAiParamModel, string>( item => item.InspectionResultId);
_eventPlanList = new Queue<SecondaryCircuitEventDrivenConfigOutput>();
//var kk = webApiRequest.GetTeleSignalData("08de219e-3524-41db-8d7d-86b547bac16a");
StartAsync();
}
private async Task StartAsync()
{
//更新计划
_ = Task.Run(async () =>
{
while (true)
{//每10分钟更新一下配置
await UpdatePlans();
await UpdateEventPlans();
//await CheckAiChannel();
await Task.Delay(TimeSpan.FromMinutes(10));
}
});
//检测计划
_ = Task.Run(async () =>
{
while (true)
{//每10秒检测一下计划
if (_updatedPlanOk)
{
await CheckPlan();
await Task.Delay(TimeSpan.FromSeconds(60));
}
else
{
await Task.Delay(TimeSpan.FromSeconds(60));
}
}
});
//事件计划
_ = Task.Run(async () =>
{
while (true)
{
if (_getEventPlanListOk)
{
await CheckEventPlan();
}
else
{
await Task.Delay(TimeSpan.FromSeconds(60));
}
}
});
//执行计划(两个线程同时执行)
int threadNumber = _isDebug ? 1 : 1;
for (int i = 0; i < threadNumber; ++i)
{
_ = Task.Run(async () => {
var rand = new Random(Guid.NewGuid().GetHashCode());
await foreach (var item in _singlePlanChannel.Reader.ReadAllAsync())
{
// 让每个线程在执行之间有不同的节奏
await Task.Delay(rand.Next(0, 300));
await ExecutePlan(item);
await Task.Delay(500);
}
});
}
//调用Ai获取诊断结果
for (int i = 0; i < threadNumber; ++i)
{
_ = Task.Run(async () => {
var rand = new Random(Guid.NewGuid().GetHashCode());
await foreach (var item in _aiChannel.ReadAllAsync())
{
// 让每个线程在执行之间有不同的节奏
await Task.Delay(rand.Next(0, 300));
await CallAiAndSave(item);
await Task.Delay(5000);
}
});
}
await Task.CompletedTask;
}
//更新计划
private async Task UpdatePlans()
{
try
{
using (await _planLock.LockAsync())
{
var oldPlan = _planList.ToArray();
_planList.Clear();
int start = 0;
while (start < 1000)
{
var list = await _webApiRequest.GetSecondaryCircuitInspectionPlanListAsync(start);
if (list != null)
{
List<SecondaryCircuitInspectionPlanStateModel> planlist = new List<SecondaryCircuitInspectionPlanStateModel>();
foreach (var item in list)
{
planlist.Add(new SecondaryCircuitInspectionPlanStateModel() { Plan = item });
}
foreach (var item in planlist)
{
var plan = oldPlan.FirstOrDefault(x => x.Plan.Id == item.Plan.Id && x.Plan.ScheduledTimeString == item.Plan.ScheduledTimeString);
if (plan != null)
{
item.ExecuteTime = plan.ExecuteTime;
}
_planList.Enqueue(item);
}
if (list.Count < 10)
{
break;
}
else
{
start += 10;
}
}
else
{
break;
}
}
//获取到绑定信息,可以更新全部状态了
if (_planList.Count > 0)
_updatedPlanOk = true;
}
}
catch (Exception ex)
{
_updatedPlanOk = false;
}
await Task.CompletedTask;
}
//更新事件计划
private async Task UpdateEventPlans()
{
try
{
using (await _eventPlanLock.LockAsync())
{
_eventPlanList.Clear();
int start = 0;
while (start < 1000)
{
var list = await _webApiRequest.GetCircuitEventDrivenConfigAsync(start);
if (list != null)
{
foreach (var item in list)
_eventPlanList.Enqueue(item);
if (list.Count < 10)
{
break;
}
else
{
start += 10;
}
}
else
{
break;
}
}
//获取到绑定信息,可以更新全部状态了
if (_eventPlanList.Count > 0)
_getEventPlanListOk = true;
}
}
catch (Exception ex)
{
_getEventPlanListOk = false;
}
await Task.CompletedTask;
}
//检测计划,判断计划是否该执行
private async Task<bool> CheckPlan()
{
bool ret = false;
if (_planList == null)
return ret;
try
{
SecondaryCircuitInspectionPlanStateModel[] planList;
using (await _planLock.LockAsync())
{
planList = _planList.ToArray();
}
DateTime now = DateTime.Now;
int week = DateTime.Now.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)DateTime.Now.DayOfWeek;
if (now.Day != _planCheckDay)
{//翻天,清空已执行标记
using (await _planLock.LockAsync())
{
foreach (var item in _planList)
item.ExecuteTime = DateTime.MinValue;
}
}
_planCheckDay = now.Day;
foreach (var item in planList)
{
if (item.ExecuteTime == DateTime.MinValue && item.Plan.IsActive)
{//当天未执行
if (now.Hour == item.Plan.ScheduledHour && now.Minute == item.Plan.ScheduledMinute)
{
if (item.Plan.ScheduledWeekDaysList.IndexOf(week) != -1)
{
await PushPlanToChannel(1, item.Plan);
using (await _planLock.LockAsync())
{
item.ExecuteTime = DateTime.Now;
}
ret = true;
}
}
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CheckPlan发生错误");
}
return ret;
}
//将需要执行的计划写到队列里
private async Task<bool> PushPlanToChannel(int triggerType, SecondaryCircuitInspectionPlanOutput plan)
{
try
{
bool ret = true;
foreach (var item in plan.InspectionItems)
{
string id = item.Id.ToString();
if(item.IsActive && !string.IsNullOrWhiteSpace(item.CalculationExpression) && !string.IsNullOrWhiteSpace(id))
{
//写到队列里,由队列控制执行频率
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(triggerType, item));
}
}
return ret;
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - ExecutePlan发生错误");
}
return false;
}
//执行计划
private async Task ExecutePlan(SecondaryCircuitInspectionItemOutputEx itemEx)
{
//string func2 = "";
//string data2 = "";
try
{
var item = itemEx.Item;
string id = item.Id.ToString();
if (!string.IsNullOrWhiteSpace(id))
{
SecondaryCircuitInspectionJsDataModel jsData = new SecondaryCircuitInspectionJsDataModel();
jsData.TimeWindowSeconds = item.TimeWindowSeconds;
jsData.TimeWindowCount = item.TimeWindowCount;
jsData.TimeWindowType = item.TimeWindowType;
jsData.TelemetryConfigs = item.TelemetryConfigs;
jsData.TelesignalConfigs = item.TelesignalConfigs;
jsData.CameraPresets = item.CameraPresets;
jsData.DeviceConfigs = item.DeviceConfigs;
jsData.VariantConfigs = item.VariantConfigs;
jsData.GatewayConfigs = item.GatewayConfigs;
var engine = new Jint.Engine();
engine.Execute(item.CalculationExpression);
ObjectInstance? saveObj = null;
var sw = Stopwatch.StartNew();
for (int i = 0; i < item.TimeWindowCount; i++)
{
List<ZzDataResultModel>? telemetryData = null;
List<ZzDataResultModel>? teleSignalData = null;
List<DeviceDzData>? settingData = null;
List<InspectionResultData>? presetData = null;
List<ZzDataResultModel>? gatewayData = null;
List<ZzDataResultModel>? variantData = null;
if (item.TelemetryConfigCount > 0)
{
telemetryData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 1);
}
if (item.TelesignalConfigCount > 0)
{
teleSignalData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 2);
}
if (item.DeviceConfigCount > 0)
{
settingData = await GetSourceDataAsync<List<DeviceDzData>>(id, 3);
}
if (item.CameraPresetCount > 0)
{
presetData = await GetSourceDataAsync<List<InspectionResultData>>(id, 4);
}
if (item.GatewayConfigCount > 0)
{
gatewayData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 5);
}
if (item.VariantConfigCount > 0)
{
variantData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 6);
}
jsData.StoreData.TelemetryData = telemetryData;
jsData.StoreData.TeleSignalData = teleSignalData;
jsData.StoreData.SettingData = settingData;
jsData.StoreData.PresetData = presetData;
jsData.StoreData.GatewayData = gatewayData;
jsData.StoreData.VariantData = variantData;
if (jsData.StoreData.TelemetryData == null && jsData.StoreData.TeleSignalData == null && jsData.StoreData.SettingData == null &&
jsData.StoreData.PresetData == null && jsData.StoreData.GatewayData == null && jsData.StoreData.VariantData == null)
{
continue;
}
var json = JsonConvert.SerializeObject(jsData,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
var js = $"JSON.parse('{json.Replace("'", "\\'")}')";
var jsObj = engine.Evaluate(js).ToObject();
var jsResult = engine.Invoke("calculate", jsObj).AsObject();
if (jsResult != null && jsResult.HasProperty("status"))
{
saveObj = jsResult;
var status = jsResult.Get("status").ToString();
if (status == "正常" || string.IsNullOrWhiteSpace(status))
{
break;
}
}
else
{
saveObj = null;
break;
}
}
sw.Stop();
//保存结果
if (saveObj != null)
{
SecondaryCircuitInspectionResultSaveModel saveData = new SecondaryCircuitInspectionResultSaveModel();
if(saveObj.HasProperty("status") && saveObj.HasProperty("inspectionResult") && saveObj.HasProperty("calculationProcess") && saveObj.HasProperty("verificationResult"))
{
saveData.SecondaryCircuitInspectionItemId = item.Id.ToString();
saveData.ExecutionDurationMs = sw.ElapsedMilliseconds;
saveData.TriggerType = itemEx.TriggerType;
if (saveData.TriggerType == 1)
saveData.InspectionPlanId = id;
else
saveData.TriggerEventId = id;
saveData.Status = saveObj.Get("status").ToString();
saveData.InspectionResult = saveObj.Get("inspectionResult").ToString();
saveData.CalculationProcess = saveObj.Get("calculationProcess").ToString();
saveData.VerificationResult = saveObj.Get("verificationResult").ToString();
saveData.Data = jsData;
var inspectionResultId = await _webApiRequest.SaveSecondaryCircuitInspectionPlanResultAsync(saveData);
//获取Ai诊断结果并保存不正常时才诊断
if (!string.IsNullOrWhiteSpace(inspectionResultId) && saveData.Status != "正常")
{
SecondaryCircuitInspectionAiParamModel aiParamModel = new SecondaryCircuitInspectionAiParamModel();
aiParamModel.InspectionResultId = inspectionResultId;
aiParamModel.InspectionName = item.Name;
aiParamModel.InspectionDescription = item.Description;
aiParamModel.Status = saveData.Status;
aiParamModel.InspectionResult = saveData.InspectionResult;
aiParamModel.CalculationProcess = saveData.CalculationProcess;
aiParamModel.VerificationResult = saveData.VerificationResult;
_aiChannel.WriteAsync(aiParamModel);
}
}
}
}
}
catch(Exception ex)
{
_logger.LogError(ex, $"SecondaryCircuitInspectionPlanService 执行巡检项失败:{itemEx.Item.Id.ToString()}");
}
}
//获取没有调用Ai接口或调用失败的巡检记录结果
private async Task CheckAiChannel()
{
if (!_aiChannel.HasItems)
{
var list = await _webApiRequest.GetFailedAiInspectionListAsync();
if (list != null)
{
foreach (var item in list)
await _aiChannel.WriteAsync(item);
}
}
}
private async Task CallAiAndSave(SecondaryCircuitInspectionAiParamModel aiParamModel)
{
try
{
var aiParam = new
{
user_message = GetAiParamString(aiParamModel),
history = new List<string[]>()
};
var aiResultRaw = await _webApiRequest.GetAIAnalysis(aiParam);
bool isSuccess = false;
if (!string.IsNullOrWhiteSpace(aiResultRaw))
{
string aiResult = ParseAiResult(aiResultRaw);
if (!string.IsNullOrWhiteSpace(aiResult))
{
SecondaryCircuitInspectionAiSaveModel data = new SecondaryCircuitInspectionAiSaveModel();
data.InspectionResultId = aiParamModel.InspectionResultId;
data.AiAnalysisResult = "成功";
data.ResultHandleDescription = aiResult;
await _webApiRequest.UpdateReportWithAIAnalysisAsync(data);
isSuccess = true;
}
}
if(!isSuccess)
{
SecondaryCircuitInspectionAiSaveModel data = new SecondaryCircuitInspectionAiSaveModel();
data.InspectionResultId = aiParamModel.InspectionResultId;
data.AiAnalysisResult = "失败";
data.ResultHandleDescription = "";
await _webApiRequest.UpdateReportWithAIAnalysisAsync(data);
}
}
catch(Exception ex)
{
_logger.LogError(ex, $"SecondaryCircuitInspectionPlanService CallAiAndSave出错");
}
}
private static string GetAiParamString(SecondaryCircuitInspectionAiParamModel aiParamModel)
{
var sb = new StringBuilder();
sb.AppendLine("你是一个电力系统专家,请根据以下变电站二次巡检结果数据生成故障排除建议:");
sb.AppendLine();
sb.AppendLine("检修的建议要避免停止变电所的正常运行,要以宽松的方式,检修工作必须遵循“安全第一、预防为主”的核心原则,实施全过程精益化管理");
sb.AppendLine("检修前,需制定详尽的计划与方案,确保人员资质合格、物资工具齐备,并严格执行工作票制度,实现安全隔离。​检修中,必须强化现场安全管控,设专人监护,并严格按标准工艺施工,做好关键数据记录与过程质检。​检修后,要严格执行试验验收程序,确保设备性能达标,彻底清理现场,并完善检修报告与设备台账,形成闭环管理");
sb.AppendLine("整个流程旨在通过规范化、标准化的作业,确保人身、设备与电网安全,提升设备可靠性,保障电力稳定供应");
sb.AppendLine(",减少思考过程");
sb.AppendLine();
// 巡检结果
sb.AppendLine($"巡检内容为:");
sb.AppendLine(aiParamModel.PlanName);
sb.AppendLine();
sb.AppendLine("巡检结果为:");
sb.AppendLine($"巡检状态: {aiParamModel.Status}");
sb.AppendLine($"计算过程: {aiParamModel.CalculationProcess}");
sb.AppendLine($"巡检结果: {aiParamModel.InspectionResult}");
sb.AppendLine($"校验结果: {aiParamModel.VerificationResult}");
sb.AppendLine();
sb.AppendLine();
sb.AppendLine("请按以下格式生成排除建议直接建议内容每条建议前加序号如1、每条建议间加换行符");
return sb.ToString();
}
private static string GetAiParamString2(SecondaryCircuitInspectionAiParamModel aiParamModel)
{
var sb = new StringBuilder();
sb.AppendLine("你是一个电力系统专家,请根据以下变电站二次巡检结果数据生成检修策略:");
sb.AppendLine();
sb.Append("检修的开始时间不得晚于当前时间 ")
.AppendLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
sb.AppendLine("检修的建议要避免停止变电所的正常运行,要以宽松的方式,检修工作必须遵循“安全第一、预防为主”的核心原则,实施全过程精益化管理");
sb.AppendLine("检修前,需制定详尽的计划与方案,确保人员资质合格、物资工具齐备,并严格执行工作票制度,实现安全隔离。​检修中,必须强化现场安全管控,设专人监护,并严格按标准工艺施工,做好关键数据记录与过程质检。​检修后,要严格执行试验验收程序,确保设备性能达标,彻底清理现场,并完善检修报告与设备台账,形成闭环管理");
sb.AppendLine("整个流程旨在通过规范化、标准化的作业,确保人身、设备与电网安全,提升设备可靠性,保障电力稳定供应");
sb.AppendLine(",减少思考过程");
sb.AppendLine();
// 巡检结果
sb.AppendLine("巡检结果为:");
sb.AppendLine($"巡检状态: {aiParamModel.Status}");
sb.AppendLine($"计算过程: {aiParamModel.CalculationProcess}");
sb.AppendLine($"巡检结果: {aiParamModel.InspectionResult}");
sb.AppendLine($"校验结果: {aiParamModel.VerificationResult}");
sb.AppendLine();
sb.AppendLine();
sb.AppendLine("请按以下JSON格式生成策略");
sb.AppendLine(@"{
""level"": ""紧急程度"",
""focusAreas"": [""重点检修区域1"", ""重点检修区域2""],
""steps"": [
{""duration"": ""时间"", ""content"": ""步骤描述""}
],
""resources"": [""资源需求1"", ""资源需求2""],
""schedule"": {
""startDate"": ""开始时间"",
""optimalWindow"": ""最佳窗口"",
""endDate"": ""结束时间""
},
""risks"": [
{""title"": ""风险标题"", ""severity"": ""风险等级"", ""mitigation"": ""缓解措施""}
]
}");
return sb.ToString();
}
private static string ParseAiResult(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
return string.Empty;
var result = new StringBuilder();
foreach (string line in raw.Split('\n'))
{
var trimmed = line.Trim();
if (string.IsNullOrWhiteSpace(trimmed))
continue;
try
{
using var doc = JsonDocument.Parse(trimmed);
var root = doc.RootElement;
if (root.TryGetProperty("type", out var typeProp) &&
typeProp.GetString() == "content" &&
root.TryGetProperty("content", out var contentProp))
{
result.Append(contentProp.GetString());
}
}
catch
{
// 跳过非 JSON 行
continue;
}
}
return result.ToString();
}
//获取计划数据
private async Task<T> GetSourceDataAsync<T>(string id, int type, int retryCount = 3)
{
object result = null;
for(int i = 0; i < retryCount; ++i)
{
switch (type)
{
case 1:
result = await _webApiRequest.GetTelemetryInfoData(id);
break;
case 2:
result = await _webApiRequest.GetTeleSignalData(id);
break;
case 3:
result = await _webApiRequest.GetDeviceDzData(id);
break;
case 4:
result = await _webApiRequest.GetInspectionResultData(id);
break;
case 5:
result = await _webApiRequest.GetGatewayInfoData(id);
break;
case 6:
result = await _webApiRequest.GetVirtualPointInfoData(id);
break;
default:
throw new ArgumentException("Invalid type");
}
if(result != null)
{
break;
}
else
{
await Task.Delay(200);
}
}
return (T)result;
}
//执行事件计划
private async Task<bool> CheckEventPlan()
{
bool ret = false;
if (_eventPlanList == null)
return ret;
try
{
SecondaryCircuitEventDrivenConfigOutput[] planList;
using (await _eventPlanLock.LockAsync())
{
planList = _eventPlanList.ToArray();
}
foreach (var item in planList)
{
await Task.Delay(item.DelayTriggerSeconds * 1000);
if (item.IsActive && item.SecondaryCircuitInspectionEventItems?.Count > 0 && !string.IsNullOrWhiteSpace(item.TriggerExpression))
{
string id = item.Id.ToString() ?? "";
if (!string.IsNullOrWhiteSpace(id))
{
var engine = new Jint.Engine();
SecondaryCircuitInspectionJsDataModel jsData = new SecondaryCircuitInspectionJsDataModel();
var tasks = new List<Task>();
Task<List<ZzDataResultModel>>? t1 = null;
Task<List<ZzDataResultModel>>? t2 = null;
if (item.TelemetryConfigs.Count > 0)
{
t1 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 1);
tasks.Add(t1);
}
if (item.TelesignalConfigs.Count > 0)
{
t2 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 2);
tasks.Add(t2);
}
await Task.WhenAll(tasks);
if (t1 != null) jsData.StoreData.TelemetryData = await t1;
if (t2 != null) jsData.StoreData.TeleSignalData = await t2;
engine.Execute(item.TriggerExpression);
bool canCheck = true;
if(!_isDebug)
{
canCheck = engine.Invoke("calculate", jsData).AsBoolean();
}
if(canCheck)
{
await Task.Delay(item.MandatoryWaitSeconds * 1000);
//CheckPlanFormIds(item.SecondaryCircuitInspectionEventItems);
//执行巡检
foreach(var planItem in item.SecondaryCircuitInspectionEventItems)
{
if (!string.IsNullOrWhiteSpace(planItem.CalculationExpression) && !string.IsNullOrWhiteSpace(planItem.Id.ToString()))
{
//写到队列里,由队列控制执行频率
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(2, planItem));
}
}
}
}
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CheckEventPlan发生错误");
}
return ret;
}
////获取遥测数据
//public async Task<List<ZzDataResultModel>> CallYCByDataIdAsync(ZzDataRequestModel request, CancellationToken cancellationToken = default)
//{
// try
// {
// using var httpClient = new HttpClient();
// string url = $"http://127.0.0.1:{_webApiSettings.Port}/api/CallYCByDataId";
// var response = await httpClient.PostAsJsonAsync(url, request);
// response.EnsureSuccessStatusCode();
// var result = await response.Content.ReadAsStringAsync();
// JObject obj = JObject.Parse(result);
// if (obj.ContainsKey("data"))
// {
// JArray jArray = obj.Value<JArray>("data");
// if (jArray != null)
// {
// List<ZzDataResultModel> list = jArray.ToObject<List<ZzDataResultModel>>();
// return list;
// }
// }
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CallYCByDataIdAsync发生错误");
// }
// return null;
//}
}
}