From 14ff22e930d9058e7ded007e03634602b3fa5f36 Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Thu, 17 Jul 2025 10:43:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=87=8D=E5=A4=8D=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=88=96=E8=80=85=E5=AF=BC=E5=85=A5=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=AF=BC=E5=85=A5=E7=BB=93=E6=9E=9C=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dialogs/ImportResultDialogViewModel.cs | 44 +++++ ViewModels/VariableTableViewModel.cs | 180 ++++++++++++------ Views/Dialogs/ImportResultDialog.xaml | 55 ++++++ Views/Dialogs/ImportResultDialog.xaml.cs | 20 ++ 4 files changed, 238 insertions(+), 61 deletions(-) create mode 100644 ViewModels/Dialogs/ImportResultDialogViewModel.cs create mode 100644 Views/Dialogs/ImportResultDialog.xaml create mode 100644 Views/Dialogs/ImportResultDialog.xaml.cs diff --git a/ViewModels/Dialogs/ImportResultDialogViewModel.cs b/ViewModels/Dialogs/ImportResultDialogViewModel.cs new file mode 100644 index 0000000..445a1a6 --- /dev/null +++ b/ViewModels/Dialogs/ImportResultDialogViewModel.cs @@ -0,0 +1,44 @@ +using System.Collections.ObjectModel; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using PMSWPF.Models; + +namespace PMSWPF.ViewModels.Dialogs; + +/// +/// ImportResultDialogViewModel 是用于显示变量导入结果的视图模型。 +/// 它包含成功导入和已存在变量的列表。 +/// +public partial class ImportResultDialogViewModel : ObservableObject +{ + /// + /// 成功导入的变量名称列表。 + /// + public ObservableCollection ImportedVariables { get; } + + /// + /// 已存在的变量名称列表。 + /// + public ObservableCollection ExistingVariables { get; } + + /// + /// 构造函数,初始化导入结果列表。 + /// + /// 成功导入的变量名称列表。 + /// 已存在的变量名称列表。 + public ImportResultDialogViewModel(List importedVariables, List existingVariables) + { + ImportedVariables = new ObservableCollection(importedVariables); + ExistingVariables = new ObservableCollection(existingVariables); + } + + /// + /// 关闭对话框的命令。 + /// + [RelayCommand] + private void Close() + { + // 在实际应用中,这里可能需要通过IDialogService或其他机制来关闭对话框 + // 对于ContentDialog,通常不需要显式关闭命令,因为对话框本身有关闭按钮或通过Result返回 + } +} diff --git a/ViewModels/VariableTableViewModel.cs b/ViewModels/VariableTableViewModel.cs index 0e0f34d..608f5eb 100644 --- a/ViewModels/VariableTableViewModel.cs +++ b/ViewModels/VariableTableViewModel.cs @@ -358,16 +358,13 @@ partial class VariableTableViewModel : ViewModelBase foreach (var variableData in importVarDataList) { // 判断是否存在重复变量 - bool isDuplicate = _dataServices.AllVariables.Values.Any(existingVar => - (existingVar.Name == variableData.Name) || - (!string.IsNullOrEmpty( - variableData.NodeId) && - existingVar.NodeId == - variableData.NodeId) || - (!string.IsNullOrEmpty( - variableData.S7Address) && - existingVar.S7Address == - variableData.S7Address) + // 判断是否存在重复变量,仅在当前 VariableTable 的 DataVariables 中查找 + bool isDuplicate = DataVariables.Any(existingVar => + (existingVar.Name == variableData.Name) || + (!string.IsNullOrEmpty(variableData.NodeId) && + existingVar.NodeId == variableData.NodeId) || + (!string.IsNullOrEmpty(variableData.S7Address) && + existingVar.S7Address == variableData.S7Address) ); if (isDuplicate) @@ -438,25 +435,53 @@ partial class VariableTableViewModel : ViewModelBase // 显示处理中的对话框 processingDialog = _dialogService.ShowProcessingDialog("正在处理...", "正在导入OPC UA变量,请稍等片刻...."); - // 为导入的每个变量设置创建时间、所属变量表ID和协议类型 + // 在进行重复检查之前,先刷新 DataVariables 集合,确保其包含所有最新数据 + await RefreshDataView(); + + List newVariables = new List(); + List importedVariableNames = new List(); + List existingVariableNames = new List(); + foreach (var variableData in importedVariables) { - variableData.CreateTime = DateTime.Now; - variableData.VariableTableId = VariableTable.Id; - variableData.ProtocolType = ProtocolType.OpcUA; // 确保协议类型正确 - variableData.IsModified = false; + // 判断是否存在重复变量,仅在当前 VariableTable 的 DataVariables 中查找 + bool isDuplicate = DataVariables.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); + } } - // 批量插入变量数据到数据库 - var resVarDataCount = await _varDataRepository.AddAsync(importedVariables); + if (newVariables.Any()) + { + // 批量插入新变量数据到数据库 + var resVarDataCount = await _varDataRepository.AddAsync(newVariables); + NlogHelper.Info($"成功导入OPC UA变量:{resVarDataCount}个。"); + } + // 再次刷新 DataVariables 集合,以反映新添加的数据 await RefreshDataView(); processingDialog?.Hide(); // 隐藏处理中的对话框 - // 显示成功通知并记录日志 - string msgSuccess = $"成功导入OPC UA变量:{resVarDataCount}个。"; - NotificationHelper.ShowSuccess(msgSuccess); + // 显示导入结果对话框 + await _dialogService.ShowImportResultDialog(importedVariableNames, existingVariableNames); } catch (Exception e) { @@ -469,60 +494,55 @@ partial class VariableTableViewModel : ViewModelBase } } - // /// - // /// 刷新数据列表 - // /// + /// + /// 刷新数据列表,高效地同步UI显示数据与数据库最新数据。 + /// private async Task RefreshDataView() { - // 更新界面显示的数据:重新从数据库加载所有变量数据 + // 从数据库加载最新的变量数据 + var latestVariables = await _varDataRepository.GetByVariableTableIdAsync(VariableTable.Id); - var varList = await _varDataRepository.GetByVariableTableIdAsync(VariableTable.Id); - // 处理删除 - if (varList.Count < DataVariables.Count) + // 将最新数据转换为字典,以便快速查找 + var latestVariablesDict = latestVariables.ToDictionary(v => v.Id); + + // 用于存储需要从 DataVariables 中移除的项 + var itemsToRemove = new List(); + + // 遍历当前 DataVariables 集合,处理删除和更新 + for (int i = DataVariables.Count - 1; i >= 0; i--) { - for (int i = DataVariables.Count-1; i >=0; i--) + var currentVariable = DataVariables[i]; + if (latestVariablesDict.TryGetValue(currentVariable.Id, out var newVariable)) { - bool isExist=false; - foreach (var variableData in varList) + // 如果存在于最新数据中,检查是否需要更新 + if (!currentVariable.Equals(newVariable)) { - if (variableData.Id==DataVariables[i].Id) - { - isExist=true; - } - } - if (!isExist) - { - DataVariables.RemoveAt(i); + // 使用 AutoMapper 更新现有对象的属性,保持对象引用不变 + _mapper.Map(newVariable, currentVariable); } + // 从字典中移除已处理的项,剩余的将是新增项 + latestVariablesDict.Remove(currentVariable.Id); + } + else + { + // 如果不存在于最新数据中,则标记为删除 + itemsToRemove.Add(currentVariable); } } - // 处理修改和 添加 - foreach (var newVariable in varList) + // 移除已标记的项 + foreach (var item in itemsToRemove) { - bool isExiset = false; - for (int i = 0; i < DataVariables.Count; i++) - { - var oldVariable = DataVariables[i]; - // 判断是否存在 - if (newVariable.Id == oldVariable.Id) - { - isExiset = true; - //判断是否相等 - if (!oldVariable.Equals(newVariable)) - { - DataVariables[i] = newVariable; - } - } - } - - // 不存在则添加 - if (!isExiset) - { - DataVariables.Add(newVariable); - } + DataVariables.Remove(item); } + // 添加所有剩余在 latestVariablesDict 中的项(这些是新增项) + foreach (var newVariable in latestVariablesDict.Values) + { + DataVariables.Add(newVariable); + } + + // 刷新视图以应用所有更改 VariableDataView.Refresh(); } @@ -547,6 +567,44 @@ partial class VariableTableViewModel : ViewModelBase // 设置新变量的所属变量表ID varData.VariableTableId = variableTable.Id; + // --- 重复性检查逻辑开始 --- + bool isDuplicate = false; + string duplicateReason = string.Empty; + + // 检查名称是否重复 + if (DataVariables.Any(v => v.Name == varData.Name)) + { + isDuplicate = true; + duplicateReason = $"名称 '{varData.Name}' 已存在。"; + } + else + { + // 根据协议类型检查S7地址或NodeId是否重复 + if (variableTable.ProtocolType == ProtocolType.S7) + { + if (!string.IsNullOrEmpty(varData.S7Address) && DataVariables.Any(v => v.S7Address == varData.S7Address)) + { + isDuplicate = true; + duplicateReason = $"S7地址 '{varData.S7Address}' 已存在。"; + } + } + else if (variableTable.ProtocolType == ProtocolType.OpcUA) + { + if (!string.IsNullOrEmpty(varData.NodeId) && DataVariables.Any(v => v.NodeId == varData.NodeId)) + { + isDuplicate = true; + duplicateReason = $"OPC UA NodeId '{varData.NodeId}' 已存在。"; + } + } + } + + if (isDuplicate) + { + NotificationHelper.ShowError($"添加变量失败:{duplicateReason}"); + return; + } + // --- 重复性检查逻辑结束 --- + // 添加变量数据到数据库 var resVarData = await _varDataRepository.AddAsync(varData); if (resVarData == null) diff --git a/Views/Dialogs/ImportResultDialog.xaml b/Views/Dialogs/ImportResultDialog.xaml new file mode 100644 index 0000000..6851515 --- /dev/null +++ b/Views/Dialogs/ImportResultDialog.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Views/Dialogs/ImportResultDialog.xaml.cs b/Views/Dialogs/ImportResultDialog.xaml.cs new file mode 100644 index 0000000..29b3d45 --- /dev/null +++ b/Views/Dialogs/ImportResultDialog.xaml.cs @@ -0,0 +1,20 @@ +using iNKORE.UI.WPF.Modern.Controls; +using PMSWPF.ViewModels.Dialogs; + +namespace PMSWPF.Views.Dialogs; + +/// +/// ImportResultDialog.xaml 的交互逻辑 +/// +public partial class ImportResultDialog : ContentDialog +{ + public ImportResultDialog() + { + InitializeComponent(); + } + + public ImportResultDialog(ImportResultDialogViewModel viewModel) : this() + { + DataContext = viewModel; + } +}