临时提交

This commit is contained in:
2025-08-25 20:16:57 +08:00
parent 645671e4b9
commit 8290c96b1b
20 changed files with 1024 additions and 448 deletions

View File

@@ -4,7 +4,7 @@ using System.Linq;
using AutoMapper;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DMS.Core.Interfaces;
using DMS.Core.Interfaces.Services;
using DMS.Core.Models;
using DMS.Helper;
using DMS.WPF.ViewModels.Items;

View File

@@ -0,0 +1,256 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DMS.Core.Models;
using DMS.Helper;
using DMS.WPF.ViewModels.Items;
using Opc.Ua.Client;
using System.Collections.ObjectModel;
namespace DMS.WPF.ViewModels.Dialogs;
public partial class ImportOpcUaDialogViewModel : DialogViewModelBase<List<VariableItemViewModel>>
{
[ObservableProperty]
private string _endpointUrl = "opc.tcp://127.0.0.1:4855"; // 默认值
//[ObservableProperty]
//private ObservableCollection<OpcUaNode> _opcUaNodes;
[ObservableProperty]
private ObservableCollection<Variable> _selectedNodeVariables;
public List<Variable> SelectedVariables { get; set; } = new List<Variable>();
[ObservableProperty]
private bool _selectAllVariables;
[ObservableProperty]
private bool _isConnected;
private Session _session;
public ImportOpcUaDialogViewModel()
{
//OpcUaNodes = new ObservableCollection<OpcUaNode>();
SelectedNodeVariables = new ObservableCollection<Variable>();
// Automatically connect when the ViewModel is created
//ConnectC.Execute(null);
}
[RelayCommand]
private async Task Connect()
{
try
{
// 断开现有连接
if (_session != null && _session.Connected)
{
await _session.CloseAsync();
_session.Dispose();
_session = null;
}
IsConnected = false;
SelectedNodeVariables.Clear();
//_session = await ServiceHelper.CreateOpcUaSessionAsync(EndpointUrl);
NotificationHelper.ShowSuccess($"已连接到 OPC UA 服务器: {EndpointUrl}");
IsConnected = true;
// 浏览根节点
//await BrowseNodes(OpcUaNodes, ObjectIds.ObjectsFolder);
}
catch (Exception ex)
{
IsConnected = false;
NotificationHelper.ShowError($"连接 OPC UA 服务器失败: {EndpointUrl} - {ex.Message}", ex);
}
}
/// <summary>
/// 处理来自服务器的数据变化通知
/// </summary>
private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
{
foreach (var value in item.DequeueValues())
{
Console.WriteLine(
$"[通知] {item.DisplayName}: {value.Value} | 时间戳: {value.SourceTimestamp.ToLocalTime()} | 状态: {value.StatusCode}");
}
}
//private async Task BrowseNodes(ObservableCollection<OpcUaNode> nodes, NodeId parentNodeId)
//{
// try
// {
// Opc.Ua.ReferenceDescriptionCollection references;
// byte[] continuationPoint = null;
// _session.Browse(
// null, // RequestHeader
// new ViewDescription(),
// parentNodeId,
// 0u,
// BrowseDirection.Forward,
// Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
// true,
// (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
// out continuationPoint,
// out references
// );
// foreach (var rd in references)
// {
// NodeType nodeType = NodeType.Folder; // 默认是文件夹
// if ((rd.NodeClass & NodeClass.Variable) != 0)
// {
// nodeType = NodeType.Variable;
// }
// else if ((rd.NodeClass & NodeClass.Object) != 0)
// {
// nodeType = NodeType.Object;
// }
// var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
// nodes.Add(opcUaNode);
// // 如果是文件夹或对象,添加一个虚拟子节点,用于懒加载
// if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
// {
// opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
// }
// }
// }
// catch (Exception ex)
// {
// NlogHelper.Error($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
// NotificationHelper.ShowError($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
// }
//}
//public async Task LoadNodeVariables(OpcUaNode node)
//{
//if (node.NodeType == NodeType.Variable)
//{
// // 如果是变量节点,直接显示它
// SelectedNodeVariables.Clear();
// SelectedNodeVariables.Add(new Variable
// {
// Name = node.DisplayName,
// NodeId = node.NodeId.ToString(),
// OpcUaNodeId = node.NodeId.ToString(),
// ProtocolType = ProtocolType.OpcUA,
// IsActive = true // 默认选中
// });
// return;
//}
//if (node.IsLoaded || node.IsLoading)
//{
// return; // 已经加载或正在加载
//}
//node.IsLoading = true;
//node.Children.Clear(); // 清除虚拟节点
//try
//{
// Opc.Ua.ReferenceDescriptionCollection references;
// byte[] continuationPoint = null;
// _session.Browse(
// null, // RequestHeader
// new ViewDescription(),
// node.NodeId,
// 0u,
// BrowseDirection.Forward,
// Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
// true,
// (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
// out continuationPoint,
// out references
// );
// foreach (var rd in references)
// {
// NodeType nodeType = NodeType.Folder;
// if ((rd.NodeClass & NodeClass.Variable) != 0)
// {
// nodeType = NodeType.Variable;
// }
// else if ((rd.NodeClass & NodeClass.Object) != 0)
// {
// nodeType = NodeType.Object;
// }
// var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
// node.Children.Add(opcUaNode);
// if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
// {
// opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
// }
// // 如果是变量,添加到右侧列表
// if (nodeType == NodeType.Variable)
// {
// // Read the DataType attribute
// ReadValueId readValueId = new ReadValueId
// {
// NodeId = opcUaNode.NodeId,
// AttributeId = Attributes.DataType,
// // You might need to specify IndexRange and DataEncoding if dealing with arrays or specific encodings
// };
// DataValueCollection results;
// DiagnosticInfoCollection diagnosticInfos;
// _session.Read(
// null, // RequestHeader
// 0, // MaxAge
// TimestampsToReturn.Source,
// new ReadValueIdCollection { readValueId },
// out results,
// out diagnosticInfos
// );
// string dataType = string.Empty;
// if (results != null && results.Count > 0 && results[0].Value != null)
// {
// // Convert the NodeId of the DataType to a readable string
// NodeId dataTypeNodeId = (NodeId)results[0].Value;
// dataType = _session.NodeCache.GetDisplayText(dataTypeNodeId);
// }
// SelectedNodeVariables.Add(new Variable
// {
// Name = opcUaNode.DisplayName,
// OpcUaNodeId = opcUaNode.NodeId.ToString(),
// ProtocolType = ProtocolType.OpcUA,
// IsActive = true, // Default selected
// DataType = dataType // Assign the read DataType
// });
// }
// }
// node.IsLoaded = true;
//}
//catch (Exception ex)
//{
// NlogHelper.Error($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
// NotificationHelper.ShowError($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
//}
//finally
//{
// node.IsLoading = false;
//}
//}
public ObservableCollection<Variable> GetSelectedVariables()
{
return new ObservableCollection<Variable>(SelectedVariables);
}
}

