Przeglądaj źródła

新增点位文件导入导出功能及PLC连接优化

新增点位数据批量导入/导出(XML),支持产品点位的备份与恢复;在点位管理界面增加相关操作按钮。PLC连接事件处理增加系统参数和点位信息的异步写入,并完善异常日志,提升系统健壮性和易用性。
孝锋 徐 7 miesięcy temu
rodzic
commit
2e53d1ed58

+ 10 - 1
TeamAAS-VM/Core/Management.cs

@@ -817,7 +817,7 @@ namespace TeamAAS_VP.Core
         /// </summary>
         /// <param name="plc"></param>
         /// <param name="isconnected"></param>
-        private void Management_PlcConnectChangedEvent(object sender, bool isconnected)
+        private async void Management_PlcConnectChangedEvent(object sender, bool isconnected)
         {
             IPlc plc = sender as IPlc;
             var sta = Status.FirstOrDefault(s => s.ID == plc.Id);
@@ -831,6 +831,15 @@ namespace TeamAAS_VP.Core
                              sta.Message = $"{plc.Name}{Lang.已连接}";
                              sta.Background = new SolidColorBrush(Colors.Green);
                          }));
+                try
+                {
+                    await WriteSystemParameterToPlcAsync(_configService.GetSystemConfiguration());
+                    await WritePositionToPlcAsync();
+                }
+                catch (Exception ex)
+                {
+                    LogHelper.WriteLogError("PLC连接成功时,写入系统参数和点位信息时出错!", ex);
+                }
             }
             else
             {

+ 191 - 0
TeamAAS-VM/ViewModels/Product/PlcPointParamsViewModel.cs

@@ -2,6 +2,7 @@
 using MahApps.Metro.Controls;
 using MaterialDesignThemes.Wpf;
 using MathNet.Numerics.LinearAlgebra;
+using Microsoft.Win32;
 using NPOI.SS.Formula.Functions;
 using OpenCvSharp.Flann;
 using Prism.Commands;
@@ -14,10 +15,12 @@ using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Drawing;
+using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
+using System.Xml.Serialization;
 using TeamAAS_VP.Controls;
 using TeamAAS_VP.Core;
 using TeamAAS_VP.Core.PLCs;
@@ -311,6 +314,48 @@ namespace TeamAAS_VP.ViewModels.Product
         }
         #endregion
 
+        #region DTOs for import/export
+        public class ProductPointsExport
+        {
+            /// <summary>
+            /// 软件版本号
+            /// </summary>
+            public string SoftwareVersion { get; set; }
+
+            /// <summary>
+            /// 产品名称
+            /// </summary>
+            public string ProductName { get; set; }
+
+            /// <summary>
+            /// 产品描述
+            /// </summary>
+            public string ProductDescription { get; set; }
+
+            /// <summary>
+            /// 设备名称
+            /// </summary>
+            public string DeviceName { get; set; }
+
+            /// <summary>
+            /// 创建日期
+            /// </summary>
+            public DateTime? Created { get; set; }
+
+            public List<PlcPoint> PickCameraPoints { get; set; }
+            public List<PlcPoint> PickPoints { get; set; }
+            public List<PlcPoint> SecPosCameraPoints { get; set; }
+            public List<PlcPoint> ScrewCameraPoints { get; set; }
+            public PlcPoint ScrewCameraLocalPos1 { get; set; }
+            public PlcPoint ScrewCameraLocalPos2 { get; set; }
+            public List<PlcPoint> ScrewPoints { get; set; }
+            public List<PlcPoint> CheckCameraPoints { get; set; }
+            public List<PlcPoint> IndependentCamerPoints { get; set; }
+            public List<PlcPoint> RemovePoints { get; set; }
+            public List<PlcPoint> PressurePlacePoints { get; set; }
+        }
+        #endregion
+
         #region 命令
         private DelegateCommand _NextCommand;
         public DelegateCommand NextCommand =>
@@ -436,6 +481,14 @@ namespace TeamAAS_VP.ViewModels.Product
         private DelegateCommand _SetOffsetCommand;
         public DelegateCommand SetOffsetCommand =>
             _SetOffsetCommand ?? (_SetOffsetCommand = new DelegateCommand(ExecuteSetOffsetCommand));
