完成巡检结果的获取

This commit is contained in:
guorui 2025-11-26 15:21:40 +08:00
parent b92ddc5c86
commit 4d4da8ac2b
17 changed files with 1581 additions and 383 deletions

View File

@ -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>>();

View File

@ -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>();

View File

@ -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
{

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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(), "开始构建数据字典...");

View File

@ -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;

View File

@ -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";
@ -67,8 +73,11 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
, IRedisRepository<object, string> redisRepository
, IAppServiceConfiguration appServiceConfiguration
, IRepository<ImProtectDevice, string> imProtectDevice
, SOMSAuditingStore SOMSAuditingStore
, 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,61 +139,91 @@ 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
{
}
}

View File

@ -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)
{
@ -182,6 +185,7 @@ namespace YunDa.SOMS.Application.GeneralInformation
}
var telemeteringRepo = query.OrderBy(t => t.SeqNo).ToList();
var telemeteringExcelList = ObjectMapper.Map<List<TelemeteringConfigurationExcel>>(telemeteringRepo);
@ -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)
@ -385,9 +446,30 @@ namespace YunDa.SOMS.Application.GeneralInformation
ClumnWidthList = new List<int> { 36, 8, 15, 12, 15, 15, 15, 10, 10, 10, 12, 10, 10, 10, 10, 10, 10, 10, 8, 10, 10 },
AutoClumnWidths = false
};
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))
{
@ -873,7 +1029,11 @@ namespace YunDa.SOMS.Application.GeneralInformation
existingConfig.PrimaryEquipmentInfoId = primaryEquipment.Id;
}
}
}
else
{
existingConfig.PrimaryEquipmentInfoId = null;
}
// 设置数据来源

View File

@ -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>
/// 周例会决策建议
/// AI处理结果
/// </summary>
public string WeeklyMeetingRecommendation { get; set; }
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>();
}
}

View File

@ -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">

View File

@ -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,19 +528,19 @@ 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);
}
}
}
rst.ResultData = ObjectMapper.Map<List<InspectionItemResultOutput>>(list);
//获取条件下所有数量
rst.TotalCount = rst.ResultData.Count;
rst.Flag = true;
}
}
}
@ -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;
// 4. 检查设备ID
if (preset.EquipmentInfoId != searchCondition.EquipmentInfoId)
continue;
if (preset.EquipmentInfoId == null)
{
// 5. 设备名称匹配检查(60%相似度)
bool isNameMatch = false;
// 5. 构建结果对象
if (data.Result.Contains(equipment.Name))
{
// 直接包含则通过
isNameMatch = true;
}
else
{
// 计算相似度(60%阈值)
double similarity = CalculateSimilarity(data.Result, equipment.Name);
if (similarity >= 0.8)
{
isNameMatch = true;
}
}
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]

View File

@ -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,
@ -846,14 +856,8 @@ 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)

View File

@ -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,19 +1273,42 @@ 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);
}
}
// 生成报告
var output = await GenerateWeeklyReportAsync(startDate, endDate, cancellationToken);
// 只有历史周才保存到缓存
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,

View File

@ -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;
}
}
}

View File

@ -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方式文件断点续传