From 6d7636d664eb697dd6e53473b0e762960e41070e Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Tue, 2 Sep 2025 16:45:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=B1=9E=E6=80=A7=E4=B8=8D=E7=BB=9F=E4=B8=80=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DMS.Application/DTOs/VariableDto.cs | 2 +- DMS.Application/DTOs/VariableTableDto.cs | 1 + DMS.Application/Services/DeviceAppService.cs | 1 + .../Enums/{CSharpDataType.cs => DataType.cs} | 2 +- DMS.Core/Models/Variable.cs | 2 +- DMS.Infrastructure.UnitTests/FakerHelper.cs | 4 +- DMS.Infrastructure/Entities/DbVariable.cs | 3 +- DMS.Infrastructure/Models/OpcUaNode.cs | 2 +- DMS.Infrastructure/Services/ExcelService.cs | 2 +- DMS.Infrastructure/Services/OpcUaService.cs | 56 ++++++------- DMS.WPF/Services/DataServices.cs | 2 +- .../Dialogs/ImportOpcUaDialogViewModel.cs | 2 +- .../ViewModels/Items/VariableItemViewModel.cs | 2 +- DMS.WPF/ViewModels/VariableTableViewModel.cs | 79 +++++++++++-------- DMS.WPF/Views/Dialogs/VariableDialog.xaml | 2 +- DMS.WPF/Views/VariableTableView.xaml | 2 +- 16 files changed, 88 insertions(+), 76 deletions(-) rename DMS.Core/Enums/{CSharpDataType.cs => DataType.cs} (96%) diff --git a/DMS.Application/DTOs/VariableDto.cs b/DMS.Application/DTOs/VariableDto.cs index cc34425..0801ab5 100644 --- a/DMS.Application/DTOs/VariableDto.cs +++ b/DMS.Application/DTOs/VariableDto.cs @@ -27,7 +27,7 @@ public class VariableDto public double AlarmMaxValue { get; set; } public double AlarmDeadband { get; set; } public ProtocolType Protocol { get; set; } - public CSharpDataType CSharpDataType { get; set; } + public DataType DataType { get; set; } public string ConversionFormula { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } diff --git a/DMS.Application/DTOs/VariableTableDto.cs b/DMS.Application/DTOs/VariableTableDto.cs index 76c2fa3..f10430a 100644 --- a/DMS.Application/DTOs/VariableTableDto.cs +++ b/DMS.Application/DTOs/VariableTableDto.cs @@ -12,6 +12,7 @@ public class VariableTableDto public string Description { get; set; } public bool IsActive { get; set; } public int DeviceId { get; set; } + public DeviceDto Device { get; set; } public ProtocolType Protocol { get; set; } public List Variables { get; set; } = new(); } \ No newline at end of file diff --git a/DMS.Application/Services/DeviceAppService.cs b/DMS.Application/Services/DeviceAppService.cs index 1a88ec9..c62bd87 100644 --- a/DMS.Application/Services/DeviceAppService.cs +++ b/DMS.Application/Services/DeviceAppService.cs @@ -99,6 +99,7 @@ public class DeviceAppService : IDeviceAppService throw new InvalidOperationException($"添加设备变量表失败,设备:{device.Name},变量表:{variableTable.Name}"); } _mapper.Map(addVariableTable,dto.VariableTable); + dto.VariableTable.Device = dto.Device; // 假设有设备菜单 if (dto.VariableTableMenu != null) diff --git a/DMS.Core/Enums/CSharpDataType.cs b/DMS.Core/Enums/DataType.cs similarity index 96% rename from DMS.Core/Enums/CSharpDataType.cs rename to DMS.Core/Enums/DataType.cs index 5d41c54..fc4de18 100644 --- a/DMS.Core/Enums/CSharpDataType.cs +++ b/DMS.Core/Enums/DataType.cs @@ -9,7 +9,7 @@ namespace DMS.Core.Enums /// /// 定义了C#中常用的数据类型。 /// - public enum CSharpDataType + public enum DataType { // 基本数值类型 Bool, diff --git a/DMS.Core/Models/Variable.cs b/DMS.Core/Models/Variable.cs index c641f12..08a0530 100644 --- a/DMS.Core/Models/Variable.cs +++ b/DMS.Core/Models/Variable.cs @@ -107,7 +107,7 @@ public class Variable /// /// 变量的数据类型。 /// - public CSharpDataType CSharpDataType { get; set; } + public DataType DataType { get; set; } /// /// 数值转换公式,例如 "+3*5"。 diff --git a/DMS.Infrastructure.UnitTests/FakerHelper.cs b/DMS.Infrastructure.UnitTests/FakerHelper.cs index a45469c..eb0cde0 100644 --- a/DMS.Infrastructure.UnitTests/FakerHelper.cs +++ b/DMS.Infrastructure.UnitTests/FakerHelper.cs @@ -73,7 +73,7 @@ namespace DMS.Infrastructure.UnitTests dbVariable.AlarmMaxValue = 100; dbVariable.AlarmDeadband = 1; dbVariable.Protocol = 0; - dbVariable.CSharpDataType = 0; + dbVariable.DataType = 0; dbVariable.CreatedAt = DateTime.Now; dbVariable.UpdatedAt = DateTime.Now; dbVariable.IsModified = false; @@ -156,7 +156,7 @@ namespace DMS.Infrastructure.UnitTests .RuleFor(v => v.AlarmMaxValue, f => f.Random.Double(50.0, 100.0)) .RuleFor(v => v.AlarmDeadband, f => f.Random.Double(0.0, 1.0)) .RuleFor(v => v.Protocol, f => f.PickRandom()) - .RuleFor(v => v.CSharpDataType, f => f.PickRandom(Enum.GetValues())) + .RuleFor(v => v.DataType, f => f.PickRandom(Enum.GetValues())) .RuleFor(v => v.OpcUaNodeId, f => $"ns=2;s=My.Variable{f.Random.Int(1, 100)}") .RuleFor(v => v.ConversionFormula, f => "x * 1.0") .RuleFor(v => v.UpdatedBy, f => f.Name.FullName()) diff --git a/DMS.Infrastructure/Entities/DbVariable.cs b/DMS.Infrastructure/Entities/DbVariable.cs index 6ccdd1c..6152b49 100644 --- a/DMS.Infrastructure/Entities/DbVariable.cs +++ b/DMS.Infrastructure/Entities/DbVariable.cs @@ -1,7 +1,6 @@ using DMS.Core.Enums; using SqlSugar; using SqlSugar.DbConvert; -using CSharpDataType = SqlSugar.CSharpDataType; namespace DMS.Infrastructure.Entities; @@ -113,7 +112,7 @@ public class DbVariable /// 变量的数据类型。 /// [SugarColumn(ColumnDataType="varchar(20)",SqlParameterDbType=typeof(EnumToStringConvert))] - public CSharpDataType CSharpDataType { get; set; } + public DataType DataType { get; set; } /// /// 数值转换公式 (例如: "+3*5"),可以为空。 diff --git a/DMS.Infrastructure/Models/OpcUaNode.cs b/DMS.Infrastructure/Models/OpcUaNode.cs index 8210b78..0a041ba 100644 --- a/DMS.Infrastructure/Models/OpcUaNode.cs +++ b/DMS.Infrastructure/Models/OpcUaNode.cs @@ -40,7 +40,7 @@ namespace DMS.Infrastructure.Models /// /// 数据类型 /// - public CSharpDataType DataType { get; set; } + public DataType DataType { get; set; } /// /// 返回节点的字符串表示形式。 diff --git a/DMS.Infrastructure/Services/ExcelService.cs b/DMS.Infrastructure/Services/ExcelService.cs index fa0fa0d..e7f2ba4 100644 --- a/DMS.Infrastructure/Services/ExcelService.cs +++ b/DMS.Infrastructure/Services/ExcelService.cs @@ -250,7 +250,7 @@ public class ExcelService : IExcelService { DMS.Core.Models.Variable variable = new DMS.Core.Models.Variable(); variable.Name = dataRow["Name"].ToString(); - variable.CSharpDataType = (DMS.Core.Enums.CSharpDataType)Enum.Parse(typeof(DMS.Core.Enums.CSharpDataType), SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()), true); + variable.DataType = (DMS.Core.Enums.DataType)Enum.Parse(typeof(DMS.Core.Enums.DataType), SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()), true); variable.SignalType = SignalType.OtherASignal; var exS7Addr = dataRow["Logical Address"].ToString(); if (exS7Addr.StartsWith("%")) diff --git a/DMS.Infrastructure/Services/OpcUaService.cs b/DMS.Infrastructure/Services/OpcUaService.cs index c96333c..04e3d5d 100644 --- a/DMS.Infrastructure/Services/OpcUaService.cs +++ b/DMS.Infrastructure/Services/OpcUaService.cs @@ -626,42 +626,42 @@ namespace DMS.Infrastructure.Services /// /// 数据类型NodeId /// 数据类型的友好名称 - private CSharpDataType GetDataTypeName(NodeId dataTypeId) + private DataType GetDataTypeName(NodeId dataTypeId) { if (dataTypeId == null) - return CSharpDataType.Unknown; + return DataType.Unknown; // 使用OPC UA内置的类型映射 switch (dataTypeId.Identifier.ToString()) { - case "1": return CSharpDataType.Bool; // Boolean - case "2": return CSharpDataType.SByte; // SByte - case "3": return CSharpDataType.Byte; // Byte - case "4": return CSharpDataType.Short; // Int16 - case "5": return CSharpDataType.UShort; // UInt16 - case "6": return CSharpDataType.Int; // Int32 - case "7": return CSharpDataType.UInt; // UInt32 - case "8": return CSharpDataType.Long; // Int64 - case "9": return CSharpDataType.ULong; // UInt64 - case "10": return CSharpDataType.Float; // Float - case "11": return CSharpDataType.Double; // Double - case "12": return CSharpDataType.String; // String - case "13": return CSharpDataType.DateTime; // DateTime - case "14": return CSharpDataType.Guid; // Guid - case "15": return CSharpDataType.ByteArray; // ByteString - case "16": return CSharpDataType.Object; // XmlElement - case "17": return CSharpDataType.Object; // NodeId - case "18": return CSharpDataType.Object; // ExpandedNodeId - case "19": return CSharpDataType.Object; // StatusCode - case "20": return CSharpDataType.Object; // QualifiedName - case "21": return CSharpDataType.Object; // LocalizedText - case "22": return CSharpDataType.Object; // ExtensionObject - case "23": return CSharpDataType.Object; // DataValue - case "24": return CSharpDataType.Object; // Variant - case "25": return CSharpDataType.Object; // DiagnosticInfo + case "1": return DataType.Bool; // Boolean + case "2": return DataType.SByte; // SByte + case "3": return DataType.Byte; // Byte + case "4": return DataType.Short; // Int16 + case "5": return DataType.UShort; // UInt16 + case "6": return DataType.Int; // Int32 + case "7": return DataType.UInt; // UInt32 + case "8": return DataType.Long; // Int64 + case "9": return DataType.ULong; // UInt64 + case "10": return DataType.Float; // Float + case "11": return DataType.Double; // Double + case "12": return DataType.String; // String + case "13": return DataType.DateTime; // DateTime + case "14": return DataType.Guid; // Guid + case "15": return DataType.ByteArray; // ByteString + case "16": return DataType.Object; // XmlElement + case "17": return DataType.Object; // NodeId + case "18": return DataType.Object; // ExpandedNodeId + case "19": return DataType.Object; // StatusCode + case "20": return DataType.Object; // QualifiedName + case "21": return DataType.Object; // LocalizedText + case "22": return DataType.Object; // ExtensionObject + case "23": return DataType.Object; // DataValue + case "24": return DataType.Object; // Variant + case "25": return DataType.Object; // DiagnosticInfo default: // 对于自定义数据类型,返回Unknown - return CSharpDataType.Unknown; + return DataType.Unknown; } } diff --git a/DMS.WPF/Services/DataServices.cs b/DMS.WPF/Services/DataServices.cs index 066fd9d..f660229 100644 --- a/DMS.WPF/Services/DataServices.cs +++ b/DMS.WPF/Services/DataServices.cs @@ -287,7 +287,7 @@ public partial class DataServices : ObservableRecipient, IRecipient if (existingItem.AlarmMaxValue != dto.AlarmMaxValue) existingItem.AlarmMaxValue = dto.AlarmMaxValue; if (existingItem.AlarmDeadband != dto.AlarmDeadband) existingItem.AlarmDeadband = dto.AlarmDeadband; if (existingItem.Protocol != dto.Protocol) existingItem.Protocol = dto.Protocol; - if (existingItem.CSharpDataType != dto.CSharpDataType) existingItem.CSharpDataType = dto.CSharpDataType; + if (existingItem.DataType != dto.DataType) existingItem.DataType = dto.DataType; if (existingItem.ConversionFormula != dto.ConversionFormula) existingItem.ConversionFormula = dto.ConversionFormula; if (existingItem.CreatedAt != dto.CreatedAt) existingItem.CreatedAt = dto.CreatedAt; diff --git a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs index 60b36a1..6a06edb 100644 --- a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs +++ b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs @@ -331,7 +331,7 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase [ObservableProperty] - private CSharpDataType _cSharpDataType; + private DataType _dataType; /// /// 获取或设置值的转换公式。 diff --git a/DMS.WPF/ViewModels/VariableTableViewModel.cs b/DMS.WPF/ViewModels/VariableTableViewModel.cs index 4f8cfd5..5bb5719 100644 --- a/DMS.WPF/ViewModels/VariableTableViewModel.cs +++ b/DMS.WPF/ViewModels/VariableTableViewModel.cs @@ -277,6 +277,11 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable { try { + if (CurrentVariableTable.Device==null) + { + NotificationHelper.ShowError("当前变量表的Device对象为空,请检查。"); + return; + } // 检查OPC UA Endpoint URL是否已设置 string opcUaEndpointUrl = CurrentVariableTable.Device.OpcUaServerUrl; if (string.IsNullOrEmpty(opcUaEndpointUrl)) @@ -286,48 +291,54 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable } // 显示OPC UA导入对话框,让用户选择要导入的变量 - ImportOpcUaDialogViewModel importOpcUaDialogViewModel = App.Current.Services.GetRequiredService() ; + ImportOpcUaDialogViewModel importOpcUaDialogViewModel = App.Current.Services.GetRequiredService(); + importOpcUaDialogViewModel.EndpointUrl = opcUaEndpointUrl; // 设置Endpoint URL var importedVariables = await _dialogService.ShowDialogAsync(importOpcUaDialogViewModel); if (importedVariables == null || !importedVariables.Any()) { return; // 用户取消或没有选择任何变量 } - //var importedVariableDtos = _mapper.Map>(importedVariables); - //foreach (var variableDto in importedVariableDtos) - //{ - // variableDto.CreatedAt = DateTime.Now; - // variableDto.UpdatedAt = DateTime.Now; - // variableDto.VariableTableId = CurrentVariableTable.Id; - // variableDto.Protocol = ProtocolType.OpcUa; // 确保协议类型正确 - //} + // 将导入的变量转换为DTO并设置必要的属性 + var importedVariableDtos = _mapper.Map>(importedVariables); + foreach (var variableDto in importedVariableDtos) + { + variableDto.CreatedAt = DateTime.Now; + variableDto.UpdatedAt = DateTime.Now; + variableDto.VariableTableId = CurrentVariableTable.Id; + } - //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)); - //} + // 检查是否存在同名变量 + var existList = await _variableAppService.FindExistingVariablesAsync(importedVariableDtos); + if (existList.Count > 0) + { + // 拼接要删除的变量名称,用于确认提示 + var existNames = string.Join("、", existList.Select(v => v.Name)); + var confirmDialogViewModel = new ConfirmDialogViewModel("存在已经添加的变量", $"变量名称:{existNames},已经存在,是否跳过继续添加其他的变量。取消则不添加任何变量", "继续"); + var res = await _dialogService.ShowDialogAsync(confirmDialogViewModel); + 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>(importedVariableDtos)); - // NotificationHelper.ShowSuccess($"从OPC UA服务器导入变量成功,共导入变量:{importedVariableDtos.Count}个"); - // } - //} - //else - //{ - // NotificationHelper.ShowSuccess($"列表中没有要添加的变量了。"); - //} + // 如果还有变量需要导入,则执行导入操作 + if (importedVariableDtos.Count != 0) + { + var isSuccess = await _variableAppService.BatchImportVariablesAsync(importedVariableDtos); + if (isSuccess) + { + _variableItemList.AddRange(_mapper.Map>(importedVariableDtos)); + NotificationHelper.ShowSuccess($"从OPC UA服务器导入变量成功,共导入变量:{importedVariableDtos.Count}个"); + } + else + { + NotificationHelper.ShowError("从OPC UA服务器导入变量失败"); + } + } + else + { + NotificationHelper.ShowSuccess("列表中没有要添加的变量了。"); + } } catch (Exception e) { diff --git a/DMS.WPF/Views/Dialogs/VariableDialog.xaml b/DMS.WPF/Views/Dialogs/VariableDialog.xaml index 5033618..4cf87ba 100644 --- a/DMS.WPF/Views/Dialogs/VariableDialog.xaml +++ b/DMS.WPF/Views/Dialogs/VariableDialog.xaml @@ -25,7 +25,7 @@ - + diff --git a/DMS.WPF/Views/VariableTableView.xaml b/DMS.WPF/Views/VariableTableView.xaml index 18e5007..b17a7ee 100644 --- a/DMS.WPF/Views/VariableTableView.xaml +++ b/DMS.WPF/Views/VariableTableView.xaml @@ -251,7 +251,7 @@ IsReadOnly="True" Visibility="{Binding Source={StaticResource proxy}, Path=Data.IsOpcUaProtocolSelected, Converter={StaticResource BooleanToVisibilityConverter}}" />