868 lines
38 KiB
C#
868 lines
38 KiB
C#
using Abp.Application.Services.Dto;
|
||
using Abp.Domain.Repositories;
|
||
using Abp.ObjectMapping;
|
||
using Abp.Web.Models;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using System;
|
||
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;
|
||
using ToolLibrary.LogHelper;
|
||
using YunDa.SOMS.Application.Core;
|
||
using YunDa.SOMS.Application.Core.Helper;
|
||
using YunDa.SOMS.Application.Core.Session;
|
||
using YunDa.SOMS.Application.Core.SwaggerHelper;
|
||
using YunDa.SOMS.DataTransferObject;
|
||
using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo;
|
||
using YunDa.SOMS.Entities.DataMonitoring;
|
||
using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo;
|
||
using YunDa.SOMS.Entities.GeneralInformation;
|
||
|
||
namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
|
||
{
|
||
/// <summary>
|
||
/// 网线管理服务
|
||
/// </summary>
|
||
[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;
|
||
private readonly IRepository<TelesignalisationConfiguration, Guid> _telesignalisationConfigurationRepository;
|
||
private readonly HttpClient _httpClient;
|
||
private readonly IConfiguration _configuration;
|
||
private readonly BeijingYounuoApiAppService _beijingYounuoApiAppService;
|
||
public NetworkCableAppService(
|
||
ISessionAppService sessionAppService,
|
||
IRepository<NetworkCable, Guid> networkCableRepository,
|
||
IRepository<TelemeteringConfiguration, Guid> telemeteringConfigurationRepository,
|
||
IRepository<TelesignalisationConfiguration, Guid> telesignalisationConfigurationRepository,
|
||
IRepository<EquipmentInfo, Guid> equipmentInfoRepository,
|
||
BeijingYounuoApiAppService beijingYounuoApiAppService,
|
||
HttpClient httpClient,
|
||
IConfiguration configuration)
|
||
: base(sessionAppService)
|
||
{
|
||
_networkCableRepository = networkCableRepository;
|
||
_equipmentInfoRepository = equipmentInfoRepository;
|
||
_telemeteringConfigurationRepository = telemeteringConfigurationRepository;
|
||
_telesignalisationConfigurationRepository = telesignalisationConfigurationRepository;
|
||
_httpClient = httpClient;
|
||
_configuration = configuration;
|
||
_beijingYounuoApiAppService = beijingYounuoApiAppService;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建网线
|
||
/// </summary>
|
||
public async Task<RequestResult<NetworkCableDto>> CreateAsync(CreateNetworkCableInput input, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
// 检查孪生体ID是否已存在
|
||
var existingEntity = await _networkCableRepository.FirstOrDefaultAsync(x => x.TwinId == input.TwinId);
|
||
if (existingEntity != null)
|
||
{
|
||
return RequestResult<NetworkCableDto>.CreateFailed($"孪生体ID '{input.TwinId}' 已存在");
|
||
}
|
||
|
||
var entity = new NetworkCable
|
||
{
|
||
CiCode = input.CiCode,
|
||
TwinId = input.TwinId,
|
||
P1CabinetName = input.P1CabinetName,
|
||
P1DeviceName = input.P1DeviceName,
|
||
P1DeviceNumber = input.P1DeviceNumber,
|
||
P1PortNumber = input.P1PortNumber,
|
||
P1InputPort = input.P1InputPort,
|
||
P2CabinetName = input.P2CabinetName,
|
||
P2DeviceName = input.P2DeviceName,
|
||
P2DeviceNumber = input.P2DeviceNumber,
|
||
P2PortNumber = input.P2PortNumber,
|
||
P2InputPort = input.P2InputPort,
|
||
WiringDirection = input.WiringDirection,
|
||
LogicalExpression = input.LogicalExpression,
|
||
ImpactScope = input.ImpactScope,
|
||
EquipmentInfoId = input.EquipmentInfoId,
|
||
LinkageData = input.LinkageData,
|
||
IsActive = true,
|
||
CreationTime = DateTime.Now
|
||
};
|
||
|
||
var createdEntity = await _networkCableRepository.InsertAsync(entity);
|
||
await CurrentUnitOfWork.SaveChangesAsync();
|
||
|
||
var result = ObjectMapper.Map<NetworkCableDto>(createdEntity);
|
||
|
||
// 获取关联设备信息
|
||
if (createdEntity.EquipmentInfoId.HasValue)
|
||
{
|
||
var equipmentInfo = await _equipmentInfoRepository.GetAsync(createdEntity.EquipmentInfoId.Value);
|
||
result.EquipmentInfoName = equipmentInfo?.Name;
|
||
}
|
||
|
||
return RequestResult<NetworkCableDto>.CreateSuccess(result, "网线创建成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"创建网线失败: {ex.Message}", ex);
|
||
return RequestResult<NetworkCableDto>.CreateFailed($"创建网线失败: {ex.Message}");
|
||
}
|
||
}
|
||
[HttpPost]
|
||
/// <summary>
|
||
/// 更新网线
|
||
/// </summary>
|
||
public async Task<RequestResult<NetworkCableDto>> UpdateAsync(UpdateNetworkCableInput input, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var entity = await _networkCableRepository.GetAsync(input.Id);
|
||
if (entity == null)
|
||
{
|
||
return RequestResult<NetworkCableDto>.CreateFailed("网线不存在");
|
||
}
|
||
|
||
// 检查孪生体ID是否已被其他记录使用
|
||
if (!string.IsNullOrEmpty(input.TwinId) && input.TwinId != entity.TwinId)
|
||
{
|
||
var existingEntity = await _networkCableRepository.FirstOrDefaultAsync(x => x.TwinId == input.TwinId && x.Id != input.Id);
|
||
if (existingEntity != null)
|
||
{
|
||
return RequestResult<NetworkCableDto>.CreateFailed($"孪生体ID '{input.TwinId}' 已被其他记录使用");
|
||
}
|
||
}
|
||
|
||
// 更新属性
|
||
if (!string.IsNullOrEmpty(input.CiCode)) entity.CiCode = input.CiCode;
|
||
if (!string.IsNullOrEmpty(input.TwinId)) entity.TwinId = input.TwinId;
|
||
if (!string.IsNullOrEmpty(input.P1CabinetName)) entity.P1CabinetName = input.P1CabinetName;
|
||
if (!string.IsNullOrEmpty(input.P1DeviceName)) entity.P1DeviceName = input.P1DeviceName;
|
||
if (!string.IsNullOrEmpty(input.P1DeviceNumber)) entity.P1DeviceNumber = input.P1DeviceNumber;
|
||
if (!string.IsNullOrEmpty(input.P1PortNumber)) entity.P1PortNumber = input.P1PortNumber;
|
||
if (!string.IsNullOrEmpty(input.P1InputPort)) entity.P1InputPort = input.P1InputPort;
|
||
if (!string.IsNullOrEmpty(input.P2CabinetName)) entity.P2CabinetName = input.P2CabinetName;
|
||
if (!string.IsNullOrEmpty(input.P2DeviceName)) entity.P2DeviceName = input.P2DeviceName;
|
||
if (!string.IsNullOrEmpty(input.P2DeviceNumber)) entity.P2DeviceNumber = input.P2DeviceNumber;
|
||
if (!string.IsNullOrEmpty(input.P2PortNumber)) entity.P2PortNumber = input.P2PortNumber;
|
||
if (!string.IsNullOrEmpty(input.P2InputPort)) entity.P2InputPort = input.P2InputPort;
|
||
if (!string.IsNullOrEmpty(input.WiringDirection)) entity.WiringDirection = input.WiringDirection;
|
||
if (!string.IsNullOrEmpty(input.LogicalExpression)) entity.LogicalExpression = input.LogicalExpression;
|
||
if (!string.IsNullOrEmpty(input.ImpactScope)) entity.ImpactScope = input.ImpactScope;
|
||
if (input.EquipmentInfoId.HasValue) entity.EquipmentInfoId = input.EquipmentInfoId;
|
||
if (!string.IsNullOrEmpty(input.LinkageData)) entity.LinkageData = input.LinkageData;
|
||
if (input.IsActive.HasValue) entity.IsActive = input.IsActive.Value;
|
||
|
||
entity.LastModificationTime = DateTime.Now;
|
||
|
||
await _networkCableRepository.UpdateAsync(entity);
|
||
await CurrentUnitOfWork.SaveChangesAsync();
|
||
|
||
var result = ObjectMapper.Map<NetworkCableDto>(entity);
|
||
|
||
// 获取关联设备信息
|
||
if (entity.EquipmentInfoId.HasValue)
|
||
{
|
||
var equipmentInfo = await _equipmentInfoRepository.GetAsync(entity.EquipmentInfoId.Value);
|
||
result.EquipmentInfoName = equipmentInfo?.Name;
|
||
}
|
||
|
||
return RequestResult<NetworkCableDto>.CreateSuccess(result, "网线更新成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"更新网线失败: {ex.Message}", ex);
|
||
return RequestResult<NetworkCableDto>.CreateFailed($"更新网线失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除网线
|
||
/// </summary>
|
||
public async Task<RequestEasyResult> DeleteAsync(Guid id, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var entity = await _networkCableRepository.GetAsync(id);
|
||
if (entity == null)
|
||
{
|
||
return RequestEasyResult.CreateFailed("网线不存在");
|
||
}
|
||
|
||
await _networkCableRepository.DeleteAsync(entity);
|
||
await CurrentUnitOfWork.SaveChangesAsync();
|
||
|
||
return RequestEasyResult.CreateSuccess("网线删除成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"删除网线失败: {ex.Message}", ex);
|
||
return RequestEasyResult.CreateFailed($"删除网线失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取网线详情
|
||
/// </summary>
|
||
public async Task<RequestResult<NetworkCableDto>> GetAsync(Guid id, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var entity = await _networkCableRepository.GetAsync(id);
|
||
if (entity == null)
|
||
{
|
||
return RequestResult<NetworkCableDto>.CreateFailed("网线不存在");
|
||
}
|
||
|
||
var result = ObjectMapper.Map<NetworkCableDto>(entity);
|
||
|
||
// 获取关联设备信息
|
||
if (entity.EquipmentInfoId.HasValue)
|
||
{
|
||
var equipmentInfo = await _equipmentInfoRepository.GetAsync(entity.EquipmentInfoId.Value);
|
||
result.EquipmentInfoName = equipmentInfo?.Name;
|
||
}
|
||
|
||
return RequestResult<NetworkCableDto>.CreateSuccess(result);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"获取网线详情失败: {ex.Message}", ex);
|
||
return RequestResult<NetworkCableDto>.CreateFailed($"获取网线详情失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取网线列表
|
||
/// </summary>
|
||
[HttpPost]
|
||
[AllowAnonymous]
|
||
[ShowApi]
|
||
public async Task<RequestPageResult<NetworkCableDto>> GetListAsync(GetNetworkCableInput input, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var query = _networkCableRepository.GetAll();
|
||
|
||
// 应用筛选条件
|
||
if (!string.IsNullOrEmpty(input.CiCode))
|
||
{
|
||
query = query.Where(x => x.CiCode.Contains(input.CiCode));
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(input.TwinId))
|
||
{
|
||
query = query.Where(x => x.TwinId.Contains(input.TwinId));
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(input.P1DeviceNumber))
|
||
{
|
||
query = query.Where(x => x.P1DeviceNumber.Contains(input.P1DeviceNumber));
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(input.P2DeviceNumber))
|
||
{
|
||
query = query.Where(x => x.P2DeviceNumber.Contains(input.P2DeviceNumber));
|
||
}
|
||
|
||
if (input.EquipmentInfoId.HasValue)
|
||
{
|
||
query = query.Where(x => x.EquipmentInfoId == input.EquipmentInfoId);
|
||
}
|
||
|
||
if (input.IsActive.HasValue)
|
||
{
|
||
query = query.Where(x => x.IsActive == input.IsActive);
|
||
}
|
||
|
||
// 获取总数
|
||
var totalCount = await query.CountAsync();
|
||
|
||
// 分页
|
||
var entities = await query
|
||
.OrderByDescending(x => x.CreationTime)
|
||
.ToListAsync();
|
||
|
||
var dtos = ObjectMapper.Map<List<NetworkCableDto>>(entities);
|
||
|
||
// 获取关联设备信息
|
||
var equipmentIds = entities.Where(x => x.EquipmentInfoId.HasValue).Select(x => x.EquipmentInfoId.Value).Distinct().ToList();
|
||
if (equipmentIds.Any())
|
||
{
|
||
var equipmentInfos = await _equipmentInfoRepository.GetAll()
|
||
.Where(x => equipmentIds.Contains(x.Id))
|
||
.ToDictionaryAsync(x => x.Id, x => x.Name);
|
||
|
||
foreach (var dto in dtos)
|
||
{
|
||
if (dto.EquipmentInfoId.HasValue && equipmentInfos.ContainsKey(dto.EquipmentInfoId.Value))
|
||
{
|
||
dto.EquipmentInfoName = equipmentInfos[dto.EquipmentInfoId.Value];
|
||
}
|
||
}
|
||
}
|
||
|
||
return RequestPageResult<NetworkCableDto>.CreateSuccess(dtos, totalCount, input.PageIndex, input.PageSize);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"获取网线列表失败: {ex.Message}", ex);
|
||
return RequestPageResult<NetworkCableDto>.CreateFailed($"获取网线列表失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 批量创建网线
|
||
/// </summary>
|
||
public async Task<RequestEasyResult> BatchCreateAsync(BatchCreateNetworkCableInput input, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var createInputs = JsonConvert.DeserializeObject<List<CreateNetworkCableInput>>(input.JsonArrayData);
|
||
if (createInputs == null || !createInputs.Any())
|
||
{
|
||
return RequestEasyResult.CreateFailed("批量创建数据为空");
|
||
}
|
||
|
||
var successCount = 0;
|
||
var failedCount = 0;
|
||
var errors = new List<string>();
|
||
|
||
foreach (var createInput in createInputs)
|
||
{
|
||
var result = await CreateAsync(createInput, cancellationToken);
|
||
if (result.Flag)
|
||
{
|
||
successCount++;
|
||
}
|
||
else
|
||
{
|
||
failedCount++;
|
||
errors.Add($"孪生体ID '{createInput.TwinId}': {result.Message}");
|
||
}
|
||
}
|
||
|
||
var message = $"批量创建完成,成功: {successCount},失败: {failedCount}";
|
||
if (errors.Any())
|
||
{
|
||
message += $"。错误详情: {string.Join("; ", errors)}";
|
||
}
|
||
|
||
return failedCount == 0
|
||
? RequestEasyResult.CreateSuccess(message)
|
||
: RequestEasyResult.CreateFailed(message);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"批量创建网线失败: {ex.Message}", ex);
|
||
return RequestEasyResult.CreateFailed($"批量创建网线失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激活/停用网线
|
||
/// </summary>
|
||
public async Task<RequestEasyResult> SetActiveAsync(Guid id, bool isActive, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var entity = await _networkCableRepository.GetAsync(id);
|
||
if (entity == null)
|
||
{
|
||
return RequestEasyResult.CreateFailed("网线不存在");
|
||
}
|
||
|
||
entity.IsActive = isActive;
|
||
entity.LastModificationTime = DateTime.Now;
|
||
|
||
await _networkCableRepository.UpdateAsync(entity);
|
||
await CurrentUnitOfWork.SaveChangesAsync();
|
||
|
||
return RequestEasyResult.CreateSuccess($"网线{(isActive ? "激活" : "停用")}成功");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"设置网线状态失败: {ex.Message}", ex);
|
||
return RequestEasyResult.CreateFailed($"设置网线状态失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 模拟断线功能 - 根据孪生体ID生成处置意见和影响范围
|
||
/// </summary>
|
||
[AllowAnonymous]
|
||
[ShowApi]
|
||
[HttpGet]
|
||
public async Task<RequestResult<DisconnectionSimulationResult>> SimulateDisconnectionAsync(string twinId, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
|
||
if (string.IsNullOrWhiteSpace(twinId))
|
||
{
|
||
return RequestResult<DisconnectionSimulationResult>.CreateFailed("孪生体ID不能为空");
|
||
}
|
||
|
||
// 查找网线配置
|
||
var networkCable = await _networkCableRepository.GetAll()
|
||
.FirstOrDefaultAsync(x => x.TwinId == twinId, cancellationToken);
|
||
|
||
if (networkCable == null)
|
||
{
|
||
return RequestResult<DisconnectionSimulationResult>.CreateFailed($"未找到孪生体ID为 {twinId} 的网线配置");
|
||
}
|
||
|
||
// 生成处置意见
|
||
var disposalAdvice = GenerateNetworkCableDisposalAdvice(networkCable);
|
||
|
||
// 生成影响范围
|
||
var (impactScopeField, impactScopeDescription) = GenerateNetworkCableImpactScope(networkCable);
|
||
|
||
var result = new DisconnectionSimulationResult
|
||
{
|
||
TwinId = twinId,
|
||
DisposalAdvice = disposalAdvice,
|
||
ImpactScopeField = impactScopeField,
|
||
ImpactScopeDescription = impactScopeDescription,
|
||
ConnectionType = "网线",
|
||
P1EndInfo = new ConnectionEndInfo
|
||
{
|
||
CabinetName = networkCable.P1CabinetName,
|
||
DeviceName = networkCable.P1DeviceName,
|
||
DeviceNumber = networkCable.P1DeviceNumber,
|
||
PortNumber = networkCable.P1PortNumber,
|
||
InputPort = networkCable.P1InputPort
|
||
},
|
||
P2EndInfo = new ConnectionEndInfo
|
||
{
|
||
CabinetName = networkCable.P2CabinetName,
|
||
DeviceName = networkCable.P2DeviceName,
|
||
DeviceNumber = networkCable.P2DeviceNumber,
|
||
PortNumber = networkCable.P2PortNumber,
|
||
InputPort = networkCable.P2InputPort
|
||
}
|
||
};
|
||
|
||
return RequestResult<DisconnectionSimulationResult>.CreateSuccess(result);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"模拟网线断线失败: {ex.Message}", ex);
|
||
return RequestResult<DisconnectionSimulationResult>.CreateFailed($"模拟网线断线失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取网线断线模拟响应 - 返回简单格式的JSON响应
|
||
/// </summary>
|
||
[AllowAnonymous]
|
||
[ShowApi]
|
||
[HttpPost]
|
||
[DontWrapResult]
|
||
public async Task<SimpleDisconnectionResponse> GetSimulatedDisconnectionResponseAsync(object obj , CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
JObject jsonObject = JObject.Parse(obj.ToString());
|
||
string twinId = jsonObject["孪生体ID"]?.ToString();
|
||
if (string.IsNullOrWhiteSpace(twinId))
|
||
{
|
||
return new SimpleDisconnectionResponse
|
||
{
|
||
Code = 400,
|
||
Success = false,
|
||
Data = "孪生体ID不能为空"
|
||
};
|
||
}
|
||
|
||
// 查找网线配置
|
||
var networkCable = await _networkCableRepository.GetAll()
|
||
.FirstOrDefaultAsync(x => x.TwinId == twinId, cancellationToken);
|
||
|
||
if (networkCable == null)
|
||
{
|
||
return new SimpleDisconnectionResponse
|
||
{
|
||
Code = 404,
|
||
Success = false,
|
||
Data = $"未找到孪生体ID为 {twinId} 的网线配置"
|
||
};
|
||
}
|
||
|
||
string responseData;
|
||
|
||
// 尝试使用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 = "模拟网线断线",
|
||
Status = 1,
|
||
SourceIdentifier = networkCable.P1DeviceNumber,
|
||
Summary = "模拟网线断线",
|
||
TwinID = twinId,
|
||
};
|
||
await _beijingYounuoApiAppService.PushYounuoAlertAsync(alert);
|
||
|
||
return new SimpleDisconnectionResponse
|
||
{
|
||
Code = 200,
|
||
Success = true,
|
||
Data = responseData
|
||
};
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(this.GetType(), $"获取网线断线模拟响应失败: {ex.Message}", ex);
|
||
return new SimpleDisconnectionResponse
|
||
{
|
||
Code = 500,
|
||
Success = false,
|
||
Data = $"系统异常: {ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成网线处置意见
|
||
/// </summary>
|
||
private string GenerateNetworkCableDisposalAdvice(NetworkCable networkCable)
|
||
{
|
||
var advice = "处置意见:\n";
|
||
|
||
if (!string.IsNullOrEmpty(networkCable.P1DeviceName) && !string.IsNullOrEmpty(networkCable.P1PortNumber))
|
||
{
|
||
advice += $"1.检查{networkCable.P1DeviceName}设备的{networkCable.P1PortNumber}网络端口\n";
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(networkCable.P1CabinetName))
|
||
{
|
||
advice += $"2.检查{networkCable.P1CabinetName}对应的网线连接状态\n";
|
||
}
|
||
|
||
advice += "3.确认网线和接头是否松动或损坏\n";
|
||
|
||
if (!string.IsNullOrEmpty(networkCable.P2DeviceName) && !string.IsNullOrEmpty(networkCable.P2PortNumber))
|
||
{
|
||
advice += $"4.检查{networkCable.P2DeviceName}设备的{networkCable.P2PortNumber}网络端口\n";
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(networkCable.P2CabinetName))
|
||
{
|
||
advice += $"5.检查{networkCable.P2CabinetName}对应的网线连接状态";
|
||
}
|
||
|
||
return advice;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成网线影响范围
|
||
/// </summary>
|
||
private (string impactScopeField, string impactScopeDescription) GenerateNetworkCableImpactScope(NetworkCable networkCable)
|
||
{
|
||
var impactScopeField = "";
|
||
var impactScopeDescription = "网线连接异常,具体包括:\n";
|
||
var telemeterings = _telemeteringConfigurationRepository.GetAll();
|
||
var telesignals = _telesignalisationConfigurationRepository.GetAll();
|
||
// 解析影响范围字段,提取设备名称和地址
|
||
if (!string.IsNullOrEmpty(networkCable.ImpactScope))
|
||
{
|
||
impactScopeField = networkCable.ImpactScope;
|
||
|
||
// 解析影响范围中的设备和地址信息
|
||
var regex = new Regex(@"\{([^}]+)\}");
|
||
var matches = regex.Matches(networkCable.ImpactScope);
|
||
|
||
int index = 1;
|
||
foreach (Match match in matches)
|
||
{
|
||
var content = match.Groups[1].Value;
|
||
if (int.TryParse(content, out int dispatherAddress))
|
||
{
|
||
var telemetering = telemeterings.FirstOrDefault(t=>t.DispatcherAddress == dispatherAddress);
|
||
if (telemetering==null)
|
||
{
|
||
var telesignal = telesignals.FirstOrDefault(t => t.DispatcherAddress == dispatherAddress);
|
||
content = telesignal != null ? telesignal.Name : $"调度地址{dispatherAddress}";
|
||
}
|
||
else
|
||
{
|
||
content = telemetering.Name;
|
||
}// 数字地址
|
||
impactScopeDescription += $"{index}. {content} 数据异常\n";
|
||
}
|
||
else
|
||
{
|
||
// 设备名称
|
||
impactScopeDescription += $"{index}. {content}相关数据异常\n";
|
||
}
|
||
index++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果没有配置影响范围,基于P1和P2端信息生成
|
||
if (!string.IsNullOrEmpty(networkCable.P1DeviceName))
|
||
{
|
||
impactScopeField += $"{{{networkCable.P1DeviceName}}}";
|
||
impactScopeDescription += $"1. {networkCable.P1DeviceName}相关数据异常\n";
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(networkCable.P2DeviceName))
|
||
{
|
||
impactScopeField += $"{{{networkCable.P2DeviceName}}}";
|
||
impactScopeDescription += $"2. {networkCable.P2DeviceName}相关数据异常\n";
|
||
}
|
||
}
|
||
|
||
return (impactScopeField, impactScopeDescription.TrimEnd('\n'));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过孪生体代码获取设备信息ID
|
||
/// </summary>
|
||
/// <param name="code">孪生体代码</param>
|
||
/// <param name="cancellationToken">取消令牌</param>
|
||
/// <returns>设备信息ID</returns>
|
||
[HttpGet]
|
||
[AllowAnonymous]
|
||
[ShowApi]
|
||
public async Task<RequestResult<Guid>> GetTwIdAsync(string code, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(code))
|
||
{
|
||
return RequestResult<Guid>.CreateFailed("孪生体代码不能为空");
|
||
}
|
||
|
||
// 从配置中获取API基础URL
|
||
var baseUrl = _configuration.GetSection("SysBaseConfig:IsmsGateWayIp").Value;
|
||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||
{
|
||
Log4Helper.Warning(GetType(), "未配置IsmsGateWayIp,使用默认值");
|
||
baseUrl = "http://127.0.0.1:38094";
|
||
}
|
||
|
||
// 构建完整的API URL
|
||
var fullUrl = $"{baseUrl.TrimEnd('/')}/api/services/SOMS/RackEquipment/GetTwId?code={Uri.EscapeDataString(code)}";
|
||
|
||
Log4Helper.Info(GetType(), $"调用GetTwId API: {fullUrl}");
|
||
|
||
// 发送HTTP GET请求
|
||
var response = await _httpClient.GetAsync(fullUrl, cancellationToken).ConfigureAwait(false);
|
||
|
||
if (response.IsSuccessStatusCode)
|
||
{
|
||
var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||
Log4Helper.Debug(GetType(), $"GetTwId API响应: {responseContent}");
|
||
|
||
// 反序列化响应
|
||
var result = JsonConvert.DeserializeObject<RequestResult<Guid>>(responseContent);
|
||
|
||
if (result != null)
|
||
{
|
||
Log4Helper.Info(GetType(), $"成功获取TwId,代码: {code}, 设备信息ID: {result.ResultData}");
|
||
return result;
|
||
}
|
||
else
|
||
{
|
||
Log4Helper.Warning(GetType(), $"GetTwId API返回空结果,代码: {code}");
|
||
return RequestResult<Guid>.CreateFailed("API返回空结果");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var errorContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||
Log4Helper.Error(GetType(), $"GetTwId API调用失败,状态码: {response.StatusCode}, 错误内容: {errorContent}");
|
||
return RequestResult<Guid>.CreateFailed($"API调用失败: {response.StatusCode}");
|
||
}
|
||
}
|
||
catch (HttpRequestException ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"调用GetTwId API时发生HTTP请求异常,代码: {code}", ex);
|
||
return RequestResult<Guid>.CreateFailed($"网络请求异常: {ex.Message}");
|
||
}
|
||
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
|
||
{
|
||
Log4Helper.Error(GetType(), $"调用GetTwId API超时,代码: {code}", ex);
|
||
return RequestResult<Guid>.CreateFailed("API调用超时");
|
||
}
|
||
catch (TaskCanceledException ex) when (cancellationToken.IsCancellationRequested)
|
||
{
|
||
Log4Helper.Warning(GetType(), $"GetTwId API调用被取消,代码: {code}");
|
||
return RequestResult<Guid>.CreateFailed("请求已取消");
|
||
}
|
||
catch (JsonException ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"调用GetTwId API时发生JSON反序列化错误,代码: {code}", ex);
|
||
return RequestResult<Guid>.CreateFailed($"响应解析失败: {ex.Message}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log4Helper.Error(GetType(), $"调用GetTwId API时发生未知错误,代码: {code}", ex);
|
||
return RequestResult<Guid>.CreateFailed($"未知错误: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
#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
|
||
|
||
}
|
||
}
|