View File

@@ -1,257 +0,0 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DMS.Core.Enums;
using DMS.Helper;
namespace DMS.WPF.ViewModels.Dialogs;
public partial class OpcUaImportDialogViewModel : ObservableObject
{
// [ObservableProperty]
// private string _endpointUrl = "opc.tcp://127.0.0.1:4855"; // 默认值
//
// [ObservableProperty]
// private ObservableCollection<OpcUaNode> _opcUaNodes;
//
// [ObservableProperty]
// private ObservableCollection<Variable> _selectedNodeVariables;
//
// public List<Variable> SelectedVariables { get; set; }=new List<Variable>();
//
// [ObservableProperty]
// private bool _selectAllVariables;
//
// [ObservableProperty]
// private bool _isConnected;
//
// private Session _session;
//
// public OpcUaImportDialogViewModel()
// {
// OpcUaNodes = new ObservableCollection<OpcUaNode>();
// SelectedNodeVariables = new ObservableCollection<Variable>();
// // Automatically connect when the ViewModel is created
// ConnectCommand.Execute(null);
//
// }
//
// [RelayCommand]
// private async Task Connect()
// {
// try
// {
// // 断开现有连接
// if (_session != null && _session.Connected)
// {
// await _session.CloseAsync();
// _session.Dispose();
// _session = null;
// }
//
// IsConnected = false;
// OpcUaNodes.Clear();
// SelectedNodeVariables.Clear();
//
// _session = await ServiceHelper.CreateOpcUaSessionAsync(EndpointUrl);
//
// NotificationHelper.ShowSuccess($"已连接到 OPC UA 服务器: {EndpointUrl}");
// IsConnected = true;
//
// // 浏览根节点
// await BrowseNodes(OpcUaNodes, ObjectIds.ObjectsFolder);
// }
// catch (Exception ex)
// {
// IsConnected = false;
// NotificationHelper.ShowError($"连接 OPC UA 服务器失败: {EndpointUrl} - {ex.Message}", ex);
// }
// }
//
// /// <summary>
// /// 处理来自服务器的数据变化通知
// /// </summary>
// private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
// {
// foreach (var value in item.DequeueValues())
// {
// Console.WriteLine(
// $"[通知] {item.DisplayName}: {value.Value} | 时间戳: {value.SourceTimestamp.ToLocalTime()} | 状态: {value.StatusCode}");
// }
// }
//
// private async Task BrowseNodes(ObservableCollection<OpcUaNode> nodes, NodeId parentNodeId)
// {
// try
// {
// Opc.Ua.ReferenceDescriptionCollection references;
// byte[] continuationPoint = null;
//
// _session.Browse(
// null, // RequestHeader
// new ViewDescription(),
// parentNodeId,
// 0u,
// BrowseDirection.Forward,
// Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
// true,
// (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
// out continuationPoint,
// out references
// );
//
// foreach (var rd in references)
// {
// NodeType nodeType = NodeType.Folder; // 默认是文件夹
// if ((rd.NodeClass & NodeClass.Variable) != 0)
// {
// nodeType = NodeType.Variable;
// }
// else if ((rd.NodeClass & NodeClass.Object) != 0)
// {
// nodeType = NodeType.Object;
// }
//
// var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
// nodes.Add(opcUaNode);
//
// // 如果是文件夹或对象,添加一个虚拟子节点,用于懒加载
// if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
// {
// opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
// }
// }
// }
// catch (Exception ex)
// {
// NlogHelper.Error($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
// NotificationHelper.ShowError($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
// }
// }
//
// public async Task LoadNodeVariables(OpcUaNode node)
// {
// if (node.NodeType == NodeType.Variable)
// {
// // 如果是变量节点,直接显示它
// SelectedNodeVariables.Clear();
// SelectedNodeVariables.Add(new Variable
// {
// Name = node.DisplayName,
// NodeId = node.NodeId.ToString(),
// OpcUaNodeId = node.NodeId.ToString(),
// ProtocolType = ProtocolType.OpcUA,
// IsActive = true // 默认选中
// });
// return;
// }
//
// if (node.IsLoaded || node.IsLoading)
// {
// return; // 已经加载或正在加载
// }
//
// node.IsLoading = true;
// node.Children.Clear(); // 清除虚拟节点
//
// try
// {
// Opc.Ua.ReferenceDescriptionCollection references;
// byte[] continuationPoint = null;
//
// _session.Browse(
// null, // RequestHeader
// new ViewDescription(),
// node.NodeId,
// 0u,
// BrowseDirection.Forward,
// Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
// true,
// (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
// out continuationPoint,
// out references
// );
//
// foreach (var rd in references)
// {
// NodeType nodeType = NodeType.Folder;
// if ((rd.NodeClass & NodeClass.Variable) != 0)
// {
// nodeType = NodeType.Variable;
// }
// else if ((rd.NodeClass & NodeClass.Object) != 0)
// {
// nodeType = NodeType.Object;
// }
//
// var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
// node.Children.Add(opcUaNode);
//
// if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
// {
// opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
// }
//
// // 如果是变量,添加到右侧列表
// if (nodeType == NodeType.Variable)
// {
// // Read the DataType attribute
// ReadValueId readValueId = new ReadValueId
// {
// NodeId = opcUaNode.NodeId,
// AttributeId = Attributes.DataType,
// // You might need to specify IndexRange and DataEncoding if dealing with arrays or specific encodings
// };
//
// DataValueCollection results;
// DiagnosticInfoCollection diagnosticInfos;
//
// _session.Read(
// null, // RequestHeader
// 0, // MaxAge
// TimestampsToReturn.Source,
// new ReadValueIdCollection { readValueId },
// out results,
// out diagnosticInfos
// );
//
// string dataType = string.Empty;
//
// if (results != null && results.Count > 0 && results[0].Value != null)
// {
// // Convert the NodeId of the DataType to a readable string
// NodeId dataTypeNodeId = (NodeId)results[0].Value;
// dataType = _session.NodeCache.GetDisplayText(dataTypeNodeId);
// }
//
// SelectedNodeVariables.Add(new Variable
// {
// Name = opcUaNode.DisplayName,
// OpcUaNodeId = opcUaNode.NodeId.ToString(),
// ProtocolType = ProtocolType.OpcUA,
// IsActive = true, // Default selected
// DataType = dataType // Assign the read DataType
// });
// }
// }
//
// node.IsLoaded = true;
// }
// catch (Exception ex)
// {
// NlogHelper.Error($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
// NotificationHelper.ShowError($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
// }
// finally
// {
// node.IsLoading = false;
// }
// }
//
// public ObservableCollection<Variable> GetSelectedVariables()
// {
// return new ObservableCollection<Variable>(SelectedVariables);
// }
}