+
+        private DelegateCommand _ImportPointsCommand;
+        public DelegateCommand ImportPointsCommand =>
+            _ImportPointsCommand ?? (_ImportPointsCommand = new DelegateCommand(ExecuteImportPointsCommand));
+
+        private DelegateCommand _ExportAllPointsCommand;
+        public DelegateCommand ExportAllPointsCommand =>
+            _ExportAllPointsCommand ?? (_ExportAllPointsCommand = new DelegateCommand(ExecuteExportAllPointsCommand));
         #endregion
 
         #region 事件
@@ -2017,6 +2070,144 @@ namespace TeamAAS_VP.ViewModels.Product
                 MessageBox.Show(ex.Message);
             }
         }
+
+        /// <summary>
+        /// 导出所有点位到本地文件(XML)
+        /// </summary>
+        void ExecuteExportAllPointsCommand()
+        {
+            try
+            {
+                if (SelectProduct == null)
+                {
+                    MessageBox.Show("未选择产品", Lang.错误, MessageBoxButton.OK, MessageBoxImage.Warning);
+                    return;
+                }
+
+                var dlg = new SaveFileDialog();
+                dlg.Filter = "Plc Product Points File|*.plcproductpoints.xml|All files|*.*";
+                dlg.FileName = SelectProduct != null ? ($"{SelectProduct.Name}_allpoints_{DateTime.Now:yyyyMMdd_HHmmss}.plcproductpoints.xml") : ($"product_points_{DateTime.Now:yyyyMMdd_HHmmss}.plcproductpoints.xml");
+                var res = dlg.ShowDialog();
+                if (res != true) return;
+
+                var filePath = dlg.FileName;
+                // 构建导出对象
+                var export = new ProductPointsExport
+                {
+                    SoftwareVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
+                    ProductName = SelectProduct.Name,
+                    ProductDescription = SelectProduct.Description,
+                    DeviceName = _configService.GetDeviceInfo().Station,
+                    Created = DateTime.Now,
+                    PickCameraPoints = SelectProduct.PickCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    PickPoints = SelectProduct.PickPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    SecPosCameraPoints = SelectProduct.SecPosCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    ScrewCameraPoints = SelectProduct.ScrewCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    ScrewCameraLocalPos1 = SelectProduct.ScrewCameraLocalPos1?.Clone() ?? new PlcPoint(),
+                    ScrewCameraLocalPos2 = SelectProduct.ScrewCameraLocalPos2?.Clone() ?? new PlcPoint(),
+                    ScrewPoints = SelectProduct.ScrewPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    CheckCameraPoints = SelectProduct.CheckCameraPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    IndependentCamerPoints = SelectProduct.IndependentCamerPoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    RemovePoints = SelectProduct.RemovePoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                    PressurePlacePoints = SelectProduct.PressurePlacePoints?.Select(p => p.Clone()).ToList() ?? new List<PlcPoint>(),
+                };
+
+                var serializer = new XmlSerializer(typeof(ProductPointsExport));
+                using (var fs = File.Create(filePath))
+                {
+                    serializer.Serialize(fs, export);
+                }
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "导出完成", Duration = 1 });
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("导出点位时出错", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+        }
+
+        /// <summary>
+        /// 导入点位文件,覆盖当前点位
+        /// </summary>
+        void ExecuteImportPointsCommand()
+        {
+            try
+            {
+                var dlg = new OpenFileDialog();
+                dlg.Filter = "Plc Points File|*.plcproductpoints.xml|All files|*.*";
+                var res = dlg.ShowDialog();
+                if (res != true) return;
+                var filePath = dlg.FileName;
+
+                // 验证并读取文件(ProductPointsExport)
+                var serializer = new XmlSerializer(typeof(ProductPointsExport));
+                ProductPointsExport import = null;
+                using (var fs = File.OpenRead(filePath))
+                {
+                    try
+                    {
+                        import = (ProductPointsExport)serializer.Deserialize(fs);
+                    }
+                    catch (Exception ex)
+                    {
+                        MessageBox.Show("无效的点位文件或文件已损坏", Lang.错误, MessageBoxButton.OK, MessageBoxImage.Error);
+                        LogHelper.WriteLogError("导入点位文件解析失败", ex);
+                        return;
+                    }
+                }
+
+                if (import == null)
+                {
+                    MessageBox.Show("导入的点位文件为空", Lang.提示, MessageBoxButton.OK, MessageBoxImage.Information);
+                    return;
+                }
+
+                // 提示用户是否覆盖
+                if (MessageBox.Show("确认要导入点位文件并覆盖当前所有点位吗", "导入点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                {
+                    return;
+                }
+
+                // 覆盖 SelectProduct 下的各类点集合
+                SelectProduct.PickCameraPoints = new ObservableCollection<PlcPoint>(import.PickCameraPoints ?? new List<PlcPoint>());
+                SelectProduct.PickPoints = new ObservableCollection<PlcPoint>(import.PickPoints ?? new List<PlcPoint>());
+                SelectProduct.SecPosCameraPoints = new ObservableCollection<PlcPoint>(import.SecPosCameraPoints ?? new List<PlcPoint>());
+                SelectProduct.ScrewCameraPoints = new ObservableCollection<PlcPoint>(import.ScrewCameraPoints ?? new List<PlcPoint>());
+                SelectProduct.ScrewCameraLocalPos1 = import.ScrewCameraLocalPos1 ?? new PlcPoint();
+                SelectProduct.ScrewCameraLocalPos2 = import.ScrewCameraLocalPos2 ?? new PlcPoint();
+                SelectProduct.ScrewPoints = new ObservableCollection<PlcPoint>(import.ScrewPoints ?? new List<PlcPoint>());
+                SelectProduct.CheckCameraPoints = new ObservableCollection<PlcPoint>(import.CheckCameraPoints ?? new List<PlcPoint>());
+                SelectProduct.IndependentCamerPoints = new ObservableCollection<PlcPoint>(import.IndependentCamerPoints ?? new List<PlcPoint>());
+                SelectProduct.RemovePoints = new ObservableCollection<PlcPoint>(import.RemovePoints ?? new List<PlcPoint>());
+                SelectProduct.PressurePlacePoints = new ObservableCollection<PlcPoint>(import.PressurePlacePoints ?? new List<PlcPoint>());
+
+                // 重新编号每个集合
+                Action<ObservableCollection<PlcPoint>> renumber = (col) =>
+                {
+                    for (int i = 0; i < col.Count; i++) col[i].Number = i + 1;
+                };
+                renumber(SelectProduct.PickCameraPoints);
+                renumber(SelectProduct.PickPoints);
+                renumber(SelectProduct.SecPosCameraPoints);
+                renumber(SelectProduct.ScrewCameraPoints);
+                renumber(SelectProduct.ScrewPoints);
+                renumber(SelectProduct.CheckCameraPoints);
+                renumber(SelectProduct.IndependentCamerPoints);
+                renumber(SelectProduct.RemovePoints);
+                renumber(SelectProduct.PressurePlacePoints);
+
+                // 根据当前 SelectedIndex 切换 Points 绑定到对应集合
+                ExecuteSelectionChangedCommand();
+
+                LogHelper.WriteLogDebug("导入点位文件成功");
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "导入完成", Duration = 1 });
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("导入点位时出错", ex);
+                _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
+            }
+        }
         #endregion
 
         #region 继承

+ 11 - 0
TeamAAS-VM/Views/Product/PlcPointParams.xaml

@@ -353,6 +353,17 @@
                                     MinWidth="80"
                                     materialDesign:ButtonAssist.CornerRadius="5"
                                     Command="{Binding MovePointDownCommand}" />
+                            <!-- 导入/导出点位文件 -->
+                            <Button Content="导入点位文件"
+                                    Margin="5,2"
+                                    MinWidth="120"
+                                    materialDesign:ButtonAssist.CornerRadius="5"
+                                    Command="{Binding ImportPointsCommand}" />
+                            <Button Content="导出所有点位"
+                                    Margin="5,2"
+                                    MinWidth="120"
+                                    materialDesign:ButtonAssist.CornerRadius="5"
+                                    Command="{Binding ExportAllPointsCommand}" />
                             <!--<Button Content="CAD导入点位"
                                     Margin="5,2"
                                     MinWidth="80"