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

1045 lines
39 KiB
C#
Raw Normal View History

using DotNetty.Common.Utilities;
using Jint;
using Jint.Native.Object;
2025-10-26 15:12:32 +08:00
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
2025-10-26 15:12:32 +08:00
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using Nito.AsyncEx;
2025-10-26 15:12:32 +08:00
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
2025-10-30 12:40:42 +08:00
using System.ComponentModel;
2025-10-26 15:12:32 +08:00
using System.Diagnostics;
using System.Dynamic;
2025-10-26 15:12:32 +08:00
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Numerics;
using System.Security.Cryptography;
2025-10-26 15:12:32 +08:00
using System.Text;
using System.Text.Json;
2025-10-26 15:12:32 +08:00
using System.Threading;
using System.Threading.Channels;
2025-10-26 15:12:32 +08:00
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;
2025-10-26 15:12:32 +08:00
namespace YunDa.Server.ISMSTcp.Services
{
//Web服务器设置
2025-10-26 15:12:32 +08:00
public class WebApiSettings
{
public int Port { get; set; }
}
//带执行状态的巡检计划结构体
2025-10-26 15:12:32 +08:00
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; }
2025-10-26 15:12:32 +08:00
//网关数据
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 PlanName { get; set; } = string.Empty;
public SecondaryCircuitInspectionResultSaveModel SaveModel { get; set; }
}
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返回的处理结果"
2025-10-26 15:12:32 +08:00
}
//二次回路巡检计划
public class SecondaryCircuitInspectionPlanService
{
private readonly bool _isDebug = false;
2025-10-26 15:12:32 +08:00
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();
2025-10-26 15:12:32 +08:00
private int _planCheckDay = 0;
private readonly Channel<SecondaryCircuitInspectionItemOutputEx> _singlePlanChannel; //巡检计划
private readonly Channel<SecondaryCircuitInspectionAiParamModel> _aiChannel; //Ai调用
//巡检事件
private Queue<SecondaryCircuitEventDrivenConfigOutput> _eventPlanList;
private readonly AsyncLock _eventPlanLock = new AsyncLock();
private bool _getEventPlanListOk = false;
2025-10-26 15:12:32 +08:00
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 = Channel.CreateUnbounded<SecondaryCircuitInspectionAiParamModel>();
_eventPlanList = new Queue<SecondaryCircuitEventDrivenConfigOutput>();
//var kk = webApiRequest.GetTeleSignalData("08de219e-3524-41db-8d7d-86b547bac16a");
2025-10-26 15:12:32 +08:00
StartAsync();
}
private async Task StartAsync()
{
//更新计划
_ = Task.Run(async () =>
{
while (true)
{//每30秒更新一下配置
await UpdatePlans();
await UpdateEventPlans();
2025-10-26 15:12:32 +08:00
await Task.Delay(30000);
}
});
//检测计划
2025-10-26 15:12:32 +08:00
_ = Task.Run(async () =>
{
while (true)
{//每10秒检测一下计划
2025-10-26 15:12:32 +08:00
if (_updatedPlanOk)
{
await CheckPlan();
await Task.Delay(10000);
2025-10-26 15:12:32 +08:00
}
else
{
await Task.Delay(10000);
}
}
});
//事件计划
_ = Task.Run(async () =>
{
while (true)
{
if (_getEventPlanListOk)
{
await CheckEventPlan();
}
else
{
await Task.Delay(10000);
}
}
});
//执行计划(两个线程同时执行)
int threadNumber = _isDebug ? 1 : 3;
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.Reader.ReadAllAsync())
{
// 让每个线程在执行之间有不同的节奏
await Task.Delay(rand.Next(0, 300));
await CallAiAndSave(item);
await Task.Delay(500);
}
});
}
2025-10-26 15:12:32 +08:00
await Task.CompletedTask;
}
//更新计划
private async Task UpdatePlans()
{
try
{
using (await _planLock.LockAsync())
2025-10-26 15:12:32 +08:00
{
var oldPlan = _planList.ToArray();
_planList.Clear();
int start = 0;
while (start < 1000)
2025-10-26 15:12:32 +08:00
{
var list = await _webApiRequest.GetSecondaryCircuitInspectionPlanListAsync(start);
if (list != null)
{
2025-10-26 15:12:32 +08:00
List<SecondaryCircuitInspectionPlanStateModel> planlist = new List<SecondaryCircuitInspectionPlanStateModel>();
2025-10-26 15:12:32 +08:00
foreach (var item in list)
{
planlist.Add(new SecondaryCircuitInspectionPlanStateModel() { Plan = item });
}
2025-10-26 15:12:32 +08:00
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;
}
2025-10-26 15:12:32 +08:00
_planList.Enqueue(item);
}
if (list.Count < 10)
2025-10-26 15:12:32 +08:00
{
break;
}
else
{
start += 10;
2025-10-26 15:12:32 +08:00
}
}
else
{
break;
}
2025-10-26 15:12:32 +08:00
}
//获取到绑定信息,可以更新全部状态了
if (_planList.Count > 0)
_updatedPlanOk = true;
2025-10-26 15:12:32 +08:00
}
2025-10-26 15:12:32 +08:00
}
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;
}
2025-10-26 15:12:32 +08:00
//检测计划,判断计划是否该执行
private async Task<bool> CheckPlan()
{
bool ret = false;
if (_planList == null)
return ret;
try
{
SecondaryCircuitInspectionPlanStateModel[] planList;
using (await _planLock.LockAsync())
2025-10-26 15:12:32 +08:00
{
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())
2025-10-26 15:12:32 +08:00
{
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;
2025-10-26 15:12:32 +08:00
}
ret = true;
2025-10-26 15:12:32 +08:00
}
}
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CheckPlan发生错误");
}
return ret;
}
//将需要执行的计划写到队列里
private async Task<bool> PushPlanToChannel(int triggerType, SecondaryCircuitInspectionPlanOutput plan)
2025-10-26 15:12:32 +08:00
{
try
{
bool ret = true;
foreach (var item in plan.InspectionItems)
{
string id = item.Id.ToString();
2025-10-26 15:12:32 +08:00
if(item.IsActive && !string.IsNullOrWhiteSpace(item.CalculationExpression) && !string.IsNullOrWhiteSpace(id))
{
//写到队列里,由队列控制执行频率
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(triggerType, item));
2025-10-26 15:12:32 +08:00
}
}
return ret;
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - ExecutePlan发生错误");
}
return false;
}
//执行计划
private async Task ExecutePlan(SecondaryCircuitInspectionItemOutputEx itemEx)
2025-10-26 15:12:32 +08:00
{
string func2 = "";
string data2 = "";
2025-10-26 15:12:32 +08:00
try
{
var item = itemEx.Item;
string id = item.Id.ToString();
if (!string.IsNullOrWhiteSpace(id))
2025-10-26 15:12:32 +08:00
{
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);
func2 = item.CalculationExpression;
ObjectInstance? saveObj = null;
var sw = Stopwatch.StartNew();
for (int i = 0; i < item.TimeWindowCount; i++)
{
var tasks = new List<Task>();
Task<List<ZzDataResultModel>>? t1 = null;
Task<List<ZzDataResultModel>>? t2 = null;
Task<List<DeviceDzData>>? t3 = null;
Task<List<InspectionResultData>>? t4 = null;
Task<List<ZzDataResultModel>>? t5 = null;
Task<List<ZzDataResultModel>>? t6 = null;
if (item.TelemetryConfigCount > 0)
{
t1 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 1);
tasks.Add(t1);
}
if (item.TelesignalConfigCount > 0)
{
t2 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 2);
tasks.Add(t2);
}
if (item.DeviceConfigCount > 0)
{
t3 = GetSourceDataAsync<List<DeviceDzData>>(id, 3);
tasks.Add(t3);
}
if (item.CameraPresetCount > 0)
{
t4 = GetSourceDataAsync<List<InspectionResultData>>(id, 4);
tasks.Add(t4);
}
if (item.GatewayConfigCount > 0)
{
t5 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 5);
tasks.Add(t5);
}
if (item.VariantConfigCount > 0)
{
t6 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 6);
tasks.Add(t6);
}
await Task.WhenAll(tasks);
if (t1 != null) jsData.StoreData.TelemetryData = await t1;
if (t2 != null) jsData.StoreData.TeleSignalData = await t2;
if (t3 != null) jsData.StoreData.SettingData = await t3;
if (t4 != null) jsData.StoreData.PresetData = await t4;
if (t5 != null) jsData.StoreData.GatewayData = await t5;
if (t6 != null) jsData.StoreData.VariantData = await t6;
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("'", "\\'")}')";
data2 = json;
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.PlanName = $"{itemEx.Item.Name} {itemEx.Item.Description}";
aiParamModel.SaveModel = saveData;
_aiChannel.Writer.WriteAsync(aiParamModel);
}
}
}
2025-10-26 15:12:32 +08:00
}
}
catch(Exception ex)
{
_logger.LogError(ex, $"SecondaryCircuitInspectionPlanService 执行巡检项失败:{itemEx.Item.Id.ToString()}");
2025-10-26 15:12:32 +08:00
}
}
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.SaveModel.Status}");
sb.AppendLine($"计算过程: {aiParamModel.SaveModel.CalculationProcess}");
sb.AppendLine($"巡检结果: {aiParamModel.SaveModel.InspectionResult}");
sb.AppendLine($"校验结果: {aiParamModel.SaveModel.VerificationResult}");
sb.AppendLine();
sb.AppendLine();
sb.AppendLine("请按以下格式生成排除建议直接建议内容每条建议前加序号如1、每条建议间加换行符");
2025-10-26 15:12:32 +08:00
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.SaveModel.Status}");
sb.AppendLine($"计算过程: {aiParamModel.SaveModel.CalculationProcess}");
sb.AppendLine($"巡检结果: {aiParamModel.SaveModel.InspectionResult}");
sb.AppendLine($"校验结果: {aiParamModel.SaveModel.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);
}
}
2025-10-26 15:12:32 +08:00
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);
2025-10-30 12:40:42 +08:00
//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));
2025-10-30 12:40:42 +08:00
}
}
}
}
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CheckEventPlan发生错误");
}
return ret;
2025-10-26 15:12:32 +08:00
}
2025-10-30 12:40:42 +08:00
////获取遥测数据
//public async Task<List<YCResultData>> CallYCByDataIdAsync(CallYCByDataIdRequest 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<YCResultData> list = jArray.ToObject<List<YCResultData>>();
// return list;
// }
// }
// }
// catch(Exception ex)
// {
// _logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CallYCByDataIdAsync发生错误");
// }
// return null;
//}
2025-10-26 15:12:32 +08:00
}
}