View File

@@ -273,86 +273,66 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable
/// 此命令通常绑定到UI中的“从OPC UA导入”按钮。
/// </summary>
[RelayCommand]
private async Task ImportFromOpcUaServer()
private async void ImportFromOpcUaServer()
{
// ContentDialog processingDialog = null; // 用于显示处理中的对话框
// try
// {
// // 检查OPC UA Endpoint URL是否已设置
// string opcUaEndpointUrl = VariableTable?.Device?.OpcUaEndpointUrl;
// if (string.IsNullOrEmpty(opcUaEndpointUrl))
// {
// NotificationHelper.ShowError("OPC UA Endpoint URL 未设置。请在设备详情中配置。");
// return;
// }
//
// // 显示OPC UA导入对话框让用户选择要导入的变量
// var importedVariables = await _dialogService.ShowOpcUaImportDialog(opcUaEndpointUrl);
// if (importedVariables == null || !importedVariables.Any())
// {
// return; // 用户取消或没有选择任何变量
// }
//
// // 显示处理中的对话框
// processingDialog = _dialogService.ShowProcessingDialog("正在处理...", "正在导入OPC UA变量,请稍等片刻....");
//
// // 在进行重复检查之前,先刷新 Variables 集合,确保其包含所有最新数据
// await RefreshDataView();
//
// List<Variable> newVariables = new List<Variable>();
// List<string> importedVariableNames = new List<string>();
// List<string> existingVariableNames = new List<string>();
//
// foreach (var variableData in importedVariables)
// {
// // 判断是否存在重复变量,仅在当前 VariableTable 的 Variables 中查找
// bool isDuplicate = Variables.Any(existingVar =>
// (existingVar.Name == variableData.Name) ||
// (!string.IsNullOrEmpty(variableData.NodeId) &&
// existingVar.NodeId == variableData.NodeId) ||
// (!string.IsNullOrEmpty(variableData.OpcUaNodeId) &&
// existingVar.OpcUaNodeId == variableData.OpcUaNodeId)
// );
//
// if (isDuplicate)
// {
// existingVariableNames.Add(variableData.Name);
// }
// else
// {
// variableData.CreateTime = DateTime.Now;
// variableData.VariableTableId = VariableTable.Id;
// variableData.ProtocolType = ProtocolType.OpcUA; // 确保协议类型正确
// variableData.IsModified = false;
// newVariables.Add(variableData);
// importedVariableNames.Add(variableData.Name);
// }
// }
//
// if (newVariables.Any())
// {
// // 批量插入新变量数据到数据库
// var resVarDataCount = await _varDataRepository.AddAsync(newVariables);
// NlogHelper.Info($"成功导入OPC UA变量{resVarDataCount}个。");
// }
//
// // 再次刷新 Variables 集合,以反映新添加的数据
// await RefreshDataView();
//
// processingDialog?.Hide(); // 隐藏处理中的对话框
//
// // 显示导入结果对话框
// await _dialogService.ShowImportResultDialog(importedVariableNames, existingVariableNames);
// }
// catch (Exception e)
// {
// // 捕获并显示错误通知
// NotificationHelper.ShowError($"从OPC UA服务器导入变量的过程中发生了不可预期的错误{e.Message}", e);
// }
// finally
// {
// processingDialog?.Hide(); // 确保在任何情况下都隐藏对话框
// }
try
{
// 检查OPC UA Endpoint URL是否已设置
string opcUaEndpointUrl = CurrentVariableTable.Device.OpcUaServerUrl;
if (string.IsNullOrEmpty(opcUaEndpointUrl))
{
NotificationHelper.ShowError("OPC UA Endpoint URL 未设置。请在设备详情中配置。");
return;
}
// 显示OPC UA导入对话框让用户选择要导入的变量
ImportOpcUaDialogViewModel importOpcUaDialogViewModel = new ImportOpcUaDialogViewModel();
var importedVariables = await _dialogService.ShowDialogAsync(importOpcUaDialogViewModel);
if (importedVariables == null || !importedVariables.Any())
{
return; // 用户取消或没有选择任何变量
}
//var importedVariableDtos = _mapper.Map<List<VariableDto>>(importedVariables);
//foreach (var variableDto in importedVariableDtos)
//{
// variableDto.CreatedAt = DateTime.Now;
// variableDto.UpdatedAt = DateTime.Now;
// variableDto.VariableTableId = CurrentVariableTable.Id;
// variableDto.Protocol = ProtocolType.OpcUa; // 确保协议类型正确
//}
//var existList = await _variableAppService.FindExistingVariablesAsync(importedVariableDtos);
//if (existList.Count > 0)
//{
// // 拼接要删除的变量名称,用于确认提示
// var existNames = string.Join("、", existList.Select(v => v.Name));
// var confrimDialogViewModel
// = new ConfirmDialogViewModel("存在已经添加的变量", $"变量名称:{existNames},已经存在,是否跳过继续添加其他的变量。取消则不添加任何变量", "继续");
// var res = await _dialogService.ShowDialogAsync(confrimDialogViewModel);
// if (!res) return;
// // 从导入列表中删除已经存在的变量
// importedVariableDtos.RemoveAll(variableDto => existList.Contains(variableDto));
//}
//if (importedVariableDtos.Count != 0)
//{
// var isSuccess = await _variableAppService.BatchImportVariablesAsync(importedVariableDtos);
// if (isSuccess)
// {
// _variableItemList.AddRange(_mapper.Map<List<VariableItemViewModel>>(importedVariableDtos));
// NotificationHelper.ShowSuccess($"从OPC UA服务器导入变量成功共导入变量{importedVariableDtos.Count}个");
// }
//}
//else
//{
// NotificationHelper.ShowSuccess($"列表中没有要添加的变量了。");
//}
}
catch (Exception e)
{
NotificationHelper.ShowError($"从OPC UA服务器导入变量的过程中发生了不可预期的错误{e.Message}", e);
}
}