From 02eab6ecf01d7286d9b2c2791812d48c714ae5ca Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Fri, 4 Jul 2025 13:40:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BB=8ETIA=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E8=A1=A8=E5=AF=BC=E5=85=A5=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Data/Entities/DbVariableData.cs | 160 ++++++++++++----------- Data/Repositories/VarDataRepository.cs | 26 ++++ Models/VariableData.cs | 168 +++++++++++++------------ PMSWPF.Tests/ExcelHelperTests.cs | 59 +++++++-- Services/DialogService.cs | 12 ++ Services/IDialogService.cs | 1 + ViewModels/VariableTableViewModel.cs | 72 +++++++++-- Views/VariableTableView.xaml | 37 ++++-- 8 files changed, 353 insertions(+), 182 deletions(-) diff --git a/Data/Entities/DbVariableData.cs b/Data/Entities/DbVariableData.cs index e91b2ff..3815bfd 100644 --- a/Data/Entities/DbVariableData.cs +++ b/Data/Entities/DbVariableData.cs @@ -10,6 +10,80 @@ namespace PMSWPF.Data.Entities; [SugarTable("VarData")] public class DbVariableData { + /// + /// 变量唯一标识符。 + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] //数据库是自增才配自增 + public int Id { get; set; } + + /// + /// 变量名称。 + /// + public string Name { get; set; } + + /// + /// 节点ID,用于标识变量在设备或系统中的唯一路径。 + /// + public string NodeId { get; set; } = String.Empty; + + /// + /// 节点ID,用于标识变量在设备或系统中的唯一路径。 + /// + public string S7Address { get; set; } = String.Empty; + + /// + /// 变量描述。 + /// + [SugarColumn(IsNullable = true)] + public string? Description { get; set; } + + /// + /// 协议类型,例如Modbus、OPC UA等。 + /// + [SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))] + public ProtocolType ProtocolType { get; set; } + + /// + /// 信号类型,例如模拟量、数字量等。 + /// + [SugarColumn(ColumnDataType = "varchar(20)", IsNullable = true, SqlParameterDbType = typeof(EnumToStringConvert))] + public SignalType SignalType { get; set; } + + /// + /// 数据类型,例如Int、Float、String等。 + /// + public string DataType { get; set; } = String.Empty; + + /// + /// 变量当前原始数据值。 + /// + public string DataValue { get; set; } = String.Empty; + + /// + /// 变量经过转换或格式化后的显示值。 + /// + public string DisplayValue { get; set; } = String.Empty; + + /// + /// 指示变量是否处于激活状态。 + /// + public bool IsActive { get; set; } + + /// + /// 指示是否需要保存变量数据。 + /// + public bool IsSave { get; set; } + + /// + /// 指示是否需要对变量进行报警监测。 + /// + public bool IsAlarm { get; set; } + + /// + /// 指示变量是否已被逻辑删除。 + /// + public bool IsDeleted { get; set; } + /// /// 报警的最大值阈值。 /// @@ -25,85 +99,15 @@ public class DbVariableData /// public string Converstion { get; set; } = String.Empty; - /// - /// 数据类型,例如Int、Float、String等。 - /// - public string DataType { get; set; } = String.Empty; - - /// - /// 变量当前原始数据值。 - /// - public string DataValue { get; set; } = String.Empty; - - /// - /// 变量描述。 - /// - [SugarColumn(IsNullable = true)] - public string? Description { get; set; } - - /// - /// 变量经过转换或格式化后的显示值。 - /// - public string DisplayValue { get; set; } = String.Empty; - - /// - /// 变量唯一标识符。 - /// - [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] //数据库是自增才配自增 - public int Id { get; set; } - - /// - /// 指示是否需要对变量进行报警监测。 - /// - public bool IsAlarm { get; set; } - - /// - /// 指示变量是否处于激活状态。 - /// - public bool IsActive { get; set; } - - /// - /// 指示变量是否已被逻辑删除。 - /// - public bool IsDeleted { get; set; } - - /// - /// 指示是否需要保存变量数据。 - /// - public bool IsSave { get; set; } - - /// - /// 关联的MQTT配置列表。 - /// - [SugarColumn(IsNullable = true)] - public List? Mqtts { get; set; } - - /// - /// 变量名称。 - /// - public string Name { get; set; } - - /// - /// 节点ID,用于标识变量在设备或系统中的唯一路径。 - /// - public string NodeId { get; set; } = String.Empty; - - /// - /// 协议类型,例如Modbus、OPC UA等。 - /// - [SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))] - public ProtocolType ProtocolType { get; set; } - /// /// 数据保存的范围或阈值。 /// public double SaveRange { get; set; } - /// - /// 信号类型,例如模拟量、数字量等。 + /// 变量数据最后更新时间。 /// - [SugarColumn(ColumnDataType = "varchar(20)", IsNullable = true, SqlParameterDbType = typeof(EnumToStringConvert))] - public SignalType SignalType { get; set; } + [SugarColumn(IsNullable = true)] + public DateTime CreateTime { get; set; } /// /// 变量数据最后更新时间。 @@ -116,6 +120,11 @@ public class DbVariableData [SugarColumn(IsNullable = true)] public DbUser? UpdateUser { get; set; } + /// + /// 关联的变量表ID。 + /// + public int VariableTableId { get; set; } + /// /// 关联的变量表实体。 /// @@ -123,7 +132,8 @@ public class DbVariableData public DbVariableTable? VariableTable { get; set; } /// - /// 关联的变量表ID。 + /// 关联的MQTT配置列表。 /// - public int VariableTableId { get; set; } + [SugarColumn(IsNullable = true)] + public List? Mqtts { get; set; } } \ No newline at end of file diff --git a/Data/Repositories/VarDataRepository.cs b/Data/Repositories/VarDataRepository.cs index 75ad395..6ea3d68 100644 --- a/Data/Repositories/VarDataRepository.cs +++ b/Data/Repositories/VarDataRepository.cs @@ -68,6 +68,32 @@ public class VarDataRepository return dbVarData.CopyTo(); } } + + /// + /// 新增VariableData + /// + /// VariableData实体 + /// + public async Task> AddAsync(List variableDatas) + { + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + + List variableDataList = new List(); + using (var _db = DbContext.GetInstance()) + { + List dbVarDataList = variableDatas.Select(varData=>varData.CopyTo()).ToList(); + foreach (var dbVariableData in dbVarDataList) + { + var resVarData = await _db.Insertable(dbVariableData).ExecuteReturnEntityAsync(); + variableDataList.Add(resVarData.CopyTo()); + } + + stopwatch.Stop(); + Logger.Info($"新增VariableData{dbVarDataList.Count}个, 耗时:{stopwatch.ElapsedMilliseconds}ms"); + return variableDataList; + } + } /// /// 更新VariableData diff --git a/Models/VariableData.cs b/Models/VariableData.cs index ca981c0..81d6ed8 100644 --- a/Models/VariableData.cs +++ b/Models/VariableData.cs @@ -8,10 +8,90 @@ namespace PMSWPF.Models; /// public partial class VariableData : ObservableObject { + /// + /// 变量唯一标识符。 + /// + public int Id { get; set; } + + /// + /// 变量名称。 + /// + [ObservableProperty] + private string name; + + /// + /// 节点ID,用于标识变量在设备或系统中的唯一路径。 + /// + public string NodeId { get; set; } + + /// + /// 节点ID,用于标识变量在设备或系统中的唯一路径。 + /// + public string S7Address { get; set; } + + + /// + /// 变量描述。 + /// + [ObservableProperty] + private string description = String.Empty; + + /// + /// 协议类型,例如Modbus、OPC UA等。 + /// + public ProtocolType ProtocolType { get; set; } + + /// + /// 信号类型,例如模拟量、数字量等。 + /// + public SignalType SignalType { get; set; } + + /// + /// 数据类型,例如Int、Float、String等。 + /// + public string DataType { get; set; } + + /// + /// 变量当前原始数据值。 + /// + [ObservableProperty] + private string dataValue = String.Empty; + + /// + /// 变量经过转换或格式化后的显示值。 + /// + [ObservableProperty] + private string displayValue = String.Empty; + + /// + /// 指示变量是否处于激活状态。 + /// + public bool IsActive { get; set; } + + /// + /// 指示是否需要保存变量数据。 + /// + public bool IsSave { get; set; } + + /// + /// 指示是否需要对变量进行报警监测。 + /// + public bool IsAlarm { get; set; } + + /// + /// 指示变量是否已被逻辑删除。 + /// + public bool IsDeleted { get; set; } + + /// + /// 指示变量是否已被修改了。 + /// + [ObservableProperty] + private bool isModified; + /// /// 报警的最大值阈值。 /// - public double AlarmMax { get; set; } /// @@ -25,90 +105,17 @@ public partial class VariableData : ObservableObject [ObservableProperty] private string converstion = String.Empty; - /// - /// 数据类型,例如Int、Float、String等。 - /// - public string DataType { get; set; } - - /// - /// 变量当前原始数据值。 - /// - [ObservableProperty] - private string dataValue = String.Empty; - - /// - /// 变量描述。 - /// - [ObservableProperty] - private string description = String.Empty; - - /// - /// 变量唯一标识符。 - /// - public int Id { get; set; } - - /// - /// 变量经过转换或格式化后的显示值。 - /// - [ObservableProperty] - private string displayValue = String.Empty; - - /// - /// 指示是否需要对变量进行报警监测。 - /// - public bool IsAlarm { get; set; } - - /// - /// 指示变量是否处于激活状态。 - /// - public bool IsActive { get; set; } - - /// - /// 指示变量是否已被逻辑删除。 - /// - public bool IsDeleted { get; set; } - - /// - /// 指示变量是否已被修改了。 - /// - [ObservableProperty] - private bool isModified; - - /// - /// 指示是否需要保存变量数据。 - /// - public bool IsSave { get; set; } - - /// - /// 关联的MQTT配置列表。 - /// - public List Mqtts { get; set; } - - /// - /// 变量名称。 - /// - [ObservableProperty] - private string name; - - /// - /// 节点ID,用于标识变量在设备或系统中的唯一路径。 - /// - public string NodeId { get; set; } - - /// - /// 协议类型,例如Modbus、OPC UA等。 - /// - public ProtocolType ProtocolType { get; set; } - /// /// 数据保存的范围或阈值。 /// public double SaveRange { get; set; } /// - /// 信号类型,例如模拟量、数字量等。 + /// 变量数据创建时间。 /// - public SignalType SignalType { get; set; } + [ObservableProperty] + private DateTime createTime; + /// /// 变量数据最后更新时间。 @@ -126,4 +133,9 @@ public partial class VariableData : ObservableObject /// public int VariableTableId { get; set; } + /// + /// 关联的MQTT配置列表。 + /// + public List Mqtts { get; set; } + } \ No newline at end of file diff --git a/PMSWPF.Tests/ExcelHelperTests.cs b/PMSWPF.Tests/ExcelHelperTests.cs index 01da699..77fad39 100644 --- a/PMSWPF.Tests/ExcelHelperTests.cs +++ b/PMSWPF.Tests/ExcelHelperTests.cs @@ -1,9 +1,10 @@ - using NUnit.Framework; using PMSWPF.Helper; using System.Collections.Generic; using System.Data; using System.IO; +using PMSWPF.Enums; +using PMSWPF.Models; namespace PMSWPF.Tests { @@ -17,7 +18,7 @@ namespace PMSWPF.Tests { // Create a temporary file for testing // _testFilePath = Path.Combine(Path.GetTempPath(), "test.xlsx"); - _testFilePath = "e:/test.xlsx"; + _testFilePath = "e:/test.xlsx"; } [TearDown] @@ -35,10 +36,10 @@ namespace PMSWPF.Tests { // Arrange var data = new List - { - new TestData { Id = 1, Name = "Test1" }, - new TestData { Id = 2, Name = "Test2" } - }; + { + new TestData { Id = 1, Name = "Test1" }, + new TestData { Id = 2, Name = "Test2" } + }; // Act ExcelHelper.ExportToExcel(data, _testFilePath); @@ -84,15 +85,51 @@ namespace PMSWPF.Tests Assert.AreEqual("Test1", result.Rows[0]["Name"]); } + [Test] + public void ImportVarDataFormExcel() + { + // Act + _testFilePath = "C:\\Users\\Administrator\\Desktop\\浓度变量.xlsx"; + var dataTable = ExcelHelper.ImportFromExcel(_testFilePath); + // 判断表头的名字 + if (dataTable.Columns[0].ColumnName != "Name" || dataTable.Columns[2].ColumnName != "Data Type" && + dataTable.Columns[3].ColumnName != "Logical Address") + throw new AggregateException( + "Excel表格式不正确:第一列的名字是:Name,第三列的名字是:Data Type,Data Type,第四列的名字是:Logical Address,请检查"); + + + List variableDatas = new List(); + foreach (DataRow dataRow in dataTable.Rows) + { + VariableData variableData = new VariableData(); + variableData.Name=dataRow["Name"].ToString(); + variableData.DataType=SiemensHelper.S7ToCSharpTypeString(dataRow["Data Type"].ToString()) ; + var exS7Addr=dataRow["Logical Address"].ToString(); + if (exS7Addr.StartsWith("%")) + { + variableData.S7Address = exS7Addr.Substring(1); + } + + variableData.ProtocolType = ProtocolType.S7; + variableData.SignalType = SignalType.OtherASignal; + variableDatas.Add(variableData); + } + Assert.Greater(variableDatas.Count, 0); + // Assert + // Assert.AreEqual(2, result.Rows.Count);FDFD + // Assert.AreEqual("1", result.Rows[0]["Id"]); + // Assert.AreEqual("Test1", result.Rows[0]["Name"]); + } + [Test] public void ImportFromExcel_ToListOfObjects_ReturnsCorrectData() { // Arrange var data = new List - { - new TestData { Id = 1, Name = "Test1" }, - new TestData { Id = 2, Name = "Test2" } - }; + { + new TestData { Id = 1, Name = "Test1" }, + new TestData { Id = 2, Name = "Test2" } + }; ExcelHelper.ExportToExcel(data, _testFilePath); // Act @@ -110,4 +147,4 @@ namespace PMSWPF.Tests public string Name { get; set; } } } -} +} \ No newline at end of file diff --git a/Services/DialogService.cs b/Services/DialogService.cs index 636f0f4..37a23f7 100644 --- a/Services/DialogService.cs +++ b/Services/DialogService.cs @@ -107,4 +107,16 @@ public class DialogService :IDialogService } return null; } + + public async Task ShowImportExcelDialog() + { + var vm = new ImportExcelDialogViewModel(); + var dialog = new ImportExcelDialog(vm); + var result = await dialog.ShowAsync(); + if (result == ContentDialogResult.Primary) + { + return vm.FilePath; + } + return null; + } } \ No newline at end of file diff --git a/Services/IDialogService.cs b/Services/IDialogService.cs index ea2581f..7a6da34 100644 --- a/Services/IDialogService.cs +++ b/Services/IDialogService.cs @@ -15,4 +15,5 @@ public interface IDialogService void ShowMessageDialog(string title, string message); Task ShowEditVarDataDialog(VariableData variableData); + Task ShowImportExcelDialog(); } \ No newline at end of file diff --git a/ViewModels/VariableTableViewModel.cs b/ViewModels/VariableTableViewModel.cs index 0456caf..b15c521 100644 --- a/ViewModels/VariableTableViewModel.cs +++ b/ViewModels/VariableTableViewModel.cs @@ -63,6 +63,7 @@ partial class VariableTableViewModel : ViewModelBase IsLoadCompletion = true; } + /// /// 退出当前实体时调用 /// @@ -80,13 +81,12 @@ partial class VariableTableViewModel : ViewModelBase // 不保存数据,还原原来的数据 foreach (var modifiedData in modifiedDatas) { - var oldData = _originalDataVariables.First(od=>od.Id ==modifiedData.Id); - oldData.CopyTo( modifiedData); + var oldData = _originalDataVariables.First(od => od.Id == modifiedData.Id); + oldData.CopyTo(modifiedData); modifiedData.IsModified = false; } return false; - } return true; @@ -107,11 +107,12 @@ partial class VariableTableViewModel : ViewModelBase { modifiedData.IsModified = false; } + NotificationHelper.ShowMessage($"修改的{modifiedDatas.Count}变量保存成功.", NotificationType.Success); } [RelayCommand] - public async void EditVarData(VariableTable variableTable) + private async void EditVarData(VariableTable variableTable) { try { @@ -138,9 +139,53 @@ partial class VariableTableViewModel : ViewModelBase } } + [RelayCommand] + private async void ImprotFromTiaVarTable() + { + try + { + // 让用户选择导入的Excel文件 + var filePath = await _dialogService.ShowImportExcelDialog(); + if (string.IsNullOrEmpty(filePath)) + return; + // 读取Excel转换成VariableData列表 + var importVarDataList = ExcelHelper.ImprotFromTiaVariableTable(filePath); + if (importVarDataList.Count == 0) + return; + + foreach (var variableData in importVarDataList) + { + variableData.CreateTime=DateTime.Now; + variableData.VariableTableId = VariableTable.Id; + } + // 插入数据库 + var resVarDataList= await _varDataRepository.AddAsync(importVarDataList); + //更新界面 + // variableTable.DataVariables.AddRange(resVarDataList); + foreach (var variableData in resVarDataList) + { + variableTable.DataVariables.Add(variableData); + } + DataVariables=new ObservableCollection(resVarDataList); + + string msgSuccess = $"成功导入变量:{resVarDataList.Count}个。"; + Logger.Info(msgSuccess); + NotificationHelper.ShowMessage(msgSuccess, NotificationType.Success); + + } + catch (Exception e) + { + string msg = $"从TIA导入变量的过程中发生了不可预期的错误:"; + Logger.Error(msg + e); + NotificationHelper.ShowMessage(msg + e.Message, NotificationType.Error); + } + + + } + [RelayCommand] - public async void AddVarData(VariableTable variableTable) + private async void AddVarData(VariableTable variableTable) { try { @@ -154,6 +199,7 @@ partial class VariableTableViewModel : ViewModelBase // 更新数据库 await _varDataRepository.UpdateAsync(varData); // 更新当前页面的 + DataVariables.Add(varData); var index = variableTable.DataVariables.IndexOf(SelectedVariableData); // 更新变量表中的 if (index >= 0 && index < variableTable.DataVariables.Count) @@ -168,13 +214,17 @@ partial class VariableTableViewModel : ViewModelBase } } - public void OnVarTableDataChanged(VariableData varData) - { - var originelData = _originalDataVariables.FirstOrDefault(d => d.Id == varData.Id); + // [RelayCommand] + // private async void ImportFromExcel() + // { + // var filePath = await _dialogService.ShowImportExcelDialog(); + // if (!string.IsNullOrEmpty(filePath)) + // { + // // TODO: Implement Excel import logic using the filePath + // NotificationHelper.ShowMessage($"Successfully imported from {filePath}", NotificationType.Success); + // } + // } - // varData.IsModified = originelData.Equals(varData); - // varData.IsModified = originelData.ValueEquals(varData); - } public async Task OnIsActiveChanged(bool active) { diff --git a/Views/VariableTableView.xaml b/Views/VariableTableView.xaml index 268dc6d..7fd4054 100644 --- a/Views/VariableTableView.xaml +++ b/Views/VariableTableView.xaml @@ -61,7 +61,7 @@ - + @@ -70,13 +70,24 @@ - - + + + + + + + + + + @@ -88,6 +99,7 @@ Icon="Setting" Label="Settings" /> + + + @@ -163,9 +179,9 @@ - + + + @@ -181,19 +197,26 @@ SelectedItem="{Binding SignalType}"> - + + + +