完成巡检结果的获取
This commit is contained in:
parent
b92ddc5c86
commit
4d4da8ac2b
@ -1095,7 +1095,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
};
|
||||
if (ids.Count>0)
|
||||
{
|
||||
var str = HttpHelper.HttpPostRequest<JObject>(url, obj);
|
||||
var str = HttpHelper.HttpPostRequestWithRetry<JObject>(url, obj);
|
||||
if (str!=null)
|
||||
{
|
||||
if (bool.Parse(str["success"].ToString()) == true)
|
||||
@ -1156,7 +1156,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, Audited]
|
||||
[HttpGet, DisableAuditing]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
public RequestResult<List<TeleSignalOutput>> GetTeleSignalData(Guid id)
|
||||
@ -1208,7 +1208,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
};
|
||||
if (ids.Count>0)
|
||||
{
|
||||
var str = HttpHelper.HttpPostRequest<JObject>(url, obj);
|
||||
var str = HttpHelper.HttpPostRequestWithRetry<JObject>(url, obj);
|
||||
if (str!=null)
|
||||
{
|
||||
if (bool.Parse(str["success"].ToString()) == true)
|
||||
@ -1311,7 +1311,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
var str = HttpHelper.HttpPostRequest<JObject>(url, obj);
|
||||
var str = HttpHelper.HttpPostRequestWithRetry<JObject>(url, obj);
|
||||
if (str != null)
|
||||
{
|
||||
if (bool.Parse(str["success"].ToString()) == true)
|
||||
@ -1358,7 +1358,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet, Audited]
|
||||
[HttpGet, DisableAuditing]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
public RequestResult<List<GatewayInfoOutput>> GetGatewayInfoData(Guid id)
|
||||
@ -1402,7 +1402,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
var str = HttpHelper.HttpPostRequest<JObject>(url, obj);
|
||||
var str = HttpHelper.HttpPostRequestWithRetry<JObject>(url, obj);
|
||||
if (str != null)
|
||||
{
|
||||
if (bool.Parse(str["success"].ToString()) == true)
|
||||
@ -1453,6 +1453,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
[HttpGet]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
[DisableAuditing]
|
||||
[UnitOfWork(isTransactional: false)]
|
||||
public async Task<RequestResult<List<DeviceDzInfoOutput>>> GetDeviceDzDataAsync(Guid id)
|
||||
{
|
||||
@ -1615,6 +1616,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
[HttpGet, Description("获取虚点信息选择框")]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
[DisableAuditing]
|
||||
public RequestResult<List<SelectModelOutput>> GetVariantForSelect()
|
||||
{
|
||||
RequestResult<List<SelectModelOutput>> rst = new RequestResult<List<SelectModelOutput>>();
|
||||
@ -1641,6 +1643,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
[HttpGet, Description("获取网关数据选择框")]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
[DisableAuditing]
|
||||
public RequestResult<List<SelectModelOutput>> GetGateWayForSelect()
|
||||
{
|
||||
RequestResult<List<SelectModelOutput>> rst = new RequestResult<List<SelectModelOutput>>();
|
||||
@ -1667,6 +1670,7 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
|
||||
[HttpGet, Description("获取基础网关数据")]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
[DisableAuditing]
|
||||
public RequestResult<List<GatewayInfoOutput>> GetGateWayBaseInfo()
|
||||
{
|
||||
RequestResult<List<GatewayInfoOutput>> rst = new RequestResult<List<GatewayInfoOutput>>();
|
||||
|
||||
@ -532,7 +532,7 @@ namespace YunDa.SOMS.Application.DataMonitoring
|
||||
.WhereIf(searchCondition.SearchCondition.Id.HasValue,
|
||||
t => t.Id == searchCondition.SearchCondition.Id).WhereIf(
|
||||
searchCondition.SearchCondition.EquipmentInfoId.HasValue,
|
||||
t => t.EquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId)
|
||||
t => t.EquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId|| t.PrimaryEquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId)
|
||||
.Join(equipTypeG, f => f.EquipmentTypeId, s => s.Id, (f, s) => f);
|
||||
datas = datas.OrderBy(t => t.EquipmentType.SeqNo).ThenBy(t => t.EquipmentInfo.SeqNo).ThenBy(t => t.DispatcherAddress);
|
||||
var rstDatas = datas.ToList().AsQueryable();
|
||||
@ -687,7 +687,7 @@ namespace YunDa.SOMS.Application.DataMonitoring
|
||||
.WhereIf(searchCondition.IsVirtualDevice.HasValue, m => m.IsVirtualDevice == searchCondition.IsVirtualDevice)
|
||||
.WhereIf(searchCondition.TransformerSubstationId.HasValue, m => m.TransformerSubstationId == searchCondition.TransformerSubstationId);
|
||||
|
||||
datas = datas.OrderBy(t => t.SeqNo);
|
||||
datas = datas.OrderBy(t => t.ismsbaseYCId);
|
||||
var dic = datas.AsEnumerable().GroupBy(t => t.EquipmentInfoId);
|
||||
var list = new List<TelemeteringConfiguration>();
|
||||
|
||||
|
||||
@ -381,7 +381,7 @@ namespace YunDa.SOMS.Application.DataMonitoring
|
||||
.WhereIf(searchCondition.SearchCondition.Id.HasValue,
|
||||
t => t.Id == searchCondition.SearchCondition.Id).WhereIf(
|
||||
searchCondition.SearchCondition.EquipmentInfoId.HasValue,
|
||||
t => t.EquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId)
|
||||
t => t.EquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId || t.PrimaryEquipmentInfoId == searchCondition.SearchCondition.EquipmentInfoId)
|
||||
.Join(equipTypeG, f => f.EquipmentTypeId, s => s.Id, (f, s) => f);
|
||||
|
||||
var rstDatas = datas.ToList().AsQueryable();
|
||||
@ -559,8 +559,7 @@ namespace YunDa.SOMS.Application.DataMonitoring
|
||||
.WhereIf(searchCondition.EquipmentInfoId.HasValue, m => m.EquipmentInfoId == searchCondition.EquipmentInfoId)
|
||||
.WhereIf(searchCondition.IsVirtualDevice.HasValue, m => m.IsVirtualDevice == searchCondition.IsVirtualDevice)
|
||||
.WhereIf(searchCondition.TransformerSubstationId.HasValue, m => m.TransformerSubstationId == searchCondition.TransformerSubstationId);
|
||||
datas = datas.OrderBy(t => t.EquipmentInfoId);
|
||||
datas = datas.OrderBy(t => t.SeqNo).ThenBy(t => t.InfoAddress);
|
||||
datas = datas.OrderBy(t => t.ismsbaseYXId).ThenBy(t => t.SeqNo);
|
||||
|
||||
rst.ResultData = datas.Select(m => new SelectModelOutput
|
||||
{
|
||||
|
||||
@ -13,6 +13,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -35,6 +37,8 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
[Description("网线管理服务")]
|
||||
public class NetworkCableAppService : SOMSAppServiceBase, INetworkCableAppService
|
||||
{
|
||||
private const string AI_API_URL = "http://192.168.81.25:8002/chat/ai";
|
||||
|
||||
private readonly IRepository<NetworkCable, Guid> _networkCableRepository;
|
||||
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
|
||||
private readonly IRepository<TelemeteringConfiguration, Guid> _telemeteringConfigurationRepository;
|
||||
@ -499,23 +503,51 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
};
|
||||
}
|
||||
|
||||
// 生成影响范围和处置意见
|
||||
var (impactScopeField, impactScopeDescription) = GenerateNetworkCableImpactScope(networkCable);
|
||||
var disposalAdvice = GenerateNetworkCableDisposalAdvice(networkCable);
|
||||
string responseData;
|
||||
|
||||
// 格式化响应数据
|
||||
var responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
// 尝试使用AI生成智能响应
|
||||
try
|
||||
{
|
||||
var prompt = BuildNetworkCableDisconnectionPrompt(networkCable);
|
||||
var aiResponse = await CallAiApiAsync(prompt, cancellationToken).ConfigureAwait(false);
|
||||
var aiContent = ParseAiStreamingResponse(aiResponse);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(aiContent))
|
||||
{
|
||||
responseData = aiContent;
|
||||
Log4Helper.Info(GetType(), $"成功使用AI生成网线断线响应,孪生体ID: {twinId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// AI返回空内容,使用静态生成方法
|
||||
Log4Helper.Warning(GetType(), $"AI返回空内容,使用静态生成方法,孪生体ID: {twinId}");
|
||||
var (impactScopeField, impactScopeDescription) = GenerateNetworkCableImpactScope(networkCable);
|
||||
var disposalAdvice = GenerateNetworkCableDisposalAdvice(networkCable);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
}
|
||||
catch (Exception aiEx)
|
||||
{
|
||||
// AI调用失败,使用静态生成方法作为后备
|
||||
Log4Helper.Warning(GetType(), $"AI API调用失败,使用静态生成方法,孪生体ID: {twinId}", aiEx);
|
||||
var (impactScopeField, impactScopeDescription) = GenerateNetworkCableImpactScope(networkCable);
|
||||
var disposalAdvice = GenerateNetworkCableDisposalAdvice(networkCable);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
|
||||
// 推送告警
|
||||
YounuoAlert alert = new YounuoAlert
|
||||
{
|
||||
LastOccurrence = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
Severity = 5,
|
||||
SourceAlertKey = "模拟光缆断线",
|
||||
SourceAlertKey = "模拟网线断线",
|
||||
Status = 1,
|
||||
SourceIdentifier = networkCable.P1DeviceNumber,
|
||||
Summary = "模拟光缆断线",
|
||||
Summary = "模拟网线断线",
|
||||
TwinID = twinId,
|
||||
};
|
||||
await _beijingYounuoApiAppService.PushYounuoAlertAsync(alert);
|
||||
|
||||
return new SimpleDisconnectionResponse
|
||||
{
|
||||
Code = 200,
|
||||
@ -717,6 +749,119 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
}
|
||||
}
|
||||
|
||||
#region AI Integration Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// 构建网线断线场景的AI提示词
|
||||
/// </summary>
|
||||
private string BuildNetworkCableDisconnectionPrompt(NetworkCable networkCable)
|
||||
{
|
||||
var prompt = new StringBuilder();
|
||||
prompt.AppendLine("请作为一名专业的电力系统运维专家,分析以下网线断线场景并提供详细的影响范围分析和处置建议。");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【断线信息】");
|
||||
prompt.AppendLine($"- 连接类型:网线");
|
||||
prompt.AppendLine($"- 孪生体ID:{networkCable.TwinId}");
|
||||
|
||||
if (!string.IsNullOrEmpty(networkCable.P1CabinetName))
|
||||
prompt.AppendLine($"- P1端屏柜:{networkCable.P1CabinetName}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P1DeviceName))
|
||||
prompt.AppendLine($"- P1端设备:{networkCable.P1DeviceName}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P1DeviceNumber))
|
||||
prompt.AppendLine($"- P1端设备编号:{networkCable.P1DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P1PortNumber))
|
||||
prompt.AppendLine($"- P1端端口:{networkCable.P1PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(networkCable.P2CabinetName))
|
||||
prompt.AppendLine($"- P2端屏柜:{networkCable.P2CabinetName}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P2DeviceName))
|
||||
prompt.AppendLine($"- P2端设备:{networkCable.P2DeviceName}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P2DeviceNumber))
|
||||
prompt.AppendLine($"- P2端设备编号:{networkCable.P2DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(networkCable.P2PortNumber))
|
||||
prompt.AppendLine($"- P2端端口:{networkCable.P2PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(networkCable.WiringDirection))
|
||||
prompt.AppendLine($"- 配线走向:{networkCable.WiringDirection}");
|
||||
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【要求】");
|
||||
prompt.AppendLine("请按照以下格式提供分析结果:");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("影响范围:");
|
||||
prompt.AppendLine("(请详细列出该网线断线可能影响的设备、系统和功能,每项单独一行)");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("处置意见:");
|
||||
prompt.AppendLine("(请提供具体的排查步骤和处置建议,按优先级排序,每项单独一行)");
|
||||
|
||||
return prompt.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用AI API获取分析结果
|
||||
/// </summary>
|
||||
private async Task<string> CallAiApiAsync(string userMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestData = new
|
||||
{
|
||||
user_message = userMessage,
|
||||
history = new List<object>()
|
||||
};
|
||||
|
||||
var jsonContent = JsonConvert.SerializeObject(requestData);
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
Log4Helper.Info(GetType(), $"调用AI API: {AI_API_URL}");
|
||||
|
||||
var response = await _httpClient.PostAsync(AI_API_URL, content, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
Log4Helper.Debug(GetType(), $"AI API原始响应长度: {responseText.Length} 字符");
|
||||
|
||||
return responseText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析AI流式响应,提取content内容
|
||||
/// </summary>
|
||||
private string ParseAiStreamingResponse(string rawResponse)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawResponse))
|
||||
return string.Empty;
|
||||
|
||||
var result = new StringBuilder();
|
||||
|
||||
foreach (string line in rawResponse.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();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -36,6 +38,8 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
[Description("光缆管理服务")]
|
||||
public class OpticalCableAppService : SOMSAppServiceBase, IOpticalCableAppService
|
||||
{
|
||||
private const string AI_API_URL = "http://192.168.81.25:8002/chat/ai";
|
||||
|
||||
private readonly IRepository<OpticalCable, Guid> _opticalCableRepository;
|
||||
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
|
||||
private readonly HttpClient _httpClient;
|
||||
@ -556,12 +560,39 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
};
|
||||
}
|
||||
|
||||
// 生成影响范围和处置意见
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalCableImpactScope(opticalCable);
|
||||
var disposalAdvice = GenerateOpticalCableDisposalAdvice(opticalCable);
|
||||
string responseData;
|
||||
|
||||
// 格式化响应数据
|
||||
var responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
// 尝试使用AI生成智能响应
|
||||
try
|
||||
{
|
||||
var prompt = BuildOpticalCableDisconnectionPrompt(opticalCable);
|
||||
var aiResponse = await CallAiApiAsync(prompt, cancellationToken).ConfigureAwait(false);
|
||||
var aiContent = ParseAiStreamingResponse(aiResponse);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(aiContent))
|
||||
{
|
||||
responseData = aiContent;
|
||||
Log4Helper.Info(GetType(), $"成功使用AI生成光缆断线响应,孪生体ID: {twinId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// AI返回空内容,使用静态生成方法
|
||||
Log4Helper.Warning(GetType(), $"AI返回空内容,使用静态生成方法,孪生体ID: {twinId}");
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalCableImpactScope(opticalCable);
|
||||
var disposalAdvice = GenerateOpticalCableDisposalAdvice(opticalCable);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
}
|
||||
catch (Exception aiEx)
|
||||
{
|
||||
// AI调用失败,使用静态生成方法作为后备
|
||||
Log4Helper.Warning(GetType(), $"AI API调用失败,使用静态生成方法,孪生体ID: {twinId}", aiEx);
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalCableImpactScope(opticalCable);
|
||||
var disposalAdvice = GenerateOpticalCableDisposalAdvice(opticalCable);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
|
||||
// 推送告警
|
||||
YounuoAlert alert = new YounuoAlert
|
||||
{
|
||||
LastOccurrence = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
@ -573,6 +604,7 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
TwinID = twinId,
|
||||
};
|
||||
await _beijingYounuoApiAppService.PushYounuoAlertAsync(alert);
|
||||
|
||||
return new SimpleDisconnectionResponse
|
||||
{
|
||||
Code = 200,
|
||||
@ -768,5 +800,117 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
return RequestResult<Guid>.CreateFailed($"未知错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#region AI Integration Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// 构建光缆断线场景的AI提示词
|
||||
/// </summary>
|
||||
private string BuildOpticalCableDisconnectionPrompt(OpticalCable opticalCable)
|
||||
{
|
||||
var prompt = new StringBuilder();
|
||||
prompt.AppendLine("请作为一名专业的电力系统运维专家,分析以下光缆断线场景并提供详细的影响范围分析和处置建议。");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【断线信息】");
|
||||
prompt.AppendLine($"- 连接类型:光缆");
|
||||
prompt.AppendLine($"- 孪生体ID:{opticalCable.TwinId}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalCable.P1CabinetName))
|
||||
prompt.AppendLine($"- P1端屏柜:{opticalCable.P1CabinetName}");
|
||||
if (!string.IsNullOrEmpty(opticalCable.P1DeviceNumber))
|
||||
prompt.AppendLine($"- P1端设备编号:{opticalCable.P1DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(opticalCable.P1PortNumber))
|
||||
prompt.AppendLine($"- P1端端口:{opticalCable.P1PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalCable.P2CabinetName))
|
||||
prompt.AppendLine($"- P2端屏柜:{opticalCable.P2CabinetName}");
|
||||
if (!string.IsNullOrEmpty(opticalCable.P2DeviceNumber))
|
||||
prompt.AppendLine($"- P2端设备编号:{opticalCable.P2DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(opticalCable.P2PortNumber))
|
||||
prompt.AppendLine($"- P2端端口:{opticalCable.P2PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalCable.CableNumber))
|
||||
prompt.AppendLine($"- 光缆编号:{opticalCable.CableNumber}");
|
||||
if (!string.IsNullOrEmpty(opticalCable.WiringDirection))
|
||||
prompt.AppendLine($"- 配线走向:{opticalCable.WiringDirection}");
|
||||
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【要求】");
|
||||
prompt.AppendLine("请按照以下格式提供分析结果:");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("影响范围:");
|
||||
prompt.AppendLine("(请详细列出该光缆断线可能影响的设备、系统和功能,每项单独一行)");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("处置意见:");
|
||||
prompt.AppendLine("(请提供具体的排查步骤和处置建议,按优先级排序,每项单独一行)");
|
||||
|
||||
return prompt.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用AI API获取分析结果
|
||||
/// </summary>
|
||||
private async Task<string> CallAiApiAsync(string userMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestData = new
|
||||
{
|
||||
user_message = userMessage,
|
||||
history = new List<object>()
|
||||
};
|
||||
|
||||
var jsonContent = JsonConvert.SerializeObject(requestData);
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
Log4Helper.Info(GetType(), $"调用AI API: {AI_API_URL}");
|
||||
|
||||
var response = await _httpClient.PostAsync(AI_API_URL, content, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
Log4Helper.Debug(GetType(), $"AI API原始响应长度: {responseText.Length} 字符");
|
||||
|
||||
return responseText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析AI流式响应,提取content内容
|
||||
/// </summary>
|
||||
private string ParseAiStreamingResponse(string rawResponse)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawResponse))
|
||||
return string.Empty;
|
||||
|
||||
var result = new StringBuilder();
|
||||
|
||||
foreach (string line in rawResponse.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();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,8 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -36,6 +38,8 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
[Description("光纤管理服务")]
|
||||
public class OpticalFiberAppService : SOMSAppServiceBase, IOpticalFiberAppService
|
||||
{
|
||||
private const string AI_API_URL = "http://192.168.81.25:8002/chat/ai";
|
||||
|
||||
private readonly IRepository<OpticalFiber, Guid> _opticalFiberRepository;
|
||||
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
|
||||
private readonly HttpClient _httpClient;
|
||||
@ -562,12 +566,39 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
};
|
||||
}
|
||||
|
||||
// 生成影响范围和处置意见
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalFiberImpactScope(opticalFiber);
|
||||
var disposalAdvice = GenerateOpticalFiberDisposalAdvice(opticalFiber);
|
||||
string responseData;
|
||||
|
||||
// 格式化响应数据
|
||||
var responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
// 尝试使用AI生成智能响应
|
||||
try
|
||||
{
|
||||
var prompt = BuildOpticalFiberDisconnectionPrompt(opticalFiber);
|
||||
var aiResponse = await CallAiApiAsync(prompt, cancellationToken).ConfigureAwait(false);
|
||||
var aiContent = ParseAiStreamingResponse(aiResponse);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(aiContent))
|
||||
{
|
||||
responseData = aiContent;
|
||||
Log4Helper.Info(GetType(), $"成功使用AI生成光纤断线响应,孪生体ID: {twinId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// AI返回空内容,使用静态生成方法
|
||||
Log4Helper.Warning(GetType(), $"AI返回空内容,使用静态生成方法,孪生体ID: {twinId}");
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalFiberImpactScope(opticalFiber);
|
||||
var disposalAdvice = GenerateOpticalFiberDisposalAdvice(opticalFiber);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
}
|
||||
catch (Exception aiEx)
|
||||
{
|
||||
// AI调用失败,使用静态生成方法作为后备
|
||||
Log4Helper.Warning(GetType(), $"AI API调用失败,使用静态生成方法,孪生体ID: {twinId}", aiEx);
|
||||
var (impactScopeField, impactScopeDescription) = GenerateOpticalFiberImpactScope(opticalFiber);
|
||||
var disposalAdvice = GenerateOpticalFiberDisposalAdvice(opticalFiber);
|
||||
responseData = $"影响范围:\n{impactScopeDescription}\n{disposalAdvice}";
|
||||
}
|
||||
|
||||
// 推送告警
|
||||
YounuoAlert alert = new YounuoAlert
|
||||
{
|
||||
LastOccurrence = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
@ -579,6 +610,7 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
TwinID = twinId,
|
||||
};
|
||||
await _beijingYounuoApiAppService.PushYounuoAlertAsync(alert);
|
||||
|
||||
return new SimpleDisconnectionResponse
|
||||
{
|
||||
Code = 200,
|
||||
@ -774,5 +806,117 @@ namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||||
return RequestResult<Guid>.CreateFailed($"未知错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#region AI Integration Helper Methods
|
||||
|
||||
/// <summary>
|
||||
/// 构建光纤断线场景的AI提示词
|
||||
/// </summary>
|
||||
private string BuildOpticalFiberDisconnectionPrompt(OpticalFiber opticalFiber)
|
||||
{
|
||||
var prompt = new StringBuilder();
|
||||
prompt.AppendLine("请作为一名专业的电力系统运维专家,分析以下光纤断线场景并提供详细的影响范围分析和处置建议。");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【断线信息】");
|
||||
prompt.AppendLine($"- 连接类型:光纤");
|
||||
prompt.AppendLine($"- 孪生体ID:{opticalFiber.TwinId}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P1CabinetName))
|
||||
prompt.AppendLine($"- P1端屏柜:{opticalFiber.P1CabinetName}");
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P1DeviceNumber))
|
||||
prompt.AppendLine($"- P1端设备编号:{opticalFiber.P1DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P1PortNumber))
|
||||
prompt.AppendLine($"- P1端端口:{opticalFiber.P1PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P2CabinetName))
|
||||
prompt.AppendLine($"- P2端屏柜:{opticalFiber.P2CabinetName}");
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P2DeviceNumber))
|
||||
prompt.AppendLine($"- P2端设备编号:{opticalFiber.P2DeviceNumber}");
|
||||
if (!string.IsNullOrEmpty(opticalFiber.P2PortNumber))
|
||||
prompt.AppendLine($"- P2端端口:{opticalFiber.P2PortNumber}");
|
||||
|
||||
if (!string.IsNullOrEmpty(opticalFiber.VirtualPointCode))
|
||||
prompt.AppendLine($"- 虚拟点位代码:{opticalFiber.VirtualPointCode}");
|
||||
if (!string.IsNullOrEmpty(opticalFiber.WiringDirection))
|
||||
prompt.AppendLine($"- 配线走向:{opticalFiber.WiringDirection}");
|
||||
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("【要求】");
|
||||
prompt.AppendLine("请按照以下格式提供分析结果:");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("影响范围:");
|
||||
prompt.AppendLine("(请详细列出该光纤断线可能影响的设备、系统和功能,每项单独一行)");
|
||||
prompt.AppendLine();
|
||||
prompt.AppendLine("处置意见:");
|
||||
prompt.AppendLine("(请提供具体的排查步骤和处置建议,按优先级排序,每项单独一行)");
|
||||
|
||||
return prompt.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调用AI API获取分析结果
|
||||
/// </summary>
|
||||
private async Task<string> CallAiApiAsync(string userMessage, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestData = new
|
||||
{
|
||||
user_message = userMessage,
|
||||
history = new List<object>()
|
||||
};
|
||||
|
||||
var jsonContent = JsonConvert.SerializeObject(requestData);
|
||||
var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
|
||||
|
||||
Log4Helper.Info(GetType(), $"调用AI API: {AI_API_URL}");
|
||||
|
||||
var response = await _httpClient.PostAsync(AI_API_URL, content, cancellationToken).ConfigureAwait(false);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
Log4Helper.Debug(GetType(), $"AI API原始响应长度: {responseText.Length} 字符");
|
||||
|
||||
return responseText;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析AI流式响应,提取content内容
|
||||
/// </summary>
|
||||
private string ParseAiStreamingResponse(string rawResponse)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(rawResponse))
|
||||
return string.Empty;
|
||||
|
||||
var result = new StringBuilder();
|
||||
|
||||
foreach (string line in rawResponse.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();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,13 +419,12 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var scopedRepository = scope.ServiceProvider.GetRequiredService<IRepository<TelemeteringConfiguration, Guid>>();
|
||||
|
||||
using var unitOfWork = scopedUnitOfWorkManager.Begin();
|
||||
foreach (var config in batch)
|
||||
{
|
||||
scopedRepository.Update(config);
|
||||
updateCount++;
|
||||
}
|
||||
|
||||
// 使用 UpdateRange 进行真正的批量更新操作
|
||||
scopedRepository.GetDbContext().UpdateRange(batch);
|
||||
await unitOfWork.CompleteAsync();
|
||||
|
||||
updateCount += batch.Length;
|
||||
}
|
||||
|
||||
return updateCount;
|
||||
@ -455,13 +454,11 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
|
||||
using var unitOfWork = scopedUnitOfWorkManager.Begin();
|
||||
|
||||
foreach (var config in batch)
|
||||
{
|
||||
scopedRepository.Update(config);
|
||||
updateCount++;
|
||||
}
|
||||
|
||||
// 使用 UpdateRange 进行真正的批量更新操作
|
||||
scopedRepository.GetDbContext().UpdateRange(batch);
|
||||
await unitOfWork.CompleteAsync();
|
||||
|
||||
updateCount += batch.Length;
|
||||
}
|
||||
|
||||
return updateCount;
|
||||
@ -672,24 +669,6 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
try
|
||||
{
|
||||
using var unitOfWork = _unitOfWorkManager.Begin();
|
||||
|
||||
// 串行获取基础数据,避免 DbContext 并发访问
|
||||
Log4Helper.Info(GetType(), "开始获取设备数据...");
|
||||
var deviceDataList = await _imDeviceDatumRepository
|
||||
.GetAllIncluding(t => t.Device)
|
||||
.Where(d => d.DataName != "预留") // 提前过滤预留数据
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取遥信数据...");
|
||||
var imDeviceYxList = await _imDeviceYxRepository.GetAll().ToListAsync(cancellationToken);
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取告警分类数据...");
|
||||
var dmAlarmCategoriesList = await _dmalarmCategoryRepository.GetAll().ToListAsync(cancellationToken);
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取设备信息数据...");
|
||||
var equipmentsList = await _equipmentInfoRepository.GetAll().ToListAsync(cancellationToken);
|
||||
|
||||
// 根据过滤条件获取保护装置信息
|
||||
Log4Helper.Info(GetType(), "开始获取保护装置数据...");
|
||||
var protectionDevicesQuery = _protectionDeviceInfoRepository.GetAll();
|
||||
@ -698,17 +677,46 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
protectionDevicesQuery = protectionDevicesQuery.Where(p => protectionDeviceIds.Contains(p.Id));
|
||||
}
|
||||
var protectionDevicesList = await protectionDevicesQuery.ToListAsync(cancellationToken);
|
||||
var protectionDeviceAddrList = protectionDevicesList.Select(t => t.ISMS_DeviceId);
|
||||
var protectionDeviceEquipmentInfoIdList = protectionDevicesList.Select(t => t.EquipmentInfoId);
|
||||
// 串行获取基础数据,避免 DbContext 并发访问
|
||||
Log4Helper.Info(GetType(), "开始获取设备数据...");
|
||||
var deviceDataList = await _imDeviceDatumRepository
|
||||
.GetAllIncluding(t => t.Device)
|
||||
.Where(t=> protectionDeviceAddrList.Contains(t.DeviceId))
|
||||
.Where(d => d.DataName != "预留"|| d.DataName != "未用") // 提前过滤预留数据
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取遥信数据...");
|
||||
var imDeviceYxList = await _imDeviceYxRepository.GetAll()
|
||||
.ToListAsync(cancellationToken);
|
||||
//imDeviceYxList = imDeviceYxList.Where(t=>)
|
||||
imDeviceYxList = imDeviceYxList
|
||||
.Where(device => protectionDeviceAddrList.Any(addr => device.Id.Contains(addr)))
|
||||
.ToList();
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取告警分类数据...");
|
||||
var dmAlarmCategoriesList = await _dmalarmCategoryRepository.GetAll().ToListAsync(cancellationToken);
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取设备信息数据...");
|
||||
var equipmentsList = await _equipmentInfoRepository.GetAll().ToListAsync(cancellationToken);
|
||||
|
||||
|
||||
// 获取配置数据
|
||||
Log4Helper.Info(GetType(), "开始获取遥测配置数据...");
|
||||
var telemeteringConfigsList = await _telemeteringConfigurationRepository.GetAll()
|
||||
var telemeteringConfigsList = _telemeteringConfigurationRepository.GetAll()
|
||||
.Where(t => t.EquipmentInfoId.HasValue)
|
||||
.ToListAsync(cancellationToken);
|
||||
.AsEnumerable()
|
||||
.Where(t => protectionDeviceEquipmentInfoIdList.Any(x=>x==t.EquipmentInfoId))
|
||||
.ToList();
|
||||
|
||||
Log4Helper.Info(GetType(), "开始获取遥信配置数据...");
|
||||
var telesignalisationConfigsList = await _telesignalisationConfigurationRepository.GetAll()
|
||||
var telesignalisationConfigsList = _telesignalisationConfigurationRepository.GetAll()
|
||||
.Where(t => t.EquipmentInfoId.HasValue)
|
||||
.ToListAsync(cancellationToken);
|
||||
.AsEnumerable()
|
||||
.Where(t => protectionDeviceEquipmentInfoIdList.Any(x => x == t.EquipmentInfoId))
|
||||
.ToList();
|
||||
|
||||
// 构建字典(并行处理,安全因为操作的是内存数据)
|
||||
Log4Helper.Info(GetType(), "开始构建数据字典...");
|
||||
|
||||
@ -421,7 +421,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
else
|
||||
{
|
||||
var datas = telemeterings
|
||||
.Where(t => t.EquipmentInfoId == equipmentId && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => (t.EquipmentInfoId == equipmentId || t.PrimaryEquipmentInfoId == equipmentId))
|
||||
.Where(t => t.Name != "未用" || !t.Name.Contains("预留"))
|
||||
.OrderBy(t => t.DispatcherAddress)
|
||||
.ToList();
|
||||
@ -471,7 +471,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
else
|
||||
{
|
||||
var datas = telemeterings
|
||||
.Where(t => t.EquipmentInfoId == equipmentId && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => (t.EquipmentInfoId == equipmentId || t.PrimaryEquipmentInfoId == equipmentId) && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => t.Name != "未用" || !t.Name.Contains("预留"))
|
||||
.OrderBy(t => t.DispatcherAddress)
|
||||
.ToList();
|
||||
@ -1283,7 +1283,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
if (telemeterings != null && telemeterings.Count > 0)
|
||||
{
|
||||
var equipmentTelemeterings = telemeterings
|
||||
.Where(t => t.EquipmentInfoId == equipmentId && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t =>( t.EquipmentInfoId == equipmentId||t.PrimaryEquipmentInfoId == equipmentId) && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => t.Name != "未用" && !t.Name.Contains("预留"))
|
||||
.ToList();
|
||||
|
||||
@ -1311,7 +1311,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
if (telesignalisations != null && telesignalisations.Count > 0)
|
||||
{
|
||||
var equipmentTelesignalisations = telesignalisations
|
||||
.Where(t => t.EquipmentInfoId == equipmentId && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => (t.EquipmentInfoId == equipmentId||t.PrimaryEquipmentInfoId==equipmentId) && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => t.Name != "未用" && !t.Name.Contains("预留"))
|
||||
.ToList();
|
||||
|
||||
@ -1386,7 +1386,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
if (telemeterings != null && telemeterings.Count > 0)
|
||||
{
|
||||
var equipmentTelemeterings = telemeterings
|
||||
.Where(t => t.EquipmentInfoId == equipmentId && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => (t.EquipmentInfoId == equipmentId || t.PrimaryEquipmentInfoId == equipmentId) && t.DataSourceCategory == (DataSourceCategoryEnum)dataSourceCategory)
|
||||
.Where(t => t.Name != "未用" && !t.Name.Contains("预留"))
|
||||
.Where(t => t.AlarmLevel > 0 && t.AlarmLevel != ConstantModel.DegaultValue)
|
||||
.ToList();
|
||||
@ -1468,7 +1468,8 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var zxjckey = _telemeteringModelListRediskey + "ZXJC";
|
||||
var zxjcdatas = await _telemeteringModelListRedis.HashSetGetAllAsync(zxjckey);
|
||||
|
||||
datas.AddRange(zzdatas.Where(t=>t.EquipmentInfoId == equipementInfo.Id));
|
||||
datas.AddRange(zzdatas.Where(t=>t.EquipmentInfoId == equipementInfo.Id
|
||||
||t.PrimaryEquipmentInfoId == equipementInfo.Id));
|
||||
datas.AddRange(zxjcdatas.Where(t => t.EquipmentInfoId == equipementInfo.Id));
|
||||
rst.ResultData = datas;
|
||||
rst.Flag = true;
|
||||
@ -1482,7 +1483,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据设备名称获取遥测
|
||||
/// 根据设备名称获取遥信
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
@ -1504,7 +1505,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var zxjckey = _telesignalisationModelListRediskey + "ZXJC";
|
||||
var zxjcdatas = await _telesignalisationModelListRedis.HashSetGetAllAsync(zxjckey);
|
||||
|
||||
datas.AddRange(zzdatas.Where(t => t.EquipmentInfoId == equipementInfo.Id));
|
||||
datas.AddRange(zzdatas.Where(t => t.EquipmentInfoId == equipementInfo.Id||t.PrimaryEquipmentInfoId == equipementInfo.Id));
|
||||
datas.AddRange(zxjcdatas.Where(t => t.EquipmentInfoId == equipementInfo.Id));
|
||||
rst.ResultData = datas;
|
||||
rst.Flag = true;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using Abp.Auditing;
|
||||
using Abp.Domain.Repositories;
|
||||
using Abp.Domain.Uow;
|
||||
using Abp.EntityFrameworkCore;
|
||||
using Abp.Web.Mvc.Alerts;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using iText.Layout.Element;
|
||||
@ -32,6 +33,7 @@ using YunDa.SOMS.Application.Core.Auditing;
|
||||
using YunDa.SOMS.Application.Core.Configuration;
|
||||
using YunDa.SOMS.Application.Core.Session;
|
||||
using YunDa.SOMS.Application.Core.SwaggerHelper;
|
||||
using YunDa.SOMS.BASE.Entities;
|
||||
using YunDa.SOMS.BASE.Entities.Models;
|
||||
using YunDa.SOMS.DataTransferObject;
|
||||
using YunDa.SOMS.DataTransferObject.GeneralInformation.ProtectionDeviceInfoDto;
|
||||
@ -56,6 +58,10 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
private readonly IRedisRepository<object, string> _redisRepository;
|
||||
private readonly IRepository<ProtectionDeviceInfo, Guid> _protectionDeviceInfoRepository;
|
||||
private readonly IRepository<ImProtectDevice,string> _imProtectDevice;
|
||||
private readonly IRepository<ImDeviceDz, string> _imDeviceDzDevice;
|
||||
private readonly IRepository<ImDztype, int> _imDztypeDevice;
|
||||
private readonly IDbContextProvider<ISMS_BASEContext> _imDeviceDzenumProvider;
|
||||
|
||||
private readonly SOMSAuditingStore _SOMSAuditingStore;
|
||||
private string _ISMSGateWayIp = "http://127.0.0.1:38094";
|
||||
private string _ISMSftpIp = "192.168.65.33";
|
||||
@ -69,6 +75,9 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
, IRepository<ImProtectDevice, string> imProtectDevice
|
||||
, SOMSAuditingStore SOMSAuditingStore
|
||||
, IRepository<ProtectionDeviceInfo, Guid> protectionDeviceInfoRepository
|
||||
, IRepository<ImDeviceDz, string> imDeviceDzDevice
|
||||
, IRepository<ImDztype, int> imDztypeDevice
|
||||
, IDbContextProvider<ISMS_BASEContext> imDeviceDzenumProvider
|
||||
) : base(sessionAppService)
|
||||
{
|
||||
_ISMSftpIp = appServiceConfiguration.ISMSFtpIp;
|
||||
@ -82,6 +91,9 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
_protectionDeviceInfoRepository = protectionDeviceInfoRepository;
|
||||
_imProtectDevice = imProtectDevice;
|
||||
_SOMSAuditingStore = SOMSAuditingStore;
|
||||
_imDeviceDzDevice = imDeviceDzDevice;
|
||||
_imDztypeDevice = imDztypeDevice;
|
||||
_imDeviceDzenumProvider = imDeviceDzenumProvider;
|
||||
}
|
||||
/// <summary>
|
||||
/// 转发定值行信息
|
||||
@ -91,7 +103,6 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
[HttpGet]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
[Audited]
|
||||
[Description("查询定值")]
|
||||
public async Task<RequestResult<List<DzInfo>>> GetDZInfoAsync(string dz)
|
||||
{
|
||||
@ -108,6 +119,8 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
List<string> strings = dz.Split('|').ToList();
|
||||
//CallDeviceDZ|B001|12|12|9|3|255
|
||||
int dzAddr = int.Parse( strings[3]);
|
||||
int dzCpuInex = int.Parse(strings[4]);
|
||||
|
||||
ImProtectDevice device = default;
|
||||
|
||||
using (var unitOfWork = _unitOfWorkManager.Begin())
|
||||
@ -126,62 +139,92 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
UserName = string.IsNullOrEmpty(base.GetCurrentUser()?.UserName) ? "匿名用户" : base.GetCurrentUser()?.UserName,
|
||||
ExecutionTime = DateTime.Now,
|
||||
});
|
||||
// 先从Redis缓存中获取数据
|
||||
|
||||
// 定义缓存键
|
||||
var cacheKey = "DZInfoHas";
|
||||
var cachedData = await _redisRepository.HashSetGetOneAsync(cacheKey, dz);
|
||||
List<DzInfo> dzList = null;
|
||||
bool dataFromDevice = false;
|
||||
|
||||
if (cachedData != null)
|
||||
{
|
||||
// 处理 JSON 反序列化场景
|
||||
var json = JsonConvert.SerializeObject(cachedData);
|
||||
var list = JsonConvert.DeserializeObject<List<DzInfo>>(json);
|
||||
rst.ResultData = list;
|
||||
rst.Flag = true;
|
||||
return rst;
|
||||
}
|
||||
|
||||
// 缓存中没有,从接口获取
|
||||
// 第一层:尝试从设备系统获取数据(主要数据源)
|
||||
Log4Helper.Info(this.GetType(), $"尝试从设备系统获取定值,命令:{dz}");
|
||||
string url = $"{_ISMSGateWayIp}/api";
|
||||
|
||||
// 端口连通性检测(1秒超时)
|
||||
if (!IsPortOpen(url, 5000))
|
||||
// 端口连通性检测
|
||||
if (IsPortOpen(url, 5000))
|
||||
{
|
||||
rst.Message = "目标服务不可访问,端口连接失败";
|
||||
Log4Helper.Warning(this.GetType(), $"端口连接失败,URL: {url}");
|
||||
return rst;
|
||||
try
|
||||
{
|
||||
var str = HttpHelper.HttpGetRequest<object>(url + $"?dz={dz}");
|
||||
JObject wrappedObject = JObject.Parse(str?.ToString());
|
||||
|
||||
if (wrappedObject != null)
|
||||
{
|
||||
var content = wrappedObject["content"];
|
||||
if (content != null)
|
||||
{
|
||||
dzList = JsonConvert.DeserializeObject<List<DzInfo>>(content.ToString());
|
||||
if (dzList != null && dzList.Count > 0)
|
||||
{
|
||||
dataFromDevice = true;
|
||||
Log4Helper.Info(this.GetType(), $"成功从设备系统获取定值,数量:{dzList.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Warning(this.GetType(), $"从设备系统获取定值失败,将尝试从缓存获取: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4Helper.Warning(this.GetType(), $"设备系统端口连接失败,URL: {url},将尝试从缓存获取");
|
||||
}
|
||||
|
||||
var str = HttpHelper.HttpGetRequest<object>(url + $"?dz={dz}");
|
||||
JObject wrappedObject = JObject.Parse(str?.ToString());
|
||||
if (wrappedObject!=null)
|
||||
// 第二层:如果设备系统获取失败,从Redis缓存获取(备用数据源)
|
||||
if (dzList == null || dzList.Count == 0)
|
||||
{
|
||||
var content = wrappedObject["content"];
|
||||
if (content != null)
|
||||
{
|
||||
var dzList = JsonConvert.DeserializeObject<List<DzInfo>>(content.ToString());
|
||||
int zoneNo = int.Parse( dzList[0].ZoneNo.ToString());
|
||||
Log4Helper.Info(this.GetType(), $"尝试从Redis缓存获取定值,命令:{dz}");
|
||||
var cachedData = await _redisRepository.HashSetGetOneAsync(cacheKey, dz);
|
||||
|
||||
if (dzList!=null)
|
||||
if (cachedData != null)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(cachedData);
|
||||
dzList = JsonConvert.DeserializeObject<List<DzInfo>>(json);
|
||||
|
||||
if (dzList != null && dzList.Count > 0)
|
||||
{
|
||||
// 写入Redis缓存,设置一个月过期时间
|
||||
await _redisRepository.HashSetUpdateOneAsync(cacheKey, dz, dzList);
|
||||
await _redisRepository.KeyExpireAsync(cacheKey, TimeSpan.FromDays(30));
|
||||
rst.ResultData = dzList;
|
||||
rst.Flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rst.Message = "未获取到定值";
|
||||
Log4Helper.Info(this.GetType(), $"定值查询命令:{dz},未获取到定值");
|
||||
Log4Helper.Info(this.GetType(), $"成功从缓存获取定值,数量:{dzList.Count}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rst.Message = "未获取到定值";
|
||||
Log4Helper.Info(this.GetType(), $"定值查询命令:{dz},未获取到定值");
|
||||
Log4Helper.Warning(this.GetType(), $"缓存中未找到定值数据,命令:{dz}");
|
||||
}
|
||||
}
|
||||
|
||||
// 处理获取到的数据
|
||||
if (dzList != null && dzList.Count > 0)
|
||||
{
|
||||
// 处理枚举值替换
|
||||
ProcessEnumerationValues(dzList, device.Id, dzCpuInex);
|
||||
|
||||
// 如果数据来自设备系统,更新到Redis缓存(永久缓存,无过期时间)
|
||||
if (dataFromDevice)
|
||||
{
|
||||
await _redisRepository.HashSetUpdateOneAsync(cacheKey, dz, dzList);
|
||||
Log4Helper.Info(this.GetType(), $"已将设备系统数据缓存到Redis(永久缓存),命令:{dz}");
|
||||
}
|
||||
|
||||
rst.ResultData = dzList;
|
||||
rst.Flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rst.Message = "未获取到定值,设备系统和缓存均无数据";
|
||||
Log4Helper.Info(this.GetType(), $"定值查询失败,命令:{dz}");
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -192,6 +235,106 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
return rst;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理定值列表,将枚举类型的数值替换为中文描述
|
||||
/// </summary>
|
||||
/// <param name="dzList">定值信息列表</param>
|
||||
/// <param name="deviceId">保护装置ID</param>
|
||||
private void ProcessEnumerationValues(List<DzInfo> dzList, string deviceId, int dzCpuInex)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (dzList == null || !dzList.Any() || string.IsNullOrEmpty(deviceId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取该装置的所有定值配置
|
||||
List<ImDeviceDz> deviceDzList = null;
|
||||
using (var unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
deviceDzList = _imDeviceDzDevice.GetAll()
|
||||
.Where(d => d.DeviceId == deviceId)
|
||||
.Where(d=>d.CpuIndex == dzCpuInex)
|
||||
.ToList();
|
||||
unitOfWork.Complete();
|
||||
}
|
||||
|
||||
if (deviceDzList == null || !deviceDzList.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取所有需要的枚举类型ID
|
||||
var enumTypeIds = deviceDzList
|
||||
.Where(d => d.EnumTypeId.HasValue && d.EnumTypeId.Value > 0)
|
||||
.Select(d => d.EnumTypeId.Value)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
if (!enumTypeIds.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询所有相关的枚举定义
|
||||
Dictionary<int, List<ImDeviceDzenum>> enumDefinitions = new Dictionary<int, List<ImDeviceDzenum>>();
|
||||
using (var unitOfWork = _unitOfWorkManager.Begin())
|
||||
{
|
||||
var dbContext = _imDeviceDzenumProvider.GetDbContext();
|
||||
var allEnums = dbContext.Set<ImDeviceDzenum>()
|
||||
.Where(e => enumTypeIds.Contains(e.EnumTypeId))
|
||||
.ToList();
|
||||
|
||||
// 按EnumTypeId分组
|
||||
foreach (var enumTypeId in enumTypeIds)
|
||||
{
|
||||
enumDefinitions[enumTypeId] = allEnums
|
||||
.Where(e => e.EnumTypeId == enumTypeId)
|
||||
.ToList();
|
||||
}
|
||||
unitOfWork.Complete();
|
||||
}
|
||||
|
||||
// 处理每个定值信息
|
||||
foreach (var dzInfo in dzList)
|
||||
{
|
||||
|
||||
// 查找对应的定值配置(通过DzIndex匹配SeqNo)
|
||||
var deviceDz = deviceDzList.FirstOrDefault(d => d.DzComment == dzInfo.Name);
|
||||
if (deviceDz == null || !deviceDz.EnumTypeId.HasValue || deviceDz.EnumTypeId.Value <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 解析当前值为数字
|
||||
if (!int.TryParse(dzInfo.Value, out int enumIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 查找对应的枚举定义
|
||||
if (!enumDefinitions.ContainsKey(deviceDz.EnumTypeId.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var enumEntry = enumDefinitions[deviceDz.EnumTypeId.Value]
|
||||
.FirstOrDefault(e => e.EnumIndex == enumIndex);
|
||||
|
||||
if (enumEntry != null && !string.IsNullOrEmpty(enumEntry.EnumComment))
|
||||
{
|
||||
// 替换数值为中文描述
|
||||
dzInfo.Value = enumEntry.EnumComment;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Warning(this.GetType(), $"处理定值枚举值时发生错误: {ex.Message}", ex);
|
||||
// 不抛出异常,保持原有数据返回
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 根据设备id查询定值
|
||||
/// </summary>
|
||||
@ -231,11 +374,11 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
if (device!=null)
|
||||
{
|
||||
|
||||
string search = $"CallDeviceDZ|B001|{device.DeviceAddr}|{device.GateWay.PhyAddr}|9|3|{actualZoneNo}";
|
||||
string search = $"CallDeviceDZ|B001|{device.GateWay.PhyAddr}|{device.DeviceAddr}|9|3|{actualZoneNo}";
|
||||
var data1 = await GetDZInfoAsync(search);
|
||||
rst.ResultData.SysDz = data1.ResultData;
|
||||
|
||||
search = $"CallDeviceDZ|B001|{device.DeviceAddr}|{device.GateWay.PhyAddr}|1|3|{actualZoneNo}";
|
||||
search = $"CallDeviceDZ|B001|{device.GateWay.PhyAddr}|{device.DeviceAddr}|1|3|{actualZoneNo}";
|
||||
var data2 = await GetDZInfoAsync(search);
|
||||
rst.ResultData.UserDz = data2.ResultData;
|
||||
rst.ResultData.DeviceName = device.DeviceName;
|
||||
@ -277,7 +420,7 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
unitOfWork.Complete();
|
||||
}
|
||||
|
||||
if (cachedData != null)
|
||||
if (cachedData != null&&cachedData.Count>0)
|
||||
{
|
||||
foreach (var item in cachedData.Keys)
|
||||
{
|
||||
@ -325,7 +468,10 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
|
||||
rst.Flag = true;
|
||||
return rst;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,37 +1,39 @@
|
||||
using Abp.Application.Services;
|
||||
using Abp.Auditing;
|
||||
using Abp.Domain.Repositories;
|
||||
using Abp.EntityFrameworkCore.Repositories;
|
||||
using Abp.Linq.Extensions;
|
||||
using Abp.ObjectMapping;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YunDa.SOMS.DataTransferObject.GeneralInformation.TransformerSubstationDto;
|
||||
using ToolLibrary.LogHelper;
|
||||
using YunDa.SOMS.Application.Core;
|
||||
using YunDa.SOMS.Application.Core.Helper.PDFHelper;
|
||||
using YunDa.SOMS.Application.Core.OfficeHelper;
|
||||
using YunDa.SOMS.Application.Core.Session;
|
||||
using YunDa.SOMS.Application.Core.SwaggerHelper;
|
||||
using YunDa.SOMS.DataTransferObject;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelecommandConfigurationDto;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelemeteringConfigurationDto;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelesignalisationConfigurationDto;
|
||||
using YunDa.SOMS.DataTransferObject.GeneralInformation.EquipmentTypeDto;
|
||||
using YunDa.SOMS.DataTransferObject.GeneralInformation.TransformerSubstationDto;
|
||||
using YunDa.SOMS.Entities.DataMonitoring;
|
||||
using YunDa.SOMS.Entities.GeneralInformation;
|
||||
using YunDa.SOMS.Entities.MySQL.DataMonitoring;
|
||||
using YunDa.SOMS.Entities.VideoSurveillance;
|
||||
using YunDa.SOMS.DataTransferObject.GeneralInformation.EquipmentTypeDto;
|
||||
using System.Collections.Generic;
|
||||
using ToolLibrary.LogHelper;
|
||||
using YunDa.SOMS.Application.Core.SwaggerHelper;
|
||||
using YunDa.SOMS.Application.Core.Helper.PDFHelper;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using YunDa.SOMS.Application.Core.OfficeHelper;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelemeteringConfigurationDto;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelesignalisationConfigurationDto;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.TelecommandConfigurationDto;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Abp.ObjectMapping;
|
||||
using YunDa.SOMS.Application.Core;
|
||||
using YunDa.SOMS.Application.Core.Session;
|
||||
using Abp.Linq.Extensions;
|
||||
using static NetMQ.NetMQSelector;
|
||||
|
||||
namespace YunDa.SOMS.Application.GeneralInformation
|
||||
{
|
||||
@ -164,10 +166,11 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
ExcelHandler excelWrite = new DataConfigurationExcelHandle();
|
||||
try
|
||||
{
|
||||
var query = _telemeteringConfigurationRepository.GetAllIncluding(t => t.EquipmentType, t => t.TransformerSubstation, t => t.EquipmentInfo, t => t.PrimaryEquipmentInfo, t => t.PrimaryEquipmentInfo.EquipmentType)
|
||||
var query = _telemeteringConfigurationRepository.GetAllIncluding(t => t.TransformerSubstation, t => t.EquipmentInfo, t => t.PrimaryEquipmentInfo)
|
||||
.Where(t => t.IsActive && t.TransformerSubstationId == input.TransformerSubstationId)
|
||||
.WhereIf(input.DataSourceCategory.HasValue, t => t.DataSourceCategory == input.DataSourceCategory);
|
||||
|
||||
.WhereIf(input.DataSourceCategory.HasValue, t => t.DataSourceCategory == input.DataSourceCategory)
|
||||
.AsNoTracking();
|
||||
var equipmentTypes = _equipmentTypeRepository.GetAll().ToDictionary(t=>t.Id);
|
||||
// 根据 EquipmentInfoId 和 EquipmentTypeId 进行筛选
|
||||
if (input.EquipmentInfoId.HasValue)
|
||||
{
|
||||
@ -183,6 +186,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
|
||||
var telemeteringRepo = query.OrderBy(t => t.SeqNo).ToList();
|
||||
|
||||
|
||||
var telemeteringExcelList = ObjectMapper.Map<List<TelemeteringConfigurationExcel>>(telemeteringRepo);
|
||||
|
||||
// 设置Excel数据
|
||||
@ -202,14 +206,35 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
|
||||
foreach (var item in telemeteringExcelList)
|
||||
{
|
||||
var PrimaryEquipmentInfoTypeName = "";
|
||||
var EquipmentTypeName = "";
|
||||
|
||||
if (item.PrimaryEquipmentInfo!=null)
|
||||
{
|
||||
if (equipmentTypes.ContainsKey(item.PrimaryEquipmentInfo.EquipmentTypeId.Value))
|
||||
{
|
||||
var equipmentType = equipmentTypes[item.PrimaryEquipmentInfo.EquipmentTypeId.Value];
|
||||
PrimaryEquipmentInfoTypeName = equipmentType.Name;
|
||||
}
|
||||
|
||||
}
|
||||
if (item.EquipmentInfo != null)
|
||||
{
|
||||
if (equipmentTypes.ContainsKey(item.EquipmentInfo.EquipmentTypeId.Value))
|
||||
{
|
||||
var equipmentType = equipmentTypes[item.EquipmentInfo.EquipmentTypeId.Value];
|
||||
EquipmentTypeName = equipmentType.Name;
|
||||
}
|
||||
}
|
||||
|
||||
var row = new List<string>
|
||||
{
|
||||
item.Id?.ToString() ?? "",
|
||||
item.SeqNo.ToString(),
|
||||
item.EquipmentInfo?.Name ?? "",
|
||||
item.EquipmentType?.Name ?? "",
|
||||
EquipmentTypeName,
|
||||
item.PrimaryEquipmentInfo?.Name ?? "",
|
||||
item.PrimaryEquipmentInfoType?.Name ?? "",
|
||||
PrimaryEquipmentInfoTypeName,
|
||||
item.Name ?? "",
|
||||
item.InfoAddress.ToString(),
|
||||
item.InfoDeviceAddress.ToString(),
|
||||
@ -282,6 +307,10 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var equipmentRepo = _equipmentInfoRepository.GetAll().ToList();
|
||||
var equipmentTypeRepo = _equipmentTypeRepository.GetAll().ToList();
|
||||
|
||||
// 使用批量操作优化性能
|
||||
var configsToUpdate = new List<TelemeteringConfiguration>();
|
||||
var configsToInsert = new List<TelemeteringConfiguration>();
|
||||
|
||||
foreach (JToken result in results)
|
||||
{
|
||||
var item = result.ToObject<TelemeteringConfigurationExcel>();
|
||||
@ -309,7 +338,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
{
|
||||
// 更新现有配置
|
||||
UpdateTelemeteringConfiguration(existingConfig, item, result, equipmentRepo, equipmentTypeRepo);
|
||||
await _telemeteringConfigurationRepository.UpdateAsync(existingConfig);
|
||||
configsToUpdate.Add(existingConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -317,12 +346,43 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var newConfig = CreateTelemeteringConfiguration(item, result, id, equipmentRepo, equipmentTypeRepo);
|
||||
if (newConfig != null)
|
||||
{
|
||||
await _telemeteringConfigurationRepository.InsertAsync(newConfig);
|
||||
configsToInsert.Add(newConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 批量处理更新和插入操作
|
||||
const int batchSize = 1000;
|
||||
int totalProcessed = 0;
|
||||
|
||||
// 批量更新
|
||||
if (configsToUpdate.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToUpdate.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToUpdate.Skip(i).Take(batchSize).ToList();
|
||||
_telemeteringConfigurationRepository.GetDbContext().UpdateRange(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥测数据导入服务 - 批量更新了 {configsToUpdate.Count} 条记录");
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
if (configsToInsert.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToInsert.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToInsert.Skip(i).Take(batchSize).ToList();
|
||||
await _telemeteringConfigurationRepository.GetDbContext().AddRangeAsync(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥测数据导入服务 - 批量插入了 {configsToInsert.Count} 条记录");
|
||||
}
|
||||
|
||||
requestEasyResult.Flag = true;
|
||||
requestEasyResult.Message = $"成功处理 {totalProcessed} 条记录(更新: {configsToUpdate.Count}, 插入: {configsToInsert.Count})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -353,6 +413,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var query = _telesignalisationConfigurationRepository.GetAllIncluding(t => t.EquipmentType, t => t.TransformerSubstation, t => t.EquipmentInfo, t => t.PrimaryEquipmentInfo, t => t.PrimaryEquipmentInfo.EquipmentType)
|
||||
.Where(t => t.IsActive && t.TransformerSubstationId == input.TransformerSubstationId)
|
||||
.WhereIf(input.DataSourceCategory.HasValue, t => t.DataSourceCategory == input.DataSourceCategory);
|
||||
var equipmentTypes = _equipmentTypeRepository.GetAll().ToDictionary(t => t.Id);
|
||||
|
||||
// 根据 EquipmentInfoId 和 EquipmentTypeId 进行筛选
|
||||
if (input.EquipmentInfoId.HasValue)
|
||||
@ -388,6 +449,27 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
|
||||
foreach (var item in telesignalisationExcelList)
|
||||
{
|
||||
|
||||
var PrimaryEquipmentInfoTypeName = "";
|
||||
var EquipmentTypeName = "";
|
||||
|
||||
if (item.PrimaryEquipmentInfo != null)
|
||||
{
|
||||
if (equipmentTypes.ContainsKey(item.PrimaryEquipmentInfo.EquipmentTypeId.Value))
|
||||
{
|
||||
var equipmentType = equipmentTypes[item.PrimaryEquipmentInfo.EquipmentTypeId.Value];
|
||||
PrimaryEquipmentInfoTypeName = equipmentType.Name;
|
||||
}
|
||||
|
||||
}
|
||||
if (item.EquipmentInfo != null)
|
||||
{
|
||||
if (equipmentTypes.ContainsKey(item.EquipmentInfo.EquipmentTypeId.Value))
|
||||
{
|
||||
var equipmentType = equipmentTypes[item.EquipmentInfo.EquipmentTypeId.Value];
|
||||
EquipmentTypeName = equipmentType.Name;
|
||||
}
|
||||
}
|
||||
var row = new List<string>
|
||||
{
|
||||
item.Id?.ToString() ?? "",
|
||||
@ -470,6 +552,10 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var equipmentTypeRepo = _equipmentTypeRepository.GetAll().ToList();
|
||||
var alarmCategoryRepo = _dmAlarmCategoryRepo.GetAll().Where(a => a.IsActive).ToList();
|
||||
|
||||
// 使用批量操作优化性能
|
||||
var configsToUpdate = new List<TelesignalisationConfiguration>();
|
||||
var configsToInsert = new List<TelesignalisationConfiguration>();
|
||||
|
||||
foreach (JToken result in results)
|
||||
{
|
||||
var item = result.ToObject<TelesignalisationConfigurationExcel>();
|
||||
@ -497,7 +583,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
{
|
||||
// 更新现有配置
|
||||
UpdateTelesignalisationConfiguration(existingConfig, item, result, equipmentRepo, equipmentTypeRepo, alarmCategoryRepo);
|
||||
await _telesignalisationConfigurationRepository.UpdateAsync(existingConfig);
|
||||
configsToUpdate.Add(existingConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -505,12 +591,43 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var newConfig = CreateTelesignalisationConfiguration(item, result, id, equipmentRepo, equipmentTypeRepo, alarmCategoryRepo);
|
||||
if (newConfig != null)
|
||||
{
|
||||
await _telesignalisationConfigurationRepository.InsertAsync(newConfig);
|
||||
configsToInsert.Add(newConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 批量处理更新和插入操作
|
||||
const int batchSize = 1000;
|
||||
int totalProcessed = 0;
|
||||
|
||||
// 批量更新
|
||||
if (configsToUpdate.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToUpdate.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToUpdate.Skip(i).Take(batchSize).ToList();
|
||||
_telesignalisationConfigurationRepository.GetDbContext().UpdateRange(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥信数据导入服务 - 批量更新了 {configsToUpdate.Count} 条记录");
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
if (configsToInsert.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToInsert.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToInsert.Skip(i).Take(batchSize).ToList();
|
||||
await _telesignalisationConfigurationRepository.GetDbContext().AddRangeAsync(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥信数据导入服务 - 批量插入了 {configsToInsert.Count} 条记录");
|
||||
}
|
||||
|
||||
requestEasyResult.Flag = true;
|
||||
requestEasyResult.Message = $"成功处理 {totalProcessed} 条记录(更新: {configsToUpdate.Count}, 插入: {configsToInsert.Count})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -639,6 +756,10 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var equipmentRepo = _equipmentInfoRepository.GetAll().ToList();
|
||||
var equipmentTypeRepo = _equipmentTypeRepository.GetAll().ToList();
|
||||
|
||||
// 使用批量操作优化性能
|
||||
var configsToUpdate = new List<TelecommandConfiguration>();
|
||||
var configsToInsert = new List<TelecommandConfiguration>();
|
||||
|
||||
foreach (JToken result in results)
|
||||
{
|
||||
var item = result.ToObject<TelecommandConfigurationExcel>();
|
||||
@ -654,7 +775,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
{
|
||||
// 更新现有配置
|
||||
UpdateTelecommandConfiguration(existingConfig, item, result, equipmentRepo, equipmentTypeRepo);
|
||||
await _telecommandConfigurationRepository.UpdateAsync(existingConfig);
|
||||
configsToUpdate.Add(existingConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -662,12 +783,43 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
var newConfig = CreateTelecommandConfiguration(item, result, id, equipmentRepo, equipmentTypeRepo);
|
||||
if (newConfig != null)
|
||||
{
|
||||
await _telecommandConfigurationRepository.InsertAsync(newConfig);
|
||||
configsToInsert.Add(newConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 批量处理更新和插入操作
|
||||
const int batchSize = 1000;
|
||||
int totalProcessed = 0;
|
||||
|
||||
// 批量更新
|
||||
if (configsToUpdate.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToUpdate.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToUpdate.Skip(i).Take(batchSize).ToList();
|
||||
_telecommandConfigurationRepository.GetDbContext().UpdateRange(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥控数据导入服务 - 批量更新了 {configsToUpdate.Count} 条记录");
|
||||
}
|
||||
|
||||
// 批量插入
|
||||
if (configsToInsert.Any())
|
||||
{
|
||||
for (int i = 0; i < configsToInsert.Count; i += batchSize)
|
||||
{
|
||||
var batch = configsToInsert.Skip(i).Take(batchSize).ToList();
|
||||
await _telecommandConfigurationRepository.GetDbContext().AddRangeAsync(batch);
|
||||
await CurrentUnitOfWork.SaveChangesAsync();
|
||||
totalProcessed += batch.Count;
|
||||
}
|
||||
Log4Helper.Info(this.GetType(), $"遥控数据导入服务 - 批量插入了 {configsToInsert.Count} 条记录");
|
||||
}
|
||||
|
||||
requestEasyResult.Flag = true;
|
||||
requestEasyResult.Message = $"成功处理 {totalProcessed} 条记录(更新: {configsToUpdate.Count}, 插入: {configsToInsert.Count})";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -815,6 +967,10 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
config.PrimaryEquipmentInfoId = primaryEquipment.Id;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
config.PrimaryEquipmentInfoId = null;
|
||||
}
|
||||
|
||||
// 设置数据来源
|
||||
if (Enum.TryParse<DataSourceCategoryEnum>(item.DataSourceCategory.ToString(), out var dataSource))
|
||||
@ -859,7 +1015,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
|
||||
// 设置设备1信息
|
||||
var primaryEquipmentName = result["关联设备1"]?.ToString();
|
||||
var primaryEquipmentTypeName = result["关联类型设备1"]?.ToString();
|
||||
var primaryEquipmentTypeName = result["关联设备类型1"]?.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(primaryEquipmentName))
|
||||
{
|
||||
@ -875,6 +1031,10 @@ namespace YunDa.SOMS.Application.GeneralInformation
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
existingConfig.PrimaryEquipmentInfoId = null;
|
||||
}
|
||||
|
||||
// 设置数据来源
|
||||
if (Enum.TryParse<DataSourceCategoryEnum>(item.DataSourceCategory.ToString(), out var dataSource))
|
||||
|
||||
@ -94,7 +94,7 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AI分析结果(支持层级/树形结构数据)
|
||||
/// AI分析结果 正常|异常
|
||||
/// </summary>
|
||||
public string AIAnalysisResult { get; set; }
|
||||
|
||||
@ -392,25 +392,18 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public Guid? InspectionItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模块类型ID
|
||||
/// </summary>
|
||||
public Guid? ModuleTypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结果状态
|
||||
/// </summary>
|
||||
public SecondaryCircuitInspectionResultStatus? ResultStatus { get; set; }
|
||||
public string ModuleTypeName { get; set; }
|
||||
public string SecondaryCircuitInspectionItemName { get; set; }
|
||||
|
||||
public string ResultStatusName { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 触发方式
|
||||
/// </summary>
|
||||
public SecondaryCircuitInspectionPlanType? TriggerType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否异常
|
||||
/// </summary>
|
||||
public bool? IsAbnormal { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -456,6 +449,11 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public class DailyReportOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 报告ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总巡检项数
|
||||
/// </summary>
|
||||
@ -475,6 +473,11 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// 处置完成率
|
||||
/// </summary>
|
||||
public double DisposalCompletionRate { get; set; }
|
||||
/// <summary>
|
||||
/// AI处理结果
|
||||
/// </summary>
|
||||
public string ResultHandleDescription { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异常维度:按照父级类型进行统计
|
||||
@ -519,6 +522,11 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public class WeeklyReportOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 报告ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 趋势维度
|
||||
/// </summary>
|
||||
@ -529,11 +537,11 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public List<ModuleTypeDistribution> DistributionDimension { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 周例会决策建议
|
||||
/// </summary>
|
||||
public string WeeklyMeetingRecommendation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AI处理结果
|
||||
/// </summary>
|
||||
public string ResultHandleDescription { get; set; }
|
||||
/// <summary>
|
||||
/// 高频重复异常点
|
||||
/// </summary>
|
||||
@ -543,7 +551,7 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
{
|
||||
TrendDimension = new WeeklyTrendData();
|
||||
DistributionDimension = new List<ModuleTypeDistribution>();
|
||||
WeeklyMeetingRecommendation = "请调用AI分析";
|
||||
|
||||
HighFrequencyRepeatAbnormalPoints = new List<RepeatAbnormalPoint>();
|
||||
}
|
||||
}
|
||||
@ -647,6 +655,11 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public class MonthlyReportOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 报告ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 月度故障概率趋势:每月第一周到最后一周的每周故障概率
|
||||
/// </summary>
|
||||
@ -657,10 +670,7 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
/// </summary>
|
||||
public List<ModuleTypeDistribution> AbnormalTypeDistribution { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 月例会决策建议
|
||||
/// </summary>
|
||||
public string MonthlyMeetingRecommendation { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 高频重复异常点
|
||||
@ -668,9 +678,9 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
public List<RepeatAbnormalPoint> HighFrequencyRepeatAbnormalPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// AI预测建议
|
||||
/// AI处理结果
|
||||
/// </summary>
|
||||
public string AIPredictionRecommendation { get; set; }
|
||||
public string ResultHandleDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 月度关键指标对比
|
||||
@ -681,9 +691,9 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
|
||||
{
|
||||
MonthlyFaultProbabilityTrend = new List<WeeklyFaultProbability>();
|
||||
AbnormalTypeDistribution = new List<ModuleTypeDistribution>();
|
||||
MonthlyMeetingRecommendation = "请调用AI分析";
|
||||
|
||||
HighFrequencyRepeatAbnormalPoints = new List<RepeatAbnormalPoint>();
|
||||
AIPredictionRecommendation = "请调用AI分析";
|
||||
|
||||
MonthlyKeyIndicatorComparison = new List<KeyIndicatorComparison>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -6842,7 +6842,7 @@
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultDetailOutput.AIAnalysisResult">
|
||||
<summary>
|
||||
AI分析结果(支持层级/树形结构数据)
|
||||
AI分析结果 正常|异常
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultDetailOutput.ResultHandleDescription">
|
||||
@ -7110,26 +7110,11 @@
|
||||
巡检项ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultSearchConditionInput.ModuleTypeId">
|
||||
<summary>
|
||||
模块类型ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultSearchConditionInput.ResultStatus">
|
||||
<summary>
|
||||
结果状态
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultSearchConditionInput.TriggerType">
|
||||
<summary>
|
||||
触发方式
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.SecondaryCircuitInspectionResultSearchConditionInput.IsAbnormal">
|
||||
<summary>
|
||||
是否异常
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.CreateDisposalProcessRecordInput">
|
||||
<summary>
|
||||
创建处置过程记录输入DTO
|
||||
@ -7170,6 +7155,11 @@
|
||||
日报输出DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.DailyReportOutput.Id">
|
||||
<summary>
|
||||
报告ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.DailyReportOutput.TotalInspectionCount">
|
||||
<summary>
|
||||
总巡检项数
|
||||
@ -7190,6 +7180,11 @@
|
||||
处置完成率
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.DailyReportOutput.ResultHandleDescription">
|
||||
<summary>
|
||||
AI处理结果
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.DailyReportOutput.AbnormalByModuleType">
|
||||
<summary>
|
||||
异常维度:按照父级类型进行统计
|
||||
@ -7225,6 +7220,11 @@
|
||||
周报输出DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.WeeklyReportOutput.Id">
|
||||
<summary>
|
||||
报告ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.WeeklyReportOutput.TrendDimension">
|
||||
<summary>
|
||||
趋势维度
|
||||
@ -7235,9 +7235,9 @@
|
||||
分布维度:按照父级类型统计
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.WeeklyReportOutput.WeeklyMeetingRecommendation">
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.WeeklyReportOutput.ResultHandleDescription">
|
||||
<summary>
|
||||
周例会决策建议
|
||||
AI处理结果
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.WeeklyReportOutput.HighFrequencyRepeatAbnormalPoints">
|
||||
@ -7335,6 +7335,11 @@
|
||||
月报输出DTO
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.Id">
|
||||
<summary>
|
||||
报告ID
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.MonthlyFaultProbabilityTrend">
|
||||
<summary>
|
||||
月度故障概率趋势:每月第一周到最后一周的每周故障概率
|
||||
@ -7345,19 +7350,14 @@
|
||||
异常类型占比:按照父级类型统计
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.MonthlyMeetingRecommendation">
|
||||
<summary>
|
||||
月例会决策建议
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.HighFrequencyRepeatAbnormalPoints">
|
||||
<summary>
|
||||
高频重复异常点
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.AIPredictionRecommendation">
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.ResultHandleDescription">
|
||||
<summary>
|
||||
AI预测建议
|
||||
AI处理结果
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Output.MonthlyReportOutput.MonthlyKeyIndicatorComparison">
|
||||
|
||||
@ -71,6 +71,8 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
private readonly IRepository<PatternRecognitionConfigutration, Guid> _patternRecognitionConfigutrationRepository;
|
||||
private readonly IRepository<DMAlarmCategory, Guid> _alarmCategoryRepository;
|
||||
private readonly IRepository<PresetPoint, Guid> _presetPointRepository;
|
||||
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
|
||||
|
||||
private readonly IRepository<TelesignalisationConfiguration, Guid> _telesignalisationConfigurationRepository;
|
||||
|
||||
private readonly IRepository<MeasureTemperaturePoint, Guid> _mtpRepository;
|
||||
@ -121,6 +123,7 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
IMongoDbRepository<BsonDocument, Guid> bsonDocumentResultRepository,
|
||||
IRepository<TelesignalisationConfiguration, Guid> telesignalisationConfigurationRepository,
|
||||
IRepository<VideoDev, Guid> videoDevRepository,
|
||||
IRepository<EquipmentInfo, Guid> equipmentInfoRepository,
|
||||
ISessionAppService sessionAppService) :
|
||||
base(sessionAppService, appServiceConfiguration)
|
||||
{
|
||||
@ -148,6 +151,7 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
_telesignalisationConfigurationRepository = telesignalisationConfigurationRepository;
|
||||
_allTimeImageRepository = allTimeImageRepository;
|
||||
_videoDevRepository = videoDevRepository;
|
||||
_equipmentInfoRepository = equipmentInfoRepository;
|
||||
_bsonDocumentResultRepository = bsonDocumentResultRepository;
|
||||
}
|
||||
#region 巡检结果编辑
|
||||
@ -492,13 +496,25 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
var f = builder.Lte("AnalysisTime", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now;
|
||||
var f = builder.Lte("AnalysisTime", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
if (searchCondition.MinTime.HasValue)
|
||||
{
|
||||
DateTime date = Convert.ToDateTime(searchCondition.MinTime);
|
||||
var f = builder.Gte("AnalysisTime", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
if (filters.Count>0)
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now.Date - TimeSpan.FromDays(5);
|
||||
var f = builder.Gte("AnalysisTime", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
if (filters.Count > 0)
|
||||
{
|
||||
var filter = builder.And(filters);
|
||||
var sorter = Builders<InspectionItemResult>.Sort;
|
||||
@ -512,7 +528,7 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
{
|
||||
foreach (var preset in presetRepo)
|
||||
{
|
||||
if (data.VideoDevId== preset.VideoDevId&&data.PresetPointNumber == preset.Number)
|
||||
if (data.VideoDevId == preset.VideoDevId && data.PresetPointNumber == preset.Number)
|
||||
{
|
||||
list.Add(data);
|
||||
}
|
||||
@ -551,6 +567,11 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
try
|
||||
{
|
||||
var prserPoints = _presetPointRepository.GetAll().ToList();
|
||||
var equipment = _equipmentInfoRepository.GetAll().FirstOrDefault(t => t.Id == searchCondition.EquipmentInfoId);
|
||||
if (equipment == null)
|
||||
{
|
||||
return rst;
|
||||
}
|
||||
var cameras = _videoDevRepository.GetAll().ToList();
|
||||
var builder = Builders<BsonDocument>.Filter;
|
||||
|
||||
@ -562,12 +583,24 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
var f = builder.Lte("Time", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now;
|
||||
var f = builder.Lte("Time", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
if (searchCondition.MinTime.HasValue)
|
||||
{
|
||||
DateTime date = Convert.ToDateTime(searchCondition.MinTime);
|
||||
var f = builder.Gte("Time", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now.Date - TimeSpan.FromDays(5);
|
||||
var f = builder.Gte("Time", date);//<
|
||||
filters.Add(f);
|
||||
}
|
||||
var sorter = Builders<BsonDocument>.Sort;
|
||||
SortDefinition<BsonDocument> sortDefinition = sorter.Descending("Time");
|
||||
_bsonDocumentResultRepository.CollectionName = nameof(OriginalInspectionStoreResult);
|
||||
@ -583,9 +616,9 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
// 创建查找字典优化性能
|
||||
var cameraDict = cameras.ToDictionary(c => c.DevName);
|
||||
var presetDict = prserPoints.GroupBy(p => p.VideoDevId)
|
||||
.ToDictionary(g => g.Key,
|
||||
g => g.ToDictionary(p => p.Number));
|
||||
|
||||
.ToDictionary(g => g.Key,
|
||||
g => g.DistinctBy(p => p.Number)
|
||||
.ToDictionary(p => p.Number));
|
||||
foreach (var data in originalData)
|
||||
{
|
||||
// 1. 查找摄像头
|
||||
@ -600,25 +633,49 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
if (!presetDict.TryGetValue(camera.Id, out var devicePresets) ||
|
||||
!devicePresets.TryGetValue(presetCode, out var preset))
|
||||
continue;
|
||||
if (preset.EquipmentInfoId == null)
|
||||
{
|
||||
// 5. 设备名称匹配检查(60%相似度)
|
||||
bool isNameMatch = false;
|
||||
|
||||
// 4. 检查设备ID
|
||||
if (preset.EquipmentInfoId != searchCondition.EquipmentInfoId)
|
||||
continue;
|
||||
if (data.Result.Contains(equipment.Name))
|
||||
{
|
||||
// 直接包含则通过
|
||||
isNameMatch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 计算相似度(60%阈值)
|
||||
double similarity = CalculateSimilarity(data.Result, equipment.Name);
|
||||
if (similarity >= 0.8)
|
||||
{
|
||||
isNameMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 构建结果对象
|
||||
if (!isNameMatch)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4. 检查设备ID
|
||||
if (preset.EquipmentInfoId != searchCondition.EquipmentInfoId)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 6. 构建结果对象
|
||||
var output = new InspectionItemResultOutput
|
||||
{
|
||||
VideoDevName = data.CamName,
|
||||
PresetPointNumber = presetCode,
|
||||
AnalysisTime = DateTime.Parse(data.CaptureTime),
|
||||
AnalysisStatus = int.Parse(data.Status),
|
||||
AnalysisMessage = data.Message,
|
||||
AnalysisResult = data.Result,
|
||||
SeqNo = int.Parse(data.Seq),
|
||||
VideoDevId = camera.Id,
|
||||
PresetPointName = preset.Name,
|
||||
//AliasPath = ""
|
||||
RelativePath =string.IsNullOrEmpty( data.RelativePath)?"\\": data.RelativePath,
|
||||
RelativePath = string.IsNullOrEmpty(data.RelativePath) ? "\\" : data.RelativePath,
|
||||
BasePath = string.IsNullOrEmpty(data.BasePath) ? "\\" : data.BasePath,
|
||||
InspectionItemFiles = data.PictureNames.Select(t => new AttachmentFile
|
||||
{
|
||||
@ -627,10 +684,11 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
FileType = 0
|
||||
})
|
||||
};
|
||||
|
||||
rst.ResultData.Add(output);
|
||||
}
|
||||
rst.Flag = true;
|
||||
|
||||
|
||||
rst.Flag = true;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -641,7 +699,50 @@ namespace YunDa.SOMS.MongoDB.Application.Inspection
|
||||
}
|
||||
return rst;
|
||||
}
|
||||
// 相似度计算方法(选择以下任一种)
|
||||
private double CalculateSimilarity(string source, string target)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target))
|
||||
return 0;
|
||||
|
||||
// 方法1: 简单的子串匹配比例
|
||||
int matchCount = 0;
|
||||
foreach (char c in target)
|
||||
{
|
||||
if (source.Contains(c))
|
||||
matchCount++;
|
||||
}
|
||||
return (double)matchCount / target.Length;
|
||||
|
||||
// 方法2: Levenshtein距离(更精确,推荐)
|
||||
// int distance = LevenshteinDistance(source, target);
|
||||
// int maxLength = Math.Max(source.Length, target.Length);
|
||||
// return 1.0 - (double)distance / maxLength;
|
||||
}
|
||||
|
||||
// Levenshtein距离算法(可选,更精确)
|
||||
private int LevenshteinDistance(string source, string target)
|
||||
{
|
||||
int n = source.Length;
|
||||
int m = target.Length;
|
||||
int[,] d = new int[n + 1, m + 1];
|
||||
|
||||
if (n == 0) return m;
|
||||
if (m == 0) return n;
|
||||
|
||||
for (int i = 0; i <= n; i++) d[i, 0] = i;
|
||||
for (int j = 0; j <= m; j++) d[0, j] = j;
|
||||
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
for (int j = 1; j <= m; j++)
|
||||
{
|
||||
int cost = (target[j - 1] == source[i - 1]) ? 0 : 1;
|
||||
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
|
||||
}
|
||||
}
|
||||
return d[n, m];
|
||||
}
|
||||
[HttpPost]
|
||||
[UnitOfWork(true)]
|
||||
[ShowApi]
|
||||
|
||||
@ -52,7 +52,10 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
private readonly IMongoDatabase _mongoDatabase;
|
||||
private readonly IRepository<SecondaryCircuitInspectionItem, Guid> _inspectionItemRepository;
|
||||
private readonly IRepository<SecondaryCircuitInspectionPlan, Guid> _inspectionPlanRepository;
|
||||
private readonly IRepository<SecondaryCircuitInspectionPlanItem, Guid> _planItemRepository;
|
||||
|
||||
private readonly IRepository<SecondaryCircuitEventDrivenConfig, Guid> _eventDrivenConfigRepository;
|
||||
private readonly IRepository<SecondaryCircuitInspectionEventItem, Guid> _eventItemRepository;
|
||||
|
||||
public SecondaryCircuitInspectionResultAppService(
|
||||
IMongoDbRepository<SecondaryCircuitInspectionResult, string> inspectionResultRepository,
|
||||
@ -60,6 +63,8 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
IRepository<SecondaryCircuitInspectionItem, Guid> inspectionItemRepository,
|
||||
IRepository<SecondaryCircuitInspectionPlan, Guid> inspectionPlanRepository,
|
||||
IRepository<SecondaryCircuitEventDrivenConfig, Guid> eventDrivenConfigRepository,
|
||||
IRepository<SecondaryCircuitInspectionEventItem, Guid> eventItemRepository,
|
||||
IRepository<SecondaryCircuitInspectionPlanItem, Guid> planItemRepository,
|
||||
ISessionAppService sessionAppService) : base(sessionAppService)
|
||||
{
|
||||
_inspectionResultRepository = inspectionResultRepository;
|
||||
@ -67,7 +72,8 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
_inspectionItemRepository = inspectionItemRepository;
|
||||
_inspectionPlanRepository = inspectionPlanRepository;
|
||||
_eventDrivenConfigRepository = eventDrivenConfigRepository;
|
||||
|
||||
_eventItemRepository = eventItemRepository;
|
||||
_planItemRepository = planItemRepository;
|
||||
// 初始化 MongoDB 数据库
|
||||
_mongoDatabase = _inspectionResultRepository.Database;
|
||||
}
|
||||
@ -113,15 +119,25 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
SecondaryCircuitInspectionPlan inspectionPlan = null;
|
||||
if (intput.InspectionPlanId.HasValue)
|
||||
{
|
||||
inspectionPlan = await _inspectionPlanRepository.GetAll()
|
||||
.FirstOrDefaultAsync(x => x.Id == intput.InspectionPlanId, cancellationToken);
|
||||
var inspectionPlanItem = await _planItemRepository.GetAll().Include(t=>t.InspectionPlan)
|
||||
.FirstOrDefaultAsync(x => x.InspectionItemId == intput.InspectionPlanId, cancellationToken);
|
||||
|
||||
if (inspectionPlanItem != null)
|
||||
{
|
||||
inspectionPlan = inspectionPlanItem.InspectionPlan;
|
||||
}
|
||||
}
|
||||
|
||||
SecondaryCircuitEventDrivenConfig eventDrivenConfig = null;
|
||||
if (intput.TriggerEventId.HasValue)
|
||||
{
|
||||
eventDrivenConfig = await _eventDrivenConfigRepository.GetAll()
|
||||
var eventDrivenConfigitem = await _eventItemRepository.GetAll().Include(t=>t.SecondaryCircuitEventDrivenConfig)
|
||||
.FirstOrDefaultAsync(x => x.Id == intput.TriggerEventId, cancellationToken);
|
||||
|
||||
if (eventDrivenConfigitem!=null)
|
||||
{
|
||||
eventDrivenConfig = eventDrivenConfigitem.SecondaryCircuitEventDrivenConfig;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建实体并映射基本字段
|
||||
@ -150,7 +166,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
// 填充名称字段
|
||||
entity.SecondaryCircuitInspectionItemName = inspectionItem.Name;
|
||||
entity.InspectionPlanName = inspectionPlan?.Name;
|
||||
entity.TransformerSubstationName = inspectionPlan?.TransformerSubstation?.SubstationName;
|
||||
|
||||
entity.SubTypeName = inspectionItem.ModuleType?.Name;
|
||||
|
||||
// 获取模块类型的父类型名称作为SubTypeName
|
||||
@ -162,7 +178,6 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
|
||||
entity.ConfigTypeName = eventDrivenConfig?.Name;
|
||||
entity.ResultStatusName = GetEnumDescription(entity.ResultStatus);
|
||||
entity.TriggerTypeName = GetEnumDescription(entity.TriggerType);
|
||||
|
||||
// 使用动态集合名称(按年月分片)
|
||||
var collectionName = entity.GetCollectionName();
|
||||
@ -541,7 +556,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
{
|
||||
Id = result.Id,
|
||||
IsDisposed = disposalRecords.Any(x => x.IsCompleted),
|
||||
InspectionItemName = result.SecondaryCircuitInspectionItemName,
|
||||
InspectionItemName = result.SecondaryCircuitInspectionItemName??result.ConfigTypeName,
|
||||
ModuleTypeName = result.ModuleTypeName,
|
||||
Status = result.Status,
|
||||
InspectionResult = result.InspectionResult,
|
||||
@ -599,6 +614,8 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
PageSearchCondition<SecondaryCircuitInspectionResultSearchConditionInput> searchCondition)
|
||||
{
|
||||
var rst = new RequestPageResult<SecondaryCircuitInspectionResultDetailOutput>();
|
||||
//var plans = _inspectionPlanRepository.GetAll().ToDictionary(t=>t.Id);
|
||||
//var enents = _eventDrivenConfigRepository.GetAll().ToDictionary(t => t.Id);
|
||||
|
||||
try
|
||||
{
|
||||
@ -636,23 +653,21 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
{
|
||||
filters.Add(filterBuilder.Eq(x => x.InspectionPlanId, condition.InspectionPlanId.Value));
|
||||
}
|
||||
|
||||
// 巡检项过滤
|
||||
if (condition.InspectionItemId.HasValue)
|
||||
if (!string.IsNullOrEmpty(condition.ModuleTypeName))
|
||||
{
|
||||
filters.Add(filterBuilder.Eq(x => x.SecondaryCircuitInspectionItemId, condition.InspectionItemId.Value));
|
||||
filters.Add(filterBuilder.Eq(x => x.ModuleTypeName, condition.ModuleTypeName));
|
||||
}
|
||||
|
||||
// 模块类型过滤
|
||||
if (condition.ModuleTypeId.HasValue)
|
||||
if (!string.IsNullOrEmpty(condition.SecondaryCircuitInspectionItemName))
|
||||
{
|
||||
filters.Add(filterBuilder.Eq("ModuleTypeId", condition.ModuleTypeId.Value));
|
||||
filters.Add(filterBuilder.Regex(x => x.SecondaryCircuitInspectionItemName,
|
||||
new BsonRegularExpression(condition.SecondaryCircuitInspectionItemName, "i")));
|
||||
}
|
||||
|
||||
// 结果状态过滤
|
||||
if (condition.ResultStatus.HasValue)
|
||||
if (!string.IsNullOrEmpty(condition.ResultStatusName))
|
||||
{
|
||||
filters.Add(filterBuilder.Eq(x => x.ResultStatus, condition.ResultStatus.Value));
|
||||
filters.Add(filterBuilder.Eq(x => x.ResultStatusName, condition.ResultStatusName));
|
||||
}
|
||||
|
||||
// 触发方式过滤
|
||||
@ -661,12 +676,6 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
filters.Add(filterBuilder.Eq(x => x.TriggerType, condition.TriggerType.Value));
|
||||
}
|
||||
|
||||
// 是否异常过滤
|
||||
if (condition.IsAbnormal.HasValue)
|
||||
{
|
||||
filters.Add(filterBuilder.Eq(x => x.IsAbnormal, condition.IsAbnormal.Value));
|
||||
}
|
||||
|
||||
var filter = filterBuilder.And(filters);
|
||||
|
||||
// 查询数据
|
||||
@ -729,7 +738,8 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
{
|
||||
Id = result.Id,
|
||||
IsDisposed = disposalRecords.Where(t=>t.InspectionResultId == result.Id).Any(x => x.IsCompleted),
|
||||
InspectionItemName = result.SecondaryCircuitInspectionItemName,
|
||||
InspectionItemName = result.SecondaryCircuitInspectionItemName??"",
|
||||
|
||||
ModuleTypeName = result.ModuleTypeName,
|
||||
SubTypeName = result.SubTypeName,
|
||||
Status = result.Status,
|
||||
@ -737,7 +747,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
//VerificationResult = result.VerificationResult,
|
||||
//CalculationProcess = result.CalculationProcess,
|
||||
ExecutionTime = result.ExecutionTime,
|
||||
InspectionPlanName = result.InspectionPlanName,
|
||||
InspectionPlanName = result.InspectionPlanName?? result.ConfigTypeName,
|
||||
TransformerSubstationName = result.TransformerSubstationName,
|
||||
IsAbnormal = result.IsAbnormal,
|
||||
//AbnormalDescription = result.AbnormalDescription,
|
||||
@ -847,13 +857,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
#region 日报、周报、月报API
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 更新报告AI分析结果和巡检结果处理措施
|
||||
/// </summary>
|
||||
@ -866,40 +870,56 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// 处理日报/周报/月报的AI分析(如果提供了ReportId)
|
||||
if (!string.IsNullOrWhiteSpace(input.ReportId))
|
||||
{
|
||||
var reportCollectionName = "SecondaryCircuitInspectionReport";
|
||||
var reportCollectionName = "SecondaryCircuitInspectionAIReport";
|
||||
|
||||
var reportCollection = _mongoDatabase.GetCollection<BsonDocument>(reportCollectionName);
|
||||
var reportFilter = Builders<BsonDocument>.Filter.Eq("ReportId", ObjectId.Parse(input.ReportId));
|
||||
|
||||
var reportFilter = Builders<BsonDocument>.Filter.Eq("_id", ObjectId.Parse(input.ReportId));
|
||||
var reportUpdate = Builders<BsonDocument>.Update
|
||||
.Set("ReportId", ObjectId.Parse(input.ReportId)) // 添加ReportId,确保插入时有该字段
|
||||
.Set("AIAnalysisResult", input.AIAnalysisResult)
|
||||
.Set("UpdatedAt", DateTime.Now);
|
||||
.Set("ResultHandleDescription", input.ResultHandleDescription)
|
||||
.Set("UpdatedAt", DateTime.Now)
|
||||
.SetOnInsert("CreatedAt", DateTime.Now); // 仅在插入时设置CreatedAt
|
||||
|
||||
var reportResult = await reportCollection.UpdateOneAsync(reportFilter, reportUpdate, cancellationToken: cancellationToken);
|
||||
// 设置upsert选项
|
||||
var options = new UpdateOptions { IsUpsert = true };
|
||||
|
||||
if (reportResult.ModifiedCount == 0)
|
||||
{
|
||||
Log4Helper.Warning($"报告不存在或更新失败: ReportId={input.ReportId}");
|
||||
}
|
||||
else
|
||||
var reportResult = await reportCollection.UpdateOneAsync(
|
||||
reportFilter,
|
||||
reportUpdate,
|
||||
options,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
if (reportResult.ModifiedCount > 0)
|
||||
{
|
||||
Log4Helper.Info($"更新报告AI分析成功: ReportId={input.ReportId}");
|
||||
}
|
||||
else if (reportResult.UpsertedId != null)
|
||||
{
|
||||
Log4Helper.Info($"插入新报告AI分析成功: ReportId={input.ReportId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log4Helper.Warning($"报告处理异常: ReportId={input.ReportId}");
|
||||
}
|
||||
}
|
||||
|
||||
// 处理单个巡检项的AI分析(如果提供了InspectionResultId)
|
||||
if (!string.IsNullOrWhiteSpace(input.InspectionResultId))
|
||||
else if (!string.IsNullOrWhiteSpace(input.InspectionResultId))
|
||||
{
|
||||
var aiReportCollectionName = "SecondaryCircuitInspectionAIReport";
|
||||
var aiReportCollection = _mongoDatabase.GetCollection<BsonDocument>(aiReportCollectionName);
|
||||
|
||||
var filter = Builders<BsonDocument>.Filter.Eq("InspectionResultId", input.InspectionResultId);
|
||||
var report = (await aiReportCollection.FindAsync(filter)).FirstOrDefault();
|
||||
// 判断是更新还是插入操作
|
||||
if (!string.IsNullOrWhiteSpace(input.Id))
|
||||
if (report != null)
|
||||
{
|
||||
// 更新现有记录
|
||||
var filter = Builders<BsonDocument>.Filter.Eq("_id", ObjectId.Parse(input.Id));
|
||||
var update = Builders<BsonDocument>.Update
|
||||
.Set("AIAnalysisResult", input.AIAnalysisResult)
|
||||
.Set("ResultHandleDescription", input.ResultHandleDescription)
|
||||
|
||||
@ -1187,6 +1187,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[ShowApi]
|
||||
[AllowAnonymous]
|
||||
public async Task<RequestResult<DailyReportOutput>> GetDailyReportAsync(
|
||||
DateTime reportDate,
|
||||
CancellationToken cancellationToken = default)
|
||||
@ -1203,7 +1204,18 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
if (cachedReport != null)
|
||||
{
|
||||
var cachedOutput = BsonSerializer.Deserialize<DailyReportOutput>(cachedReport.GetValue("ReportData").AsBsonDocument);
|
||||
Log4Helper.Info($"从缓存获取日报成功: ReportDate={reportDate:yyyy-MM-dd}");
|
||||
|
||||
// 设置报告ID
|
||||
cachedOutput.Id = cachedReport.GetValue("_id").AsObjectId.ToString();
|
||||
|
||||
// 查询AI分析结果
|
||||
var aiAnalysisResult = cachedReport.GetValue("AIAnalysisResult", BsonNull.Value);
|
||||
if (aiAnalysisResult != BsonNull.Value)
|
||||
{
|
||||
cachedOutput.ResultHandleDescription = aiAnalysisResult.AsString;
|
||||
}
|
||||
|
||||
Log4Helper.Info($"从缓存获取日报成功: ReportDate={reportDate:yyyy-MM-dd}, ReportId={cachedOutput.Id}");
|
||||
return RequestResult<DailyReportOutput>.CreateSuccess(cachedOutput);
|
||||
}
|
||||
}
|
||||
@ -1217,8 +1229,12 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
// 只有历史日期才保存到缓存
|
||||
if (!isToday)
|
||||
{
|
||||
await SaveReportAsync("Daily", reportDate, reportDate, output.ToBsonDocument(), cancellationToken);
|
||||
Log4Helper.Info($"历史日报已缓存: ReportDate={reportDate:yyyy-MM-dd}");
|
||||
var reportId = await SaveReportAsync("Daily", reportDate, reportDate, output.ToBsonDocument(), cancellationToken);
|
||||
if (!string.IsNullOrEmpty(reportId))
|
||||
{
|
||||
output.Id = reportId;
|
||||
}
|
||||
Log4Helper.Info($"历史日报已缓存: ReportDate={reportDate:yyyy-MM-dd}, ReportId={reportId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1257,7 +1273,26 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
if (cachedReport != null)
|
||||
{
|
||||
var cachedOutput = BsonSerializer.Deserialize<WeeklyReportOutput>(cachedReport.GetValue("ReportData").AsBsonDocument);
|
||||
Log4Helper.Info($"从缓存获取周报成功: StartDate={startDate:yyyy-MM-dd}, EndDate={endDate:yyyy-MM-dd}");
|
||||
|
||||
// 设置报告ID
|
||||
cachedOutput.Id = cachedReport.GetValue("_id").AsObjectId.ToString();
|
||||
var reportCollectionName = "SecondaryCircuitInspectionAIReport";
|
||||
var reportCollection = _mongoDatabase.GetCollection<BsonDocument>(reportCollectionName);
|
||||
|
||||
var reportFilter = Builders<BsonDocument>.Filter.Eq("ReportId", ObjectId.Parse(cachedOutput.Id));
|
||||
// 查询AI分析结果
|
||||
var reportResult =( await reportCollection.FindAsync(reportFilter)).FirstOrDefault();
|
||||
|
||||
if (reportResult !=null)
|
||||
{
|
||||
cachedOutput.ResultHandleDescription = reportResult["ResultHandleDescription"]?.AsString;
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedOutput.ResultHandleDescription = "请点击按钮生成分析结果";
|
||||
}
|
||||
|
||||
Log4Helper.Info($"从缓存获取周报成功: StartDate={startDate:yyyy-MM-dd}, EndDate={endDate:yyyy-MM-dd}, ReportId={cachedOutput.Id}");
|
||||
return RequestResult<WeeklyReportOutput>.CreateSuccess(cachedOutput);
|
||||
}
|
||||
}
|
||||
@ -1268,8 +1303,12 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
// 只有历史周才保存到缓存
|
||||
if (!isCurrentWeek)
|
||||
{
|
||||
await SaveReportAsync("Weekly", startDate, endDate, output.ToBsonDocument(), cancellationToken);
|
||||
Log4Helper.Info($"历史周报已缓存: StartDate={startDate:yyyy-MM-dd}, EndDate={endDate:yyyy-MM-dd}");
|
||||
var reportId = await SaveReportAsync("Weekly", startDate, endDate, output.ToBsonDocument(), cancellationToken);
|
||||
if (!string.IsNullOrEmpty(reportId))
|
||||
{
|
||||
output.Id = reportId;
|
||||
}
|
||||
Log4Helper.Info($"历史周报已缓存: StartDate={startDate:yyyy-MM-dd}, EndDate={endDate:yyyy-MM-dd}, ReportId={reportId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1311,7 +1350,25 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
if (cachedReport != null)
|
||||
{
|
||||
var cachedOutput = BsonSerializer.Deserialize<MonthlyReportOutput>(cachedReport.GetValue("ReportData").AsBsonDocument);
|
||||
Log4Helper.Info($"从缓存获取月报成功: Year={year}, Month={month}");
|
||||
|
||||
// 设置报告ID
|
||||
cachedOutput.Id = cachedReport.GetValue("_id").AsObjectId.ToString();
|
||||
var reportCollectionName = "SecondaryCircuitInspectionAIReport";
|
||||
var reportCollection = _mongoDatabase.GetCollection<BsonDocument>(reportCollectionName);
|
||||
|
||||
var reportFilter = Builders<BsonDocument>.Filter.Eq("ReportId", ObjectId.Parse(cachedOutput.Id));
|
||||
// 查询AI分析结果
|
||||
var reportResult = (await reportCollection.FindAsync(reportFilter)).FirstOrDefault();
|
||||
|
||||
if (reportResult != null)
|
||||
{
|
||||
cachedOutput.ResultHandleDescription = reportResult["ResultHandleDescription"].AsString;
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedOutput.ResultHandleDescription = "请点击按钮生成分析结果";
|
||||
}
|
||||
Log4Helper.Info($"从缓存获取月报成功: Year={year}, Month={month}, ReportId={cachedOutput.Id}");
|
||||
return RequestResult<MonthlyReportOutput>.CreateSuccess(cachedOutput);
|
||||
}
|
||||
}
|
||||
@ -1322,8 +1379,12 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
// 只有历史月份才保存到缓存
|
||||
if (!isCurrentMonth)
|
||||
{
|
||||
await SaveReportAsync("Monthly", startDate, endDate, output.ToBsonDocument(), cancellationToken);
|
||||
Log4Helper.Info($"历史月报已缓存: Year={year}, Month={month}");
|
||||
var reportId = await SaveReportAsync("Monthly", startDate, endDate, output.ToBsonDocument(), cancellationToken);
|
||||
if (!string.IsNullOrEmpty(reportId))
|
||||
{
|
||||
output.Id = reportId;
|
||||
}
|
||||
Log4Helper.Info($"历史月报已缓存: Year={year}, Month={month}, ReportId={reportId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1417,7 +1478,7 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
/// <summary>
|
||||
/// 保存报告到缓存
|
||||
/// </summary>
|
||||
private async Task SaveReportAsync(
|
||||
private async Task<string> SaveReportAsync(
|
||||
string reportType,
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
@ -1441,11 +1502,14 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
};
|
||||
|
||||
await collection.InsertOneAsync(document, cancellationToken: cancellationToken);
|
||||
Log4Helper.Info($"保存报告到缓存成功: ReportType={reportType}, StartDate={startDate:yyyy-MM-dd}");
|
||||
var reportId = document["_id"].AsObjectId.ToString();
|
||||
Log4Helper.Info($"保存报告到缓存成功: ReportType={reportType}, StartDate={startDate:yyyy-MM-dd}, ReportId={reportId}");
|
||||
return reportId;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Error($"保存报告到缓存失败: {ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1552,6 +1616,8 @@ namespace YunDa.SOMS.MongoDB.Application.DataMonitoring.SecondaryCircuitInspecti
|
||||
else
|
||||
disposalProgress = "未处理";
|
||||
|
||||
|
||||
|
||||
output.HighFrequencyAbnormalItems.Add(new HighFrequencyAbnormalItem
|
||||
{
|
||||
InspectionItemName = group.Key,
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
using Abp.Auditing;
|
||||
using Abp.Authorization;
|
||||
using Abp.Domain.Repositories;
|
||||
using log4net.Filter;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization;
|
||||
using MongoDB.Driver;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
@ -11,6 +13,7 @@ using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ToolLibrary.LogHelper;
|
||||
using Yunda.SOMS.MongoDB.Entities.MeasuresTemperature;
|
||||
@ -20,8 +23,10 @@ using YunDa.SOMS.Application.Core.Session;
|
||||
using YunDa.SOMS.Application.Core.SwaggerHelper;
|
||||
using YunDa.SOMS.DataTransferObject;
|
||||
using YunDa.SOMS.DataTransferObject.Iec104;
|
||||
using YunDa.SOMS.DataTransferObject.MainstationData;
|
||||
using YunDa.SOMS.DataTransferObject.VideoSurveillance.MeasureTemperatureResultDto;
|
||||
using YunDa.SOMS.DataTransferObject.VideoSurveillance.MeasureTemperatureResultDto.SearchCondition;
|
||||
using YunDa.SOMS.Entities.GeneralInformation;
|
||||
using YunDa.SOMS.Entities.System;
|
||||
using YunDa.SOMS.Entities.VideoSurveillance;
|
||||
using YunDa.SOMS.MongoDB.Repositories;
|
||||
@ -38,7 +43,8 @@ namespace YunDa.SOMS.MongoDB.Application.MeasuresTemperature
|
||||
/// 红外测温结果仓储
|
||||
/// </summary>
|
||||
private readonly IMongoDbRepository<MeasureTemperatureResult, Guid> _resultRepository;
|
||||
|
||||
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
|
||||
private readonly IRepository<PresetPoint, Guid> _presetPointRepository;
|
||||
private readonly IMongoDbRepository<BsonDocument, Guid> _bsonDocumentResultRepository;
|
||||
/// <summary>
|
||||
/// 红外测温点仓储
|
||||
@ -50,6 +56,8 @@ namespace YunDa.SOMS.MongoDB.Application.MeasuresTemperature
|
||||
, IRepository<MeasureTemperaturePoint, Guid> mtpRepository,
|
||||
IMongoDbRepository<BsonDocument, Guid> bsonDocumentResultRepository
|
||||
, IRepository<SysConfiguration, Guid> sysConfigurationRepository
|
||||
, IRepository<EquipmentInfo, Guid> equipmentInfoRepository
|
||||
, IRepository<PresetPoint, Guid> presetPointRepository
|
||||
, ISessionAppService sessionAppService) :
|
||||
base(sessionAppService)
|
||||
{
|
||||
@ -57,6 +65,8 @@ namespace YunDa.SOMS.MongoDB.Application.MeasuresTemperature
|
||||
_mtpRepository = mtpRepository;
|
||||
_bsonDocumentResultRepository = bsonDocumentResultRepository;
|
||||
_sysConfigurationRepository = sysConfigurationRepository;
|
||||
_equipmentInfoRepository = equipmentInfoRepository;
|
||||
_presetPointRepository = presetPointRepository;
|
||||
}
|
||||
|
||||
#region 测温结果编辑
|
||||
@ -340,76 +350,7 @@ namespace YunDa.SOMS.MongoDB.Application.MeasuresTemperature
|
||||
[Abp.Domain.Uow.UnitOfWork(true)]
|
||||
public RequestPageResult<MeasureTemperatureResultOutput> FindDatas(PageSearchCondition<MeasureTemperatureResultSearchConditonInput> searchCondition)
|
||||
{
|
||||
var search = searchCondition.SearchCondition;
|
||||
RequestPageResult<MeasureTemperatureResultOutput> requestPageResult = new RequestPageResult<MeasureTemperatureResultOutput>();
|
||||
List<MeasureTemperatureResultOutput> outputs = new List<MeasureTemperatureResultOutput>();
|
||||
var builder = Builders<BsonDocument>.Filter;
|
||||
var listfilters = new List<FilterDefinition<BsonDocument>>();
|
||||
if (!string.IsNullOrWhiteSpace(search.Name))
|
||||
{
|
||||
var filterDefinition = builder.Regex("Name", search.Name);
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
if (search.EquipmentInfoId.HasValue)
|
||||
{
|
||||
var filterDefinition = builder.Eq("EquipmentInfoId", search.EquipmentInfoId);
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
if (search.StartTime.HasValue)
|
||||
{
|
||||
var filterDefinition = builder.Gte("MeasureTime", search.StartTime);//<
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
if (search.EndTime.HasValue)
|
||||
{
|
||||
var filterDefinition = builder.Lt("MeasureTime", search.EndTime);//<
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
|
||||
var filter = builder.And(listfilters);
|
||||
if (listfilters.Count == 0)
|
||||
{
|
||||
filter = builder.Empty;
|
||||
}
|
||||
try
|
||||
{
|
||||
_bsonDocumentResultRepository.CollectionName = "MeasureTemperatureResult";
|
||||
|
||||
IFindFluent<BsonDocument, BsonDocument> rst = _bsonDocumentResultRepository.GetAllIncludeToFindFluent(filter);
|
||||
var sorter = Builders<BsonDocument>.Sort;
|
||||
var sortDefine = sorter.Descending("MeasureTime");
|
||||
rst = rst.Sort(sortDefine);
|
||||
requestPageResult.TotalCount = (int)rst.CountDocuments();
|
||||
var skipCount = searchCondition.PageIndex <= 0
|
||||
? -1
|
||||
: (searchCondition.PageIndex - 1) * searchCondition.PageSize;
|
||||
if (skipCount != -1)
|
||||
rst = rst.Skip(skipCount).Limit(searchCondition.PageSize);
|
||||
outputs = rst.ToEnumerable().Select(c => new MeasureTemperatureResultOutput
|
||||
{
|
||||
Id = c["_id"].AsGuid,
|
||||
MeasureTemperaturePointId = c["MeasureTemperaturePointId"].AsGuid,
|
||||
Number = c["Number"].ToInt32(),
|
||||
Name = c["Name"]?.ToString(),
|
||||
TemperatureValue = (float)(c["TemperatureValue"]?.AsNullableDouble == null ? 0.0 : c["TemperatureValue"]?.AsNullableDouble),
|
||||
Message = c["Message"]?.ToString(),
|
||||
MeasureTime = c["MeasureTime"]?.ToNullableLocalTime(),
|
||||
Status = c["Status"].ToInt32(),
|
||||
PresetPointId = c["PresetPointId"]?.AsNullableGuid,
|
||||
PresetPointName = c["PresetPointName"]?.ToString(),
|
||||
EquipmentTypeId = c["EquipmentTypeId"]?.AsNullableGuid,
|
||||
EquipmentTypeName = c["EquipmentTypeName"]?.ToString(),
|
||||
EquipmentInfoId = c["EquipmentInfoId"]?.AsNullableGuid,
|
||||
EquipmentInfoName = c["EquipmentInfoName"]?.ToString(),
|
||||
}).ToList();
|
||||
requestPageResult.ResultData = outputs;
|
||||
requestPageResult.Flag = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Error(this.GetType(), "测温结果服务", ex);
|
||||
}
|
||||
return requestPageResult;
|
||||
return FindMeasureTempertureResults(searchCondition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -651,5 +592,284 @@ namespace YunDa.SOMS.MongoDB.Application.MeasuresTemperature
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询温度测量结果(热成像设备)
|
||||
/// </summary>
|
||||
/// <param name="searchCondition">查询条件</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost, Audited, Description("查询温度测量结果(热成像设备)")]
|
||||
[Abp.Domain.Uow.UnitOfWork(true)]
|
||||
public RequestPageResult<MeasureTemperatureResultOutput> FindMeasureTempertureResults(PageSearchCondition<MeasureTemperatureResultSearchConditonInput> searchCondition)
|
||||
{
|
||||
var search = searchCondition.SearchCondition;
|
||||
RequestPageResult<MeasureTemperatureResultOutput> requestPageResult = new RequestPageResult<MeasureTemperatureResultOutput>();
|
||||
List<MeasureTemperatureResultOutput> outputs = new List<MeasureTemperatureResultOutput>();
|
||||
|
||||
try
|
||||
{
|
||||
// 第一步:从预置点仓储中筛选出 DevType 为 12 或 22 的热成像预置点
|
||||
var thermalPresetPoints = _presetPointRepository
|
||||
.GetAllIncluding(p => p.VideoDev, p => p.EquipmentInfo, p => p.EquipmentType)
|
||||
.Where(p => p.VideoDev != null &&
|
||||
(p.VideoDev.DevType == VideoDevTypeEnum.热成像枪机_热成像 ||
|
||||
p.VideoDev.DevType == VideoDevTypeEnum.热成像球机_热成像))
|
||||
.ToList();
|
||||
|
||||
if (thermalPresetPoints.Count == 0)
|
||||
{
|
||||
// 如果没有符合条件的预置点,返回空结果
|
||||
requestPageResult.ResultData = outputs;
|
||||
requestPageResult.TotalCount = 0;
|
||||
requestPageResult.Flag = true;
|
||||
return requestPageResult;
|
||||
}
|
||||
|
||||
// 获取设备信息(如果指定了设备ID)
|
||||
EquipmentInfo equipment = null;
|
||||
if (search.EquipmentInfoId.HasValue)
|
||||
{
|
||||
equipment = _equipmentInfoRepository.GetAll().FirstOrDefault(t => t.Id == search.EquipmentInfoId);
|
||||
}
|
||||
|
||||
// 第二步:构建 MongoDB 查询过滤器
|
||||
var builder = Builders<BsonDocument>.Filter;
|
||||
var listfilters = new List<FilterDefinition<BsonDocument>>();
|
||||
|
||||
// 添加时间范围过滤条件
|
||||
if (search.StartTime.HasValue)
|
||||
{
|
||||
var filterDefinition = builder.Gte("Time", search.StartTime);
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now - TimeSpan.FromDays(3);
|
||||
var f = builder.Gte("Time", date);
|
||||
listfilters.Add(f);
|
||||
}
|
||||
|
||||
if (search.EndTime.HasValue)
|
||||
{
|
||||
var filterDefinition = builder.Lt("Time", search.EndTime);
|
||||
listfilters.Add(filterDefinition);
|
||||
}
|
||||
else
|
||||
{
|
||||
DateTime date = DateTime.Now;
|
||||
var f = builder.Lte("Time", date);
|
||||
listfilters.Add(f);
|
||||
}
|
||||
|
||||
var filter = builder.And(listfilters);
|
||||
if (listfilters.Count == 0)
|
||||
{
|
||||
filter = builder.Empty;
|
||||
}
|
||||
|
||||
// 第三步:从 OriginalInspectionStoreResult 集合查询数据
|
||||
_bsonDocumentResultRepository.CollectionName = nameof(OriginalInspectionStoreResult);
|
||||
|
||||
var sorter = Builders<BsonDocument>.Sort;
|
||||
var sortDefine = sorter.Descending("Time");
|
||||
|
||||
var originalDataList = _bsonDocumentResultRepository.GetAllIncludeToFindFluent(filter, sort: sortDefine)
|
||||
.ToList();
|
||||
|
||||
var originalData = originalDataList.Select(t => BsonSerializer.Deserialize<OriginalInspectionStoreResult>(t));
|
||||
|
||||
// 第四步:创建查找字典优化性能
|
||||
var presetDict = thermalPresetPoints
|
||||
.GroupBy(p => p.VideoDevId)
|
||||
.ToDictionary(g => g.Key,
|
||||
g => g.DistinctBy(p => p.Number)
|
||||
.ToDictionary(p => p.Number));
|
||||
|
||||
var cameraDict = thermalPresetPoints
|
||||
.Where(p => p.VideoDev != null)
|
||||
.Select(p => p.VideoDev)
|
||||
.DistinctBy(v => v.DevName)
|
||||
.ToDictionary(v => v.DevName);
|
||||
|
||||
// 第五步:处理每条原始巡检数据
|
||||
foreach (var data in originalData)
|
||||
{
|
||||
// 1. 查找摄像头
|
||||
if (!cameraDict.TryGetValue(data.CamName, out var camera))
|
||||
continue;
|
||||
|
||||
// 2. 解析预置码
|
||||
if (!int.TryParse(data.PresetCode, out int presetCode))
|
||||
continue;
|
||||
|
||||
// 3. 查找预置点
|
||||
if (!presetDict.TryGetValue(camera.Id, out var devicePresets) ||
|
||||
!devicePresets.TryGetValue(presetCode, out var preset))
|
||||
continue;
|
||||
|
||||
// 4. 设备过滤(如果指定了设备ID)
|
||||
if (search.EquipmentInfoId.HasValue)
|
||||
{
|
||||
if (preset.EquipmentInfoId == null)
|
||||
{
|
||||
// 如果预置点没有关联设备,通过设备名称匹配
|
||||
if (equipment != null && !string.IsNullOrEmpty(data.EquipmentInfoName))
|
||||
{
|
||||
if (!data.EquipmentInfoName.Contains(equipment.Name) &&
|
||||
CalculateSimilarity(data.EquipmentInfoName, equipment.Name) < 0.8)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (preset.EquipmentInfoId != search.EquipmentInfoId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 解析温度数据
|
||||
var temperatureResults = ParseTemperatureFromResult(data, preset);
|
||||
|
||||
// 6. 名称过滤(如果指定了名称)
|
||||
if (!string.IsNullOrWhiteSpace(search.Name))
|
||||
{
|
||||
temperatureResults = temperatureResults
|
||||
.Where(t => t.Name != null && t.Name.Contains(search.Name))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// 7. 添加到输出列表
|
||||
outputs.AddRange(temperatureResults);
|
||||
}
|
||||
|
||||
// 第六步:排序和分页
|
||||
outputs = outputs.OrderByDescending(o => o.MeasureTime).ToList();
|
||||
requestPageResult.TotalCount = outputs.Count;
|
||||
|
||||
var skipCount = searchCondition.PageIndex <= 0
|
||||
? 0
|
||||
: (searchCondition.PageIndex - 1) * searchCondition.PageSize;
|
||||
|
||||
if (searchCondition.PageSize > 0)
|
||||
{
|
||||
outputs = outputs.Skip(skipCount).Take(searchCondition.PageSize).ToList();
|
||||
}
|
||||
|
||||
requestPageResult.ResultData = outputs;
|
||||
requestPageResult.Flag = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Error(this.GetType(), "测温结果服务-查询热成像设备测温结果", ex);
|
||||
requestPageResult.Flag = false;
|
||||
requestPageResult.Message = ex.Message;
|
||||
}
|
||||
|
||||
return requestPageResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从巡检结果数据中解析温度数据
|
||||
/// </summary>
|
||||
/// <param name="data">原始巡检结果数据</param>
|
||||
/// <param name="preset">预置点信息</param>
|
||||
/// <returns>温度测量结果列表</returns>
|
||||
private List<MeasureTemperatureResultOutput> ParseTemperatureFromResult(OriginalInspectionStoreResult data, PresetPoint preset)
|
||||
{
|
||||
var results = new List<MeasureTemperatureResultOutput>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(data.Result))
|
||||
return results;
|
||||
|
||||
try
|
||||
{
|
||||
// 解析测量时间
|
||||
DateTime measureTime = data.Time;
|
||||
if (!string.IsNullOrWhiteSpace(data.CaptureTime))
|
||||
{
|
||||
if (DateTime.TryParse(data.CaptureTime, out DateTime captureTime))
|
||||
{
|
||||
measureTime = captureTime;
|
||||
}
|
||||
}
|
||||
|
||||
// 解析状态
|
||||
int status = 0;
|
||||
if (!string.IsNullOrWhiteSpace(data.Status))
|
||||
{
|
||||
int.TryParse(data.Status, out status);
|
||||
}
|
||||
|
||||
// 分割多个测温点数据(支持中英文逗号分隔)
|
||||
var analysisResultArr = data.Result.Split(new[] { ",", ",", "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
int pointNumber = 1;
|
||||
foreach (var item in analysisResultArr)
|
||||
{
|
||||
// 分割名称和温度值(支持中英文冒号)
|
||||
var parts = item.Split(new[] { ":", ":" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
string pointName = parts[0].Trim();
|
||||
string valueStr = parts[1].Trim();
|
||||
|
||||
// 使用正则表达式提取温度数值
|
||||
string pattern = @"\d+(?:\.\d+)?";
|
||||
Match match = Regex.Match(valueStr, pattern);
|
||||
|
||||
if (match.Success && float.TryParse(match.Value, out float temperatureValue))
|
||||
{
|
||||
var output = new MeasureTemperatureResultOutput
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
MeasureTemperaturePointId = Guid.Empty, // 原始数据没有测温点ID
|
||||
Number = pointNumber++,
|
||||
Name = pointName,
|
||||
TemperatureValue = temperatureValue,
|
||||
Message = data.Message ?? "热成像测温",
|
||||
MeasureTime = measureTime,
|
||||
Status = status,
|
||||
PresetPointId = preset.Id,
|
||||
PresetPointName = preset.Name,
|
||||
EquipmentTypeId = preset.EquipmentTypeId,
|
||||
EquipmentTypeName = preset.EquipmentType?.Name,
|
||||
EquipmentInfoId = preset.EquipmentInfoId,
|
||||
EquipmentInfoName = preset.EquipmentInfo?.Name
|
||||
};
|
||||
|
||||
results.Add(output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log4Helper.Error(this.GetType(), $"解析温度数据失败: {data.Result}", ex);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算字符串相似度
|
||||
/// </summary>
|
||||
private double CalculateSimilarity(string source, string target)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(target))
|
||||
return 0;
|
||||
|
||||
// 简单的子串匹配比例
|
||||
int matchCount = 0;
|
||||
foreach (char c in target)
|
||||
{
|
||||
if (source.Contains(c))
|
||||
matchCount++;
|
||||
}
|
||||
return (double)matchCount / target.Length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -159,62 +159,92 @@ namespace ToolLibrary
|
||||
/// </summary>
|
||||
/// <param name="url">请求连接</param>
|
||||
/// <param name="dicParams">请求参数</param>
|
||||
/// <param name="retryCount">总尝试次数(包括初始尝试),默认3次</param>
|
||||
/// <param name="func">重试延迟函数</param>
|
||||
/// <param name="accessToken">访问令牌</param>
|
||||
/// <returns>根据泛型返回响应值</returns>
|
||||
public static T HttpPostRequestWithRetry<T>(string url,
|
||||
object dicParams = null,
|
||||
int retryCount = 10,
|
||||
int retryCount = 3,
|
||||
Func<int, TimeSpan> func = null,
|
||||
string accessToken = null
|
||||
)
|
||||
{
|
||||
Stream requestStream = null;
|
||||
if (func == null)
|
||||
{
|
||||
func = count => TimeSpan.FromSeconds(count * count);
|
||||
// 使用更合理的延迟策略:2秒、4秒、6秒...最多10秒
|
||||
func = count => TimeSpan.FromSeconds(Math.Min(count * 2, 10));
|
||||
}
|
||||
|
||||
// 配置重试策略:retryCount-1 表示在初始尝试失败后的重试次数
|
||||
var policy = Policy
|
||||
.Handle<Exception>()
|
||||
.WaitAndRetry(
|
||||
retryCount - 1,
|
||||
func,
|
||||
(exception, timeSpan, retryAttempt, context) =>
|
||||
{
|
||||
LogHelper.Log4Helper.Error(typeof(HttpClient),
|
||||
$"HTTP请求失败,第{retryAttempt}次重试,url:{url},延迟{timeSpan.TotalSeconds}秒",
|
||||
exception);
|
||||
}
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
HttpWebRequest request = GetHttpWebRequest(url);
|
||||
request.UseDefaultCredentials = true;
|
||||
//request.Timeout = 3000;
|
||||
request.Method = "POST";
|
||||
request.Accept = "application/json, text/javascript, */*"; //"text/html, application/xhtml+xml, */*";
|
||||
request.ContentType = "application/json;charset=UTF-8";
|
||||
//request.Headers.Add("ContentType", "application/json; charset=utf-8");
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
request.Headers.Add("Authorization", "Bearer" + " " + accessToken);
|
||||
if (dicParams != null)
|
||||
// 在重试策略中执行HTTP请求,每次重试都创建新的连接
|
||||
var result = policy.Execute(() =>
|
||||
{
|
||||
var paramStr = ObjectToJsonStr(dicParams);
|
||||
byte[] buffer = encoding.GetBytes(paramStr);
|
||||
request.ContentLength = buffer.Length;
|
||||
requestStream = request.GetRequestStream();
|
||||
requestStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
var policy = Policy
|
||||
.Handle<Exception>()
|
||||
.WaitAndRetry(
|
||||
retryCount, func,
|
||||
(exception, timeSpan, retryCount, context) =>
|
||||
HttpWebRequest request = null;
|
||||
Stream requestStream = null;
|
||||
try
|
||||
{
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
request = GetHttpWebRequest(url);
|
||||
request.UseDefaultCredentials = true;
|
||||
request.Timeout = 120000; // 120秒超时
|
||||
request.Method = "POST";
|
||||
request.Accept = "application/json, text/javascript, */*";
|
||||
request.ContentType = "application/json;charset=UTF-8";
|
||||
|
||||
if (!string.IsNullOrEmpty(accessToken))
|
||||
request.Headers.Add("Authorization", "Bearer" + " " + accessToken);
|
||||
|
||||
if (dicParams != null)
|
||||
{
|
||||
LogHelper.Log4Helper.Error(typeof(HttpClient), $"第{retryCount}重试,url:{url}", exception.InnerException);
|
||||
var paramStr = ObjectToJsonStr(dicParams);
|
||||
byte[] buffer = encoding.GetBytes(paramStr);
|
||||
request.ContentLength = buffer.Length;
|
||||
requestStream = request.GetRequestStream();
|
||||
requestStream.Write(buffer, 0, buffer.Length);
|
||||
requestStream.Close();
|
||||
requestStream = null; // 标记已关闭,避免finally中重复关闭
|
||||
}
|
||||
);
|
||||
var resulut = policy.Execute(() => GetResponseValue<T>(request));
|
||||
return resulut;
|
||||
|
||||
return GetResponseValue<T>(request);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 确保资源被释放
|
||||
if (requestStream != null)
|
||||
{
|
||||
try { requestStream.Close(); } catch { }
|
||||
}
|
||||
if (request != null)
|
||||
{
|
||||
try { request.Abort(); } catch { } // 中止请求以释放连接
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Log4Helper.Error(typeof(HttpWebRequest), "请求地址" + url, ex);
|
||||
LogHelper.Log4Helper.Error(typeof(HttpWebRequest),
|
||||
$"HTTP请求最终失败,已重试{retryCount - 1}次,请求地址:{url}", ex);
|
||||
throw; // 重新抛出异常,让调用方知道请求失败
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (requestStream != null)
|
||||
requestStream.Close();
|
||||
}
|
||||
return default(T);
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// http请求,POST方式,文件断点续传
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user