Преглед изворни кода

压力采集与点位补偿功能增强,系统参数扩展

本次更新完善了压力采集流程,支持多通道压力实时采集、超时与数据保存,并在主界面动态显示压力曲线。新增点位补偿属性及批量编辑对话框,支持一键清除补偿。系统参数增加压力传感器配置,界面支持可视化编辑与路径选择。优化视觉流程绑定、CT时间统计及相关界面交互,提升系统灵活性与可维护性。
孝锋 徐 пре 7 месеци
родитељ
комит
efdb0ec493

+ 1 - 0
TeamAAS-VM/App.xaml.cs

@@ -210,6 +210,7 @@ namespace TeamAAS_VP
             containerRegistry.RegisterDialog<ImageDisplay>();
             containerRegistry.RegisterDialog<VisionStaticAccuracyAnalyzer>();
             containerRegistry.RegisterDialog<VisionDynamicAccuracyAnalyzer>();
+            containerRegistry.RegisterDialog<PlcPointOffserParams>();
             //**************************************************************************************
 
             // 注册 SQLSugar 客户端(单例模式)

+ 259 - 43
TeamAAS-VM/Core/Management.cs

@@ -80,6 +80,31 @@ namespace TeamAAS_VP.Core
         Timer yieldtimer;
         private DateTime StartTime = DateTime.Now;
 
+        // Pressure collection
+        /// <summary>
+        /// 压力采集信号控制CTS
+        /// </summary>
+        private CancellationTokenSource[] _pressureCts = new CancellationTokenSource[10];
+        /// <summary>
+        /// 压力采集超时CTS
+        /// </summary>
+        private CancellationTokenSource[] _pressureTimeoutCts = new CancellationTokenSource[10];
+        /// <summary>
+        /// 压力采集CTS
+        /// </summary>
+        private CancellationTokenSource[] _pressureLinkedCts = new CancellationTokenSource[10];
+        /// <summary>
+        /// 压力数据集合
+        /// </summary>
+        private List<(DateTime Timestamp, float Value)>[] _pressureSamples = new List<(DateTime, float)>[10];
+        /// <summary>
+        /// 采样间隔毫秒
+        /// </summary>
+        private int _pressureSampleIntervalMs = 50; //采样间隔毫秒
+        /// <summary>
+        /// 超时自动停止秒数
+        /// </summary>
+        private int _pressureMaxDurationSeconds = 30; //超时自动停止秒数
         #endregion
 
         #region 属性
@@ -160,6 +185,15 @@ namespace TeamAAS_VP.Core
 
         public Dictionary<string, object> BackupObject { get; set; } = new Dictionary<string, object>();
 
+        private double _CTtime;
+        /// <summary>
+        /// ct
+        /// </summary>
+        public double CTtime
+        {
+            get { return _CTtime; }
+            set { SetProperty(ref _CTtime, value); }
+        }
         #endregion
 
         #region 命令
@@ -1073,6 +1107,7 @@ namespace TeamAAS_VP.Core
         Int16 _LastRequestPosition = 0;
         Int16 _LastPickINC = 0;
         Int16[] _LastMesCheck=new Int16[10];
+        DateTime[] _LastMesCheckTime = new DateTime[10];
 
         /// <summary>
         /// PLC命令触发时
@@ -1915,6 +1950,10 @@ namespace TeamAAS_VP.Core
                             //位置编号
                             Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
                             SendTaskMessage($"编号:{positionIndex}", MessageLevel.Info);
+
+                            var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, positionIndex));
+                            // 开始采集压力值
+                            StartPressureCollection(currentProduct.Name, code, positionIndex);
                         }
                         else
                         {
@@ -1944,48 +1983,51 @@ namespace TeamAAS_VP.Core
                             Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
                             SendTaskMessage($"编号:{positionIndex}", MessageLevel.Info);
                             //获取当前锁付点
-                            var screwPoint = currentProduct.ScrewPoints.FirstOrDefault(p => p.Number == positionIndex);
-                            //获取当前的机器人点位
-                            var robot = _robotService.GetAllRobots().FirstOrDefault();
-                            var currentPosition = robot.GetRobotPos();
-                            //读取压力值
-                            float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
-
-
-                            await Task.Delay(60);
-                            //获取电批结果
-                            bool isSucced = ScrewDriver.GetData();
-                            LockResult lockResult = new LockResult();
-                            lockResult.ScrewdriverGetDataSucceed = isSucced;
-                            lockResult.Number = positionIndex;
-                            lockResult.LockPassed = ScrewDriver.Success;
-                            lockResult.ProductNumber = _productService.CurrentProductCode;
-                            lockResult.LockTurns = (float)ScrewDriver.Truns;
-                            lockResult.LockTorque = (float)ScrewDriver.TorqueValue;
-                            lockResult.LockDuration = (float)ScrewDriver.FinalTime;
-                            lockResult.ScrewdriverProgramNumber = ScrewDriver.ProgramNumber;
-                            lockResult.ResultDetails = ScrewDriver.ErrorInfo;
-                            lockResult.Pressure = pressure;
-                            lockResult.TargetTorque = ScrewDriver.TargetTorque;
-                            lockResult.TargetTurnsUpperLimit = ScrewDriver.TargetTurnsUpperLimit;
-                            lockResult.TargetTurnsLowerLimit = ScrewDriver.TargetTurnsLowerLimit;
-                            lockResult.TargetLockSpeed = ScrewDriver.TargetLockSpeed;
-                            lockResult.StartPositionX = currentPosition.X;
-                            lockResult.StartPositionY = currentPosition.Y;
-                            lockResult.StartPositionZ = screwPoint.Z_Position_Start;
-                            lockResult.EndPositionZ = currentPosition.Z;
-                            lockResult.LockDescentSpeed = screwPoint.Z_Velocity_Stop;
-                            lockResult.FeederNumber = screwPoint != null ? screwPoint.Feeder : 0;
-                            lockResult.NozzleNumber = "";
-                            lockResult.OperatorName = _systemDatabaseService.GetCurrentUser().UserName;
-                            lockResult.ProductImagePath = "";
-                            lockResult.WaveDatas = ScrewDriver.WaveDatas;
-                            App.Current.Dispatcher.Invoke(() =>
-                            {
-                                _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
-                            });
-                            await _systemDatabaseService.RecordLockResultAsync(lockResult);
+                            //var screwPoint = currentProduct.ScrewPoints.FirstOrDefault(p => p.Number == positionIndex);
+                            ////获取当前的机器人点位
+                            //var robot = _robotService.GetAllRobots().FirstOrDefault();
+                            //var currentPosition = robot.GetRobotPos();
+                            ////读取压力值
+                            //float pressure = plc.ReadNode<float>(addressConfig.In_PressureValue.Address);
+
+
+                            //await Task.Delay(60);
+                            ////获取电批结果
+                            //bool isSucced = ScrewDriver.GetData();
+                            //LockResult lockResult = new LockResult();
+                            //lockResult.ScrewdriverGetDataSucceed = isSucced;
+                            //lockResult.Number = positionIndex;
+                            //lockResult.LockPassed = ScrewDriver.Success;
+                            //lockResult.ProductNumber = _productService.CurrentProductCode;
+                            //lockResult.LockTurns = (float)ScrewDriver.Truns;
+                            //lockResult.LockTorque = (float)ScrewDriver.TorqueValue;
+                            //lockResult.LockDuration = (float)ScrewDriver.FinalTime;
+                            //lockResult.ScrewdriverProgramNumber = ScrewDriver.ProgramNumber;
+                            //lockResult.ResultDetails = ScrewDriver.ErrorInfo;
+                            //lockResult.Pressure = pressure;
+                            //lockResult.TargetTorque = ScrewDriver.TargetTorque;
+                            //lockResult.TargetTurnsUpperLimit = ScrewDriver.TargetTurnsUpperLimit;
+                            //lockResult.TargetTurnsLowerLimit = ScrewDriver.TargetTurnsLowerLimit;
+                            //lockResult.TargetLockSpeed = ScrewDriver.TargetLockSpeed;
+                            //lockResult.StartPositionX = currentPosition.X;
+                            //lockResult.StartPositionY = currentPosition.Y;
+                            //lockResult.StartPositionZ = screwPoint.Z_Position_Start;
+                            //lockResult.EndPositionZ = currentPosition.Z;
+                            //lockResult.LockDescentSpeed = screwPoint.Z_Velocity_Stop;
+                            //lockResult.FeederNumber = screwPoint != null ? screwPoint.Feeder : 0;
+                            //lockResult.NozzleNumber = "";
+                            //lockResult.OperatorName = _systemDatabaseService.GetCurrentUser().UserName;
+                            //lockResult.ProductImagePath = "";
+                            //lockResult.WaveDatas = ScrewDriver.WaveDatas;
+                            //App.Current.Dispatcher.Invoke(() =>
+                            //{
+                            //    _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
+                            //});
+                            //await _systemDatabaseService.RecordLockResultAsync(lockResult);
                             await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
+                            var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, positionIndex));
+                            // 停止采集压力并保存
+                            await StopAndSavePressureCollectionAsync(currentProduct.Name, code, positionIndex);
                         }
                         else
                         {
@@ -2103,7 +2145,7 @@ namespace TeamAAS_VP.Core
                                 {
                                     //这里缺少从MES获取产品配方的内容,需要补充
 
-
+                                    _LastMesCheckTime[i] = DateTime.UtcNow;
 
                                     (bool isSuccess, string response) = await _mesService.StationGetAsync(code, 2);
                                     if (i == 0)
@@ -2135,8 +2177,12 @@ namespace TeamAAS_VP.Core
                                     SendTaskMessage($"收到{i}上传本站数据请求...", MessageLevel.Debug);
 
                                     //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
+                                    if(i == 0)
+                                    {
+                                        CTtime = DateTime.UtcNow.Subtract(_LastMesCheckTime[i]).TotalSeconds;
+                                    }
 
-                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(code, true, DateTime.Now, DateTime.Now);
+                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(code, true, _LastMesCheckTime[i], DateTime.Now);
                                     //假设上传成功,这里缺少上传失败的处理
 
                                     await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
@@ -2170,6 +2216,176 @@ namespace TeamAAS_VP.Core
             });
         }
 
+        #region Pressure collection helpers
+        /// <summary>
+        /// 开始采集压力值
+        /// </summary>
+        /// <param name="productName">配方名称</param>
+        /// <param name="productCode">产品编号</param>
+        /// <param name="Index">编号</param>
+        private void StartPressureCollection(string productName, string productCode, int Index)
+        {
+            try
+            {
+                // cancel existing if any
+                _pressureCts[Index]?.Cancel();
+                _pressureTimeoutCts[Index]?.Cancel();
+                _pressureLinkedCts[Index]?.Dispose();
+                _pressureSamples[Index].Clear();
+
+                _pressureCts[Index] = new CancellationTokenSource();
+                _pressureTimeoutCts[Index] = new CancellationTokenSource();
+
+                // timeout after configured seconds
+                _pressureTimeoutCts[Index].CancelAfter(TimeSpan.FromSeconds(_pressureMaxDurationSeconds));
+
+                // link tokens so either stop or timeout cancels
+                _pressureLinkedCts[Index] = CancellationTokenSource.CreateLinkedTokenSource(_pressureCts[Index].Token, _pressureTimeoutCts[Index].Token);
+
+                var token = _pressureLinkedCts[Index].Token;
+                var addressConfig = _configService.GetPlcAddresses();
+                var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
+                if (plc == null || !plc.IsConnected) return;
+                Task.Run(async () =>
+                {
+                    SendTaskMessage($"Pressure collection started for position {Index}", MessageLevel.Debug);
+                    while (!token.IsCancellationRequested)
+                    {
+                        try
+                        {
+                            float pressure = plc.ReadNode<float>(string.Format(addressConfig.In_PressureValue.Address, Index));
+                            lock (_pressureSamples[Index])
+                            {
+                                _pressureSamples[Index].Add((DateTime.Now, pressure));
+                            }
+                        }
+                        catch (Exception ex)
+                        {
+                            LogHelper.WriteLogError("采集压力值时出错", ex);
+                        }
+                        await Task.Delay(_pressureSampleIntervalMs);
+                    }
+                    // if cancelled due to timeout
+                    if (_pressureTimeoutCts[Index].IsCancellationRequested && !_pressureCts[Index].IsCancellationRequested)
+                    {
+                        SendTaskMessage("Pressure collection timed out, saving collected data.", MessageLevel.Alarm);
+                        await StopAndSavePressureCollectionAsync(productName, productCode, Index);
+                    }
+                }, token);
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("StartPressureCollection error", ex);
+            }
+        }
+
+        /// <summary>
+        /// 停止采集并保存压力数据
+        /// </summary>
+        /// <param name="productName"></param>
+        /// <param name="productCode"></param>
+        /// <param name="positionIndex"></param>
+        /// <returns></returns>
+        private async Task StopAndSavePressureCollectionAsync(string productName, string productCode, int Index)
+        {
+            try
+            {
+                // cancel sampling
+                _pressureCts[Index]?.Cancel();
+                // allow worker to observe cancel
+                await Task.Delay(50);
+
+                List<(DateTime Timestamp, float Value)> snapshot;
+                lock (_pressureSamples[Index])
+                {
+                    snapshot = new List<(DateTime, float)>(_pressureSamples[Index]);
+                }
+
+                if (snapshot.Count == 0)
+                {
+                    SendTaskMessage("No pressure samples collected.", MessageLevel.Info);
+                    return;
+                }
+
+                // save to file under configured path
+                try
+                {
+                    //获取系统参数
+                    var systemConfig = _configService.GetSystemConfiguration();
+                    if (systemConfig.PressureSensorConfig == null || systemConfig.PressureSensorConfig.Count <= 0)
+                    {
+                        SendTaskMessage("当前没有配置任何压力传感器!", MessageLevel.Alarm);
+                        return;
+                    }
+                    //获取当前压力传感器配置
+                    var pressureSensorConfig = systemConfig.PressureSensorConfig.FirstOrDefault(p => p.SensorId == Index);
+                    if (pressureSensorConfig == null)
+                    {
+                        SendTaskMessage($"当前压力传感器配置不存在!- {Index}", MessageLevel.Alarm);
+                        return;
+                    }
+                    //PressureFinishNotification : Prism.Events.PubSubEvent<(bool IsSuccess, int Index, (DateTime Timestamp, float Value)[] values,string SavePath )>
+                    string basePath = pressureSensorConfig?.PressureCurvePath ?? Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
+                    string datePath = DateTime.Now.ToString("yyyy-MM") + "\\" + DateTime.Now.ToString("yyyy-MM-dd") + "\\";
+                    string dirPath = Path.Combine(basePath, datePath, productName ?? "UnknownProduct", productCode ?? DateTime.Now.ToString("yyyyMMddHHmmssfff"));
+                    if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
+                    string csvfileName = $"pressure-{productCode}-{Index}-{DateTime.Now.ToString("HHmmss")}.csv";
+                    string csvPath = Path.Combine(dirPath, csvfileName);
+                    string pngfileName = $"pressure-{productCode}-{Index}-{DateTime.Now.ToString("HHmmss")}.png";
+                    string pngPath = Path.Combine(dirPath, pngfileName);
+                    if (!pressureSensorConfig.IsSavePressureCurve)
+                    {
+                        csvPath = string.Empty;
+                        pngPath = string.Empty;
+                    }
+
+                    App.Current.Dispatcher.Invoke(() =>
+                    {
+                        _eventAggregator.GetEvent<PressureFinishNotification>().Publish((true, Index, snapshot.ToArray(), pngPath));
+                    });
+                    //判断是否保存锁付曲线
+                    if (pressureSensorConfig.IsSavePressureCurve)
+                    {
+                        if (!string.IsNullOrEmpty(csvPath))
+                        {
+                            var sb = new StringBuilder();
+                            sb.AppendLine("Timestamp,Value");
+                            foreach (var s in snapshot)
+                            {
+                                sb.AppendLine($"{s.Timestamp:O},{s.Value}");
+                            }
+
+                            File.WriteAllText(csvPath, sb.ToString());
+                            SendTaskMessage($"Pressure samples saved to {csvPath}", MessageLevel.Debug);
+                        }
+
+                    }
+                }
+                catch (Exception ex)
+                {
+                    LogHelper.WriteLogError("保存压力采样文件时出错", ex);
+                    SendTaskMessage("保存压力采样文件时出错: " + ex.Message, MessageLevel.Error);
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("StopAndSavePressureCollectionAsync error", ex);
+            }
+            finally
+            {
+                try
+                {
+                    _pressureLinkedCts[Index]?.Cancel();
+                    _pressureLinkedCts[Index]?.Dispose();
+                    _pressureTimeoutCts[Index]?.Dispose();
+                    _pressureCts[Index]?.Dispose();
+                    _pressureSamples[Index].Clear();
+                }
+                catch { }
+            }
+        }
+        #endregion
+
         private async void DoYieldTime(object state)
         {
             try

+ 7 - 1
TeamAAS-VM/Events/LockFinishNotification.cs

@@ -7,7 +7,13 @@ using TeamAAS_VP.Models;
 
 namespace TeamAAS_VP.Events
 {
-    public class LockFinishNotification: Prism.Events.PubSubEvent<LockResult>
+    public class LockFinishNotification : Prism.Events.PubSubEvent<LockResult>
     {
     }
+
+    //保压完成通知
+    public class PressureFinishNotification : Prism.Events.PubSubEvent<(bool IsSuccess, int Index, (DateTime Timestamp, float Value)[] values, string SavePath)>
+    {
+
+    }
 }

+ 1 - 1
TeamAAS-VM/Models/PLC/PlcAddressConfig.cs

@@ -929,7 +929,7 @@ namespace TeamAAS_VP.Models.PLC
             In_WorkDone.Description = "锁附/组装结束 =1OK =2NG";
 
             In_PressureValue = Ensure(In_PressureValue);
-            In_PressureValue.Address = "ns=4;s=DB_DriveControl|AICtrl[1].Status.UserData";
+            In_PressureValue.Address = "ns=4;s=DB_DriveControl|AICtrl[{0}].Status.UserData";
             In_PressureValue.DataType = "float";
             In_PressureValue.Description = "压力值";
 

+ 157 - 7
TeamAAS-VM/Models/PLC/PlcPoint.cs

@@ -13,6 +13,9 @@ namespace TeamAAS_VP.Models.PLC
     public class PlcPoint : BindableBase
     {
         private int _Number;
+        /// <summary>
+        /// 点位编号
+        /// </summary>
         public int Number
         {
             get { return _Number; }
@@ -20,6 +23,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private string _Label;
+        /// <summary>
+        /// 点位标签
+        /// </summary>
         public string Label
         {
             get { return _Label; }
@@ -27,6 +33,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _X_Position;
+        /// <summary>
+        /// X轴位置
+        /// </summary>
         public float X_Position
         {
             get { return _X_Position; }
@@ -34,6 +43,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _X_Velocity;
+        /// <summary>
+        /// X轴速度
+        /// </summary>
         public float X_Velocity
         {
             get { return _X_Velocity; }
@@ -41,6 +53,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Y_Position;
+        /// <summary>
+        /// Y轴位置
+        /// </summary>
         public float Y_Position
         {
             get { return _Y_Position; }
@@ -48,6 +63,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Y_Velocity;
+        /// <summary>
+        /// Y轴速度
+        /// </summary>
         public float Y_Velocity
         {
             get { return _Y_Velocity; }
@@ -55,6 +73,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Z_Position_Start;
+        /// <summary>
+        /// Z轴起点位置
+        /// </summary>
         public float Z_Position_Start
         {
             get { return _Z_Position_Start; }
@@ -62,6 +83,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Z_Velocity_Start;
+        /// <summary>
+        /// Z轴起点速度
+        /// </summary>
         public float Z_Velocity_Start
         {
             get { return _Z_Velocity_Start; }
@@ -69,6 +93,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Z_Position_Stop;
+        /// <summary>
+        /// Z轴终点位置
+        /// </summary>
         public float Z_Position_Stop
         {
             get { return _Z_Position_Stop; }
@@ -76,6 +103,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Z_Velocity_Stop;
+        /// <summary>
+        /// Z轴终点速度
+        /// </summary>
         public float Z_Velocity_Stop
         {
             get { return _Z_Velocity_Stop; }
@@ -83,6 +113,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _U_Position;
+        /// <summary>
+        /// U轴位置
+        /// </summary>
         public float U_Position
         {
             get { return _U_Position; }
@@ -90,6 +123,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _U_Velocity;
+        /// <summary>
+        /// U轴速度
+        /// </summary>
         public float U_Velocity
         {
             get { return _U_Velocity; }
@@ -97,6 +133,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _R_Position;
+        /// <summary>
+        /// R轴位置
+        /// </summary>
         public float R_Position
         {
             get { return _R_Position; }
@@ -104,6 +143,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _R_Velocity;
+        /// <summary>
+        /// R轴速度
+        /// </summary>
         public float R_Velocity
         {
             get { return _R_Velocity; }
@@ -111,6 +153,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private float _Torque;
+        /// <summary>
+        /// 扭矩值
+        /// </summary>
         public float Torque
         {
             get { return _Torque; }
@@ -118,6 +163,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private Int16 _Feeder;
+        /// <summary>
+        /// Feeder编号
+        /// </summary>
         public Int16 Feeder
         {
             get { return _Feeder; }
@@ -125,6 +173,9 @@ namespace TeamAAS_VP.Models.PLC
         }
 
         private Int16 _ScrewProNum;
+        /// <summary>
+        /// 电批程序号
+        /// </summary>
         public Int16 ScrewProNum
         {
             get { return _ScrewProNum; }
@@ -133,12 +184,95 @@ namespace TeamAAS_VP.Models.PLC
 
         //描述
         private string _Description;
+        /// <summary>
+        /// 点位描述
+        /// </summary>
         public string Description
         {
             get { return _Description; }
             set { SetProperty(ref _Description, value); }
         }
 
+        private Guid _VisionProcessID;
+        /// <summary>
+        /// 视觉流程ID
+        /// </summary>
+        public Guid VisionProcessID
+        {
+            get { return _VisionProcessID; }
+            set { SetProperty(ref _VisionProcessID, value); }
+        }
+
+        private string _VisionProcessName;
+        /// <summary>
+        /// 视觉流程名称
+        /// </summary>
+        public string VisionProcessName
+        {
+            get { return _VisionProcessName; }
+            set { SetProperty(ref _VisionProcessName, value); }
+        }
+
+        private float _X_Offset;
+        /// <summary>
+        /// X轴补偿值
+        /// </summary>
+        public float X_Offset
+        {
+            get { return _X_Offset; }
+            set { SetProperty(ref _X_Offset, value); }
+        }
+
+        private float _Y_Offset;
+        /// <summary>
+        /// Y轴补偿值
+        /// </summary>
+        public float Y_Offset
+        {
+            get { return _Y_Offset; }
+            set { SetProperty(ref _Y_Offset, value); }
+        }
+
+        private float _Z_Start_Offset;
+        /// <summary>
+        /// Z轴起点补偿值
+        /// </summary>
+        public float Z_Start_Offset
+        {
+            get { return _Z_Start_Offset; }
+            set { SetProperty(ref _Z_Start_Offset, value); }
+        }
+
+        private float _Z_Stop_Offset;
+        /// <summary>
+        /// Z轴终点补偿值
+        /// </summary>
+        public float Z_Stop_Offset
+        {
+            get { return _Z_Stop_Offset; }
+            set { SetProperty(ref _Z_Stop_Offset, value); }
+        }
+
+        private float _U_Offset;
+        /// <summary>
+        /// U轴补偿值
+        /// </summary>
+        public float U_Offset
+        {
+            get { return _U_Offset; }
+            set { SetProperty(ref _U_Offset, value); }
+        }
+
+        private float _R_Offset;
+        /// <summary>
+        /// R轴补偿值
+        /// </summary>
+        public float R_Offset
+        {
+            get { return _R_Offset; }
+            set { SetProperty(ref _R_Offset, value); }
+        }
+
         public PlcPoint()
         {
             Number = 0;
@@ -157,6 +291,14 @@ namespace TeamAAS_VP.Models.PLC
             Torque = 0;
             Feeder = 0;
             ScrewProNum = 0;
+            Description = string.Empty;
+            X_Offset = 0;
+            Y_Offset = 0;
+            Z_Start_Offset = 0;
+            Z_Stop_Offset = 0;
+            U_Offset = 0;
+            R_Offset = 0;
+
         }
 
         public PlcPoint Clone()
@@ -180,7 +322,15 @@ namespace TeamAAS_VP.Models.PLC
                 Torque = this.Torque,
                 Feeder = this.Feeder,
                 ScrewProNum = this.ScrewProNum,
-                Description = this.Description
+                Description = this.Description,
+                VisionProcessID = this.VisionProcessID,
+                VisionProcessName = this.VisionProcessName,
+                X_Offset = this.X_Offset,
+                Y_Offset = this.Y_Offset,
+                Z_Start_Offset = this.Z_Start_Offset,
+                Z_Stop_Offset = this.Z_Stop_Offset,
+                U_Offset = this.U_Offset,
+                R_Offset = this.R_Offset
             };
         }
 
@@ -193,17 +343,17 @@ namespace TeamAAS_VP.Models.PLC
         public async Task<bool> WriteToPlcAddress(PlcPointAddress plcAddress, OpcUaClientPLC pLC)
         {
             Dictionary<string, object> nodeValues = new Dictionary<string, object>();
-            nodeValues.Add(string.Format(plcAddress.X_Position.Address, Number), X_Position);
+            nodeValues.Add(string.Format(plcAddress.X_Position.Address, Number), X_Position + X_Offset);
             nodeValues.Add(string.Format(plcAddress.X_Velocity.Address, Number), X_Velocity);
-            nodeValues.Add(string.Format(plcAddress.Y_Position.Address, Number), Y_Position);
+            nodeValues.Add(string.Format(plcAddress.Y_Position.Address, Number), Y_Position + Y_Offset);
             nodeValues.Add(string.Format(plcAddress.Y_Velocity.Address, Number), Y_Velocity);
-            nodeValues.Add(string.Format(plcAddress.Z_Position_Start.Address, Number), Z_Position_Start);
+            nodeValues.Add(string.Format(plcAddress.Z_Position_Start.Address, Number), Z_Position_Start + Z_Start_Offset);
             nodeValues.Add(string.Format(plcAddress.Z_Velocity_Start.Address, Number), Z_Velocity_Start);
-            nodeValues.Add(string.Format(plcAddress.Z_Position_Stop.Address, Number), Z_Position_Stop);
+            nodeValues.Add(string.Format(plcAddress.Z_Position_Stop.Address, Number), Z_Position_Stop + Z_Stop_Offset);
             nodeValues.Add(string.Format(plcAddress.Z_Velocity_Stop.Address, Number), Z_Velocity_Stop);
-            nodeValues.Add(string.Format(plcAddress.U_Position.Address, Number), U_Position);
+            nodeValues.Add(string.Format(plcAddress.U_Position.Address, Number), U_Position + U_Offset);
             nodeValues.Add(string.Format(plcAddress.U_Velocity.Address, Number), U_Velocity);
-            nodeValues.Add(string.Format(plcAddress.R_Position.Address, Number), R_Position);
+            nodeValues.Add(string.Format(plcAddress.R_Position.Address, Number), R_Position + R_Offset);
             nodeValues.Add(string.Format(plcAddress.R_Velocity.Address, Number), R_Velocity);
             nodeValues.Add(string.Format(plcAddress.Torque.Address, Number), Torque);
             nodeValues.Add(string.Format(plcAddress.Feeder.Address, Number), Feeder);

+ 59 - 0
TeamAAS-VM/Models/SystemConfiguration.cs

@@ -1,5 +1,6 @@
 using Prism.Mvvm;
 using System;
+using System.Collections.ObjectModel;
 using System.Reflection;
 using TeamAAS_VP.Enums;
 
@@ -196,6 +197,17 @@ namespace TeamAAS_VP.Models
             set => SetProperty(ref _ScrewTeachNum, value);
         }
 
+        private ObservableCollection<PressureSensorSettings> _PressureSensorConfig;
+        /// <summary>
+        /// 压力传感器配置列表
+        /// </summary>
+        public ObservableCollection<PressureSensorSettings> PressureSensorConfig
+        {
+            get { return _PressureSensorConfig; }
+            set { SetProperty(ref _PressureSensorConfig, value); }
+        }
+
+
         /// <summary>
         /// 字体大小子设置
         /// </summary>
@@ -237,5 +249,52 @@ namespace TeamAAS_VP.Models
             private double _captions4 = 8;
             public double Captions4 { get => _captions4; set => SetProperty(ref _captions4, value); }
         }
+
+        /// <summary>
+        /// 压力传感器配置
+        /// </summary>
+        public class PressureSensorSettings : BindableBase
+        {
+            private string _sensorName;
+            /// <summary>
+            /// 压力传感器的名称
+            /// </summary>
+            public string SensorName
+            {
+                get => _sensorName;
+                set => SetProperty(ref _sensorName, value);
+            }
+
+            private int _sensorId;
+            /// <summary>
+            /// 压力传感器的编号
+            /// </summary>
+            public int SensorId
+            {
+                get => _sensorId;
+                set => SetProperty(ref _sensorId, value);
+            }
+
+            private bool _IsSavePressureCurve;
+            /// <summary>
+            /// 是否保存压力曲线图
+            /// </summary>
+            public bool IsSavePressureCurve
+            {
+                get => _IsSavePressureCurve;
+                set => SetProperty(ref _IsSavePressureCurve, value);
+            }
+
+            private string _pressureCurvePath;
+            /// <summary>
+            /// 压力曲线图保存路径
+            /// </summary>
+            public string PressureCurvePath
+            {
+                get => _pressureCurvePath;
+                set => SetProperty(ref _pressureCurvePath, value);
+            }
+
+        }
     }
 }

+ 9 - 0
TeamAAS-VM/TeamAAS-VP.csproj

@@ -540,10 +540,12 @@
     <Compile Include="Models\Feeder\ScrewFeederInfo.cs" />
     <Compile Include="Models\ScrewFeederBatchRecord.cs" />
     <Compile Include="Services\MesService.cs" />
+    <Compile Include="ValueConverter\CountToColumnsConverter.cs" />
     <Compile Include="ViewModels\Calibration\CalibrationDistortionViewModel.cs" />
     <Compile Include="ViewModels\Calibration\CalibIndependentCameraViewModel.cs" />
     <Compile Include="ViewModels\DebugMod\PlcRobotManualStepViewModel.cs" />
     <Compile Include="ViewModels\Product\ImageDisplayViewModel.cs" />
+    <Compile Include="ViewModels\Product\PlcPointOffserParamsViewModel.cs" />
     <Compile Include="ViewModels\Product\VisionDynamicAccuracyAnalyzerViewModel.cs" />
     <Compile Include="ViewModels\Product\VisionStaticAccuracyAnalyzerViewModel.cs" />
     <Compile Include="ViewModels\Setting\AddScrewFeederViewModel.cs" />
@@ -992,6 +994,9 @@
     <Compile Include="Views\Product\PalletManage.xaml.cs">
       <DependentUpon>PalletManage.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\Product\PlcPointOffserParams.xaml.cs">
+      <DependentUpon>PlcPointOffserParams.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\Product\PlcPointParams.xaml.cs">
       <DependentUpon>PlcPointParams.xaml</DependentUpon>
     </Compile>
@@ -1361,6 +1366,10 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\Product\PlcPointOffserParams.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="Views\Product\PlcPointParams.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>

+ 21 - 0
TeamAAS-VM/ValueConverter/CountToColumnsConverter.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace TeamAAS_VP.ValueConverter
+{
+    public class CountToColumnsConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value == null) return 1;
+            if (!int.TryParse(value.ToString(), out int count)) return 1;
+            if (count <= 1) return 1;
+            if (count == 2) return 2;
+            return 3; // 3 或更多时按 3 列分布(UniformGrid 会自动换行)
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+            => throw new NotSupportedException();
+    }
+}

+ 124 - 0
TeamAAS-VM/ViewModels/Product/PlcPointOffserParamsViewModel.cs

@@ -0,0 +1,124 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using Prism.Services.Dialogs;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Windows;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+using TeamAAS_VP.Models.PLC;
+using TeamAAS_VP.Resources.Languages;
+using TeamAAS_VP.Views.Setting;
+
+namespace TeamAAS_VP.ViewModels.Product
+{
+    public class PlcPointOffserParamsViewModel : BindableBase, IDialogAware
+    {
+
+        #region 属性
+        private ObservableCollection<PlcPoint> _Points = new ObservableCollection<PlcPoint>();
+        /// <summary>
+        /// 点位集合
+        /// </summary>
+        public ObservableCollection<PlcPoint> Points
+        {
+            get { return _Points; }
+            set { SetProperty(ref _Points, value); }
+        }
+        #endregion
+
+        #region 命令
+        private DelegateCommand _ConfirmCommand;
+        public DelegateCommand ConfirmCommand =>
+            _ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand, CanExecuteConfirmCommand));
+
+        private DelegateCommand _CancelCommand;
+        public DelegateCommand CancelCommand =>
+            _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand));
+
+        private DelegateCommand _ClearAllOffsetCommand;
+        public DelegateCommand ClearAllOffsetCommand =>
+            _ClearAllOffsetCommand ?? (_ClearAllOffsetCommand = new DelegateCommand(ExecuteClearAllOffsetCommand));
+
+
+        #endregion
+
+        public PlcPointOffserParamsViewModel()
+        {
+
+        }
+
+        /// <summary>
+        /// 确认按钮
+        /// </summary>
+        /// <returns></returns>
+        bool CanExecuteConfirmCommand()
+        {
+            return true;
+        }
+
+        void ExecuteConfirmCommand()
+        {
+            IDialogParameters parameters = new DialogParameters();
+            parameters.Add("Points", Points.ToArray());
+            RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));
+        }
+
+        /// <summary>
+        /// 取消按钮
+        /// </summary>
+        void ExecuteCancelCommand()
+        {
+            IDialogParameters parameters = new DialogParameters();
+            RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel, parameters));
+        }
+
+        /// <summary>
+        /// 清除所有补偿值
+        /// </summary>
+        void ExecuteClearAllOffsetCommand()
+        {
+            foreach (var point in Points)
+            {
+                point.X_Offset = 0;
+                point.Y_Offset = 0;
+                point.Z_Start_Offset = 0;
+                point.Z_Stop_Offset = 0;
+                point.U_Offset = 0;
+                point.R_Offset = 0;
+            }
+
+        }
+
+        private string _Title;
+        public string Title
+        {
+            get { return _Title; }
+            set { SetProperty(ref _Title, value); }
+        }
+
+        public event Action<IDialogResult> RequestClose;
+
+        public bool CanCloseDialog()
+        {
+            return true;
+        }
+
+        public void OnDialogClosed()
+        {
+
+        }
+
+        public void OnDialogOpened(IDialogParameters parameters)
+        {
+            Title = parameters.GetValue<string>("Title");
+            var pts = parameters.GetValue<PlcPoint[]>("Points");
+            if (pts != null)
+            {
+                Points = new ObservableCollection<PlcPoint>(pts);
+            }
+        }
+    }
+}

+ 36 - 0
TeamAAS-VM/ViewModels/SettingViewModel.cs

@@ -33,6 +33,7 @@ using TeamAAS_VP.Services;
 using TeamAAS_VP.ViewModels.User;
 using TouchSocket.Core;
 using WPFLocalizeExtension.Engine;
+using static TeamAAS_VP.Models.SystemConfiguration;
 
 namespace TeamAAS_VP.ViewModels
 {
@@ -437,6 +438,11 @@ namespace TeamAAS_VP.ViewModels
         private DelegateCommand _SaveCardReaderConfigCommand;
         public DelegateCommand SaveCardReaderConfigCommand =>
             _SaveCardReaderConfigCommand ?? (_SaveCardReaderConfigCommand = new DelegateCommand(ExecuteSaveCardReaderConfigCommand));
+
+        private DelegateCommand<object> _BrowsePressureCurvePathCommand;
+        public DelegateCommand<object> BrowsePressureCurvePathCommand =>
+            _BrowsePressureCurvePathCommand ?? (_BrowsePressureCurvePathCommand = new DelegateCommand<object>(ExecuteBrowsePressureCurvePathCommand));
+
         #endregion
 
         #region 事件
@@ -1349,6 +1355,7 @@ namespace TeamAAS_VP.ViewModels
                 FixedCameraPutNum = sys.FixedCameraPutNum;
                 FixedCameracheckNum = sys.FixedCameracheckNum;
                 ScrewTeachNum = sys.ScrewTeachNum;
+                PressureSensorConfig = sys.PressureSensorConfig;
             }
 
             if (isFirstLoad)
@@ -1511,6 +1518,17 @@ namespace TeamAAS_VP.ViewModels
             set => SetProperty(ref _ScrewTeachNum, value);
         }
 
+        private ObservableCollection<PressureSensorSettings> _PressureSensorConfig;
+        /// <summary>
+        /// 压力传感器配置列表
+        /// </summary>
+        public ObservableCollection<PressureSensorSettings> PressureSensorConfig
+        {
+            get { return _PressureSensorConfig; }
+            set { SetProperty(ref _PressureSensorConfig, value); }
+        }
+
+
         async void ExecuteSaveSystemParametersCommand()
         {
             var view = new ShowMessage($"AAS", "是否保存系统参数?");
@@ -1530,6 +1548,7 @@ namespace TeamAAS_VP.ViewModels
                     sysConfig.FixedCameraPutNum = FixedCameraPutNum;
                     sysConfig.FixedCameracheckNum = FixedCameracheckNum;
                     sysConfig.ScrewTeachNum= ScrewTeachNum;
+                    sysConfig.PressureSensorConfig = PressureSensorConfig;
 
                     _configService.SaveSystemConfiguration(sysConfig);
                     await management.WriteSystemParameterToPlcAsync(sysConfig);
@@ -1542,6 +1561,23 @@ namespace TeamAAS_VP.ViewModels
             }
         }
 
+        /// <summary>
+        /// 选择压力曲线保存路径
+        /// </summary>
+        /// <param name="parameter"></param>
+        void ExecuteBrowsePressureCurvePathCommand(object parameter)
+        {
+            if (parameter is PressureSensorSettings sensorSettings)
+            {
+                var dialog = new System.Windows.Forms.FolderBrowserDialog();
+                System.Windows.Forms.DialogResult result = dialog.ShowDialog();
+                if (result == System.Windows.Forms.DialogResult.OK)
+                {
+                    sensorSettings.PressureCurvePath = dialog.SelectedPath;
+                }
+            }
+        }
+
         /// <summary>
         /// 保存读卡器配置
         /// </summary>

+ 66 - 6
TeamAAS-VM/Views/HomeView.xaml

@@ -14,6 +14,7 @@
              lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
              lex:ResxLocalizationProvider.DefaultDictionary="Lang"
              prism:ViewModelLocator.AutoWireViewModel="True"
+             xmlns:conv="clr-namespace:TeamAAS_VP.ValueConverter"
              mc:Ignorable="d"
              d:Height="600"
              d:Width="1024"
@@ -21,6 +22,9 @@
              d:DataContext="{d:DesignInstance Type=vm:HomeViewModel}"
              Background="Transparent"
              FontFamily="{DynamicResource DefaultFont}">
+    <UserControl.Resources>
+        <conv:CountToColumnsConverter x:Key="CountToColumnsConverter" />
+    </UserControl.Resources>
     <b:Interaction.Triggers>
         <b:EventTrigger EventName="Loaded">
             <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
@@ -33,19 +37,75 @@
         </Grid.ColumnDefinitions>
 
         <Grid Grid.Row="0">
-            <!--<Grid.RowDefinitions>
+            <Grid.RowDefinitions>
                 <RowDefinition Height="*" />
                 <RowDefinition Height="*" />
-            </Grid.RowDefinitions>-->
+            </Grid.RowDefinitions>
             <!--图像-->
-            <local:ShowVisionRender Grid.Row="0"
-                                    Grid.Column="0" />
-            <!--曲线图--><!--
+            <local:ShowVisionRender x:Name="visionRender"
+                                    Grid.Row="0"
+                                    Grid.Column="0">
+                <local:ShowVisionRender.Style>
+                    <Style TargetType="local:ShowVisionRender">
+                        <Setter Property="Grid.RowSpan"
+                                Value="1" />
+                        <Style.Triggers>
+                            <!-- 当压力曲线集合为空或没有项时,让图像占满两行 -->
+                            <DataTrigger Binding="{Binding ElementName=pressureItems, Path=HasItems}"
+                                         Value="False">
+                                <Setter Property="Grid.RowSpan"
+                                        Value="2" />
+                            </DataTrigger>
+                        </Style.Triggers>
+                    </Style>
+                </local:ShowVisionRender.Style>
+            </local:ShowVisionRender>
+            <!--曲线图-->
+            <!--
             <oxy:PlotView Grid.Row="1"
                           Grid.Column="0"
                           Model="{Binding LockCurvePlotModel}"
                           Background="Transparent"
                           Margin="10" />-->
+            <!-- 动态压力曲线集合 -->
+            <ItemsControl x:Name="pressureItems"
+                          Grid.Row="1"
+                          Grid.Column="0"
+                          ItemsSource="{Binding PressurePlotModels}">
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <!-- 一行显示,列数由转换器根据 Count 决定(1 / 2 / 3) -->
+                        <UniformGrid Rows="1"
+                                     Columns="{Binding PressurePlotModels.Count, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource CountToColumnsConverter}}" />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+
+                <!-- 保证每个项填充单元格 -->
+                <ItemsControl.ItemContainerStyle>
+                    <Style TargetType="ContentPresenter">
+                        <Setter Property="HorizontalAlignment"
+                                Value="Stretch" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Stretch" />
+                        <Setter Property="Margin"
+                                Value="6" />
+                    </Style>
+                </ItemsControl.ItemContainerStyle>
+
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <Border BorderBrush="LightGray"
+                                BorderThickness="1"
+                                CornerRadius="6"
+                                HorizontalAlignment="Stretch"
+                                VerticalAlignment="Stretch">
+                            <oxy:PlotView Model="{Binding}"
+                                          HorizontalAlignment="Stretch"
+                                          VerticalAlignment="Stretch" />
+                        </Border>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
         </Grid>
         <Grid Grid.Row="1"
               Grid.Column="1">
@@ -324,7 +384,7 @@
                                FontWeight="Bold"
                                FontSize="{DynamicResource Font.Size.Body2}"
                                VerticalAlignment="Center" />
-                    <TextBlock Text="{Binding CTTotalSeconds,StringFormat={}{0:F2} s}"
+                    <TextBlock Text="{Binding management.CTtime,StringFormat={}{0:F2} s}"
                                FontSize="{DynamicResource Font.Size.Body3}"
                                VerticalAlignment="Center"
                                Margin="10,0" />

+ 319 - 0
TeamAAS-VM/Views/Product/PlcPointOffserParams.xaml

@@ -0,0 +1,319 @@
+<UserControl x:Class="TeamAAS_VP.Views.Product.PlcPointOffserParams"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:system="clr-namespace:System;assembly=mscorlib"
+             xmlns:local="clr-namespace:TeamAAS_VP.Controls"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Product"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             mc:Ignorable="d"
+             d:DesignHeight="768"
+             d:DesignWidth="1024"
+             d:Background="White"
+             MaxHeight="1000"
+             MaxWidth="1840"
+             d:DataContext="{d:DesignInstance Type=vm:PlcPointOffserParamsViewModel}"
+             FontFamily="{DynamicResource DefaultFont}">
+    <prism:Dialog.WindowStyle>
+        <Style TargetType="Window">
+            <Setter Property="prism:Dialog.WindowStartupLocation"
+                    Value="CenterScreen" />
+            <!--<Setter Property="WindowChrome.WindowChrome">
+            <Setter.Value>
+                <WindowChrome CaptionHeight="0"
+                              ResizeBorderThickness="1" />
+            </Setter.Value>
+        </Setter>-->
+            <Setter Property="WindowStyle"
+                    Value="None" />
+            <Setter Property="AllowDrop"
+                    Value="True" />
+            <Setter Property="BorderThickness"
+                    Value="0" />
+            <Setter Property="ShowInTaskbar"
+                    Value="False" />
+            <Setter Property="SizeToContent"
+                    Value="WidthAndHeight" />
+            <Setter Property="WindowState"
+                    Value="Normal" />
+            <Setter Property="Topmost"
+                    Value="True" />
+        </Style>
+    </prism:Dialog.WindowStyle>
+    <Grid Margin="16">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="auto" />
+        </Grid.RowDefinitions>
+        <TextBlock Text="{Binding Title}"
+                   FontSize="16"
+                   FontWeight="Bold"
+                   Margin="0,10"
+                   VerticalAlignment="Center"
+                   TextAlignment="Left"
+                   HorizontalAlignment="Left" />
+        <!--点位表-->
+        <Border Grid.Row="1"
+                BorderBrush="#D0D0D0"
+                BorderThickness="1"
+                Margin="0,5">
+            <DataGrid x:Name="dgPoints"
+                      AutoGenerateColumns="False"
+                      CanUserAddRows="False"
+                      CanUserDeleteRows="False"
+                      ColumnWidth="*"
+                      SelectionUnit="FullRow"
+                      SelectionMode="Single"
+                      ItemsSource="{Binding Points}"
+                      HeadersVisibility="Column"
+                      HorizontalScrollBarVisibility="Auto"
+                      ScrollViewer.CanContentScroll="True"
+                      ScrollViewer.HorizontalScrollBarVisibility="Auto"
+                      GridLinesVisibility="All"
+                      VerticalGridLinesBrush="#D0D0D0">
+                <DataGrid.Resources>
+                    <Style TargetType="DataGridCell">
+                        <Style.Resources>
+                            <SolidColorBrush  x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
+                                              Color="#0078D7" />
+                        </Style.Resources>
+                        <Setter Property="MinHeight"
+                                Value="25" />
+                        <Setter Property="VerticalContentAlignment"
+                                Value="Center" />
+                        <Setter Property="HorizontalContentAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                        <Setter Property="TextBlock.TextAlignment"
+                                Value="Center" />
+                        <Setter Property="Padding"
+                                Value="0" />
+                        <Style.Triggers>
+                            <Trigger Property="IsSelected"
+                                     Value="True">
+                                <Setter Property="Foreground"
+                                        Value="White" />
+                            </Trigger>
+                        </Style.Triggers>
+                    </Style>
+
+                    <!-- 为 TextBlock 添加默认居中样式 -->
+                    <Style TargetType="TextBlock">
+                        <Setter Property="TextAlignment"
+                                Value="Center" />
+                        <Setter Property="HorizontalAlignment"
+                                Value="Center" />
+                        <Setter Property="VerticalAlignment"
+                                Value="Center" />
+                    </Style>
+                </DataGrid.Resources>
+                <DataGrid.Columns>
+                    <DataGridTextColumn Header="{lex:Loc 编号}"
+                                        IsReadOnly="True"
+                                        MinWidth="60"
+                                        Width="Auto"
+                                        Binding="{Binding Number, Mode=TwoWay, StringFormat={}{0:F0}}">
+                    </DataGridTextColumn>
+                    <DataGridTextColumn Header="{lex:Loc 标签}"
+                                        MinWidth="100"
+                                        Width="Auto"
+                                        Binding="{Binding Label, Mode=TwoWay}" />
+                    <!--X 坐标-->
+                    <DataGridTemplateColumn Header="X补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding X_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding X_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+                    <!--Y 坐标-->
+                    <DataGridTemplateColumn Header="Y补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding Y_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding Y_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+                    <!--Z 起点坐标-->
+                    <DataGridTemplateColumn Header="Z起点补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding Z_Start_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding Z_Start_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+                    <!--Z 终点坐标-->
+                    <DataGridTemplateColumn Header="Z终点补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding Z_Stop_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding Z_Stop_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+                    <!--U 坐标-->
+                    <DataGridTemplateColumn Header="U补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding U_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding U_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+                    <!--R 坐标-->
+                    <DataGridTemplateColumn Header="R补偿"
+                                            MinWidth="60"
+                                            Width="Auto">
+                        <DataGridTemplateColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Text="{Binding R_Offset, StringFormat={}{0:F3}}"
+                                           HorizontalAlignment="Center"
+                                           VerticalAlignment="Center" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellTemplate>
+                        <DataGridTemplateColumn.CellEditingTemplate>
+                            <DataTemplate>
+                                <mah:NumericUpDown Value="{Binding R_Offset, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                   Minimum="-9999.000"
+                                                   Maximum="9999.000"
+                                                   Interval="0.1"
+                                                   StringFormat="F3"
+                                                   HorizontalAlignment="Stretch"
+                                                   VerticalAlignment="Center"
+                                                   Margin="0"
+                                                   Padding="2" />
+                            </DataTemplate>
+                        </DataGridTemplateColumn.CellEditingTemplate>
+                    </DataGridTemplateColumn>
+
+                    <DataGridTextColumn Header="{lex:Loc 描述}"
+                                        MinWidth="100"
+                                        Width="200"
+                                        Binding="{Binding Description, Mode=TwoWay}" />
+                </DataGrid.Columns>
+            </DataGrid>
+        </Border>
+        <StackPanel Grid.Row="2"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Right">
+            <!--清除所有补偿-->
+            <Button Height="30"
+                    Margin="0,0,20,0"
+                    materialDesign:ButtonAssist.CornerRadius="10"
+                    Style="{StaticResource MaterialDesignRaisedButton}"
+                    ToolTip="清除所有补偿"
+                    Command="{Binding ClearAllOffsetCommand}">
+                <TextBlock Text="清除所有补偿" />
+            </Button>
+
+            <Button Height="30"
+                    materialDesign:ButtonAssist.CornerRadius="10"
+                    Style="{StaticResource MaterialDesignRaisedButton}"
+                    ToolTip="{lex:Loc 确定}"
+                    Command="{Binding ConfirmCommand}">
+                <TextBlock Text="{lex:Loc 确定}" />
+            </Button>
+            <Button Height="30"
+                    Margin="20,0"
+                    materialDesign:ButtonAssist.CornerRadius="10"
+                    Style="{StaticResource MaterialDesignRaisedButton}"
+                    ToolTip="{lex:Loc 取消}"
+                    Command="{Binding CancelCommand}">
+                <TextBlock Text="{lex:Loc 取消}" />
+            </Button>
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 15 - 0
TeamAAS-VM/Views/Product/PlcPointOffserParams.xaml.cs

@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace TeamAAS_VP.Views.Product
+{
+    /// <summary>
+    /// Interaction logic for PlcPointOffserParams
+    /// </summary>
+    public partial class PlcPointOffserParams : UserControl
+    {
+        public PlcPointOffserParams()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 36 - 1
TeamAAS-VM/Views/Product/PlcPointParams.xaml

@@ -351,6 +351,13 @@
                                     </Style>
                                 </Button.Style>
                             </Button>-->
+                            <!--设置补偿值-->
+                            <Button Content="设置补偿值"
+                                    Margin="5,2"
+                                    MinWidth="80"
+                                    d:Visibility="Visible"
+                                    materialDesign:ButtonAssist.CornerRadius="5"
+                                    Command="{Binding SetOffsetCommand}" />
                         </StackPanel>
                         <Border BorderBrush="LightGray"
                                 BorderThickness="1"
@@ -908,7 +915,35 @@
                                             </DataTemplate>
                                         </DataGridTemplateColumn.CellEditingTemplate>
                                     </DataGridTemplateColumn>-->
-
+                                    <!--视觉流程-->
+                                    <DataGridTemplateColumn x:Name="colProcedure"
+                                                            Header="视觉流程"
+                                                            MinWidth="60"
+                                                            Width="Auto">
+                                        <DataGridTemplateColumn.CellTemplate>
+                                            <DataTemplate>
+                                                <ComboBox MinWidth="50"
+                                                          Margin="5,0,0,0"
+                                                          ItemsSource="{Binding DataContext.ProcedureModels,RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
+                                                          SelectedValuePath="Id"
+                                                          SelectedValue="{Binding VisionProcessID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                          SelectionChanged="ProcedureCombo_SelectionChanged">
+                                                    <ComboBox.ItemTemplate>
+                                                        <DataTemplate>
+                                                            <StackPanel Orientation="Horizontal">
+                                                                <materialDesign:PackIcon Kind="VideoOutline" />
+                                                                <TextBlock Text="{Binding CameraName}"
+                                                                           Margin="6,0" />
+                                                                <materialDesign:PackIcon Kind="ProgressWrench" />
+                                                                <TextBlock Text="{Binding Name}"
+                                                                           Margin="6,0" />
+                                                            </StackPanel>
+                                                        </DataTemplate>
+                                                    </ComboBox.ItemTemplate>
+                                                </ComboBox>
+                                            </DataTemplate>
+                                        </DataGridTemplateColumn.CellTemplate>
+                                    </DataGridTemplateColumn>
                                     <DataGridTextColumn Header="{lex:Loc 描述}"
                                                         MinWidth="100"
                                                         Width="200"

+ 42 - 0
TeamAAS-VM/Views/Product/PlcPointParams.xaml.cs

@@ -19,12 +19,54 @@ namespace TeamAAS_VP.Views.Product
             InitializeComponent();
             VM = DataContext as PlcPointParamsViewModel;
             VM.PropertyChanged += VM_PropertyChanged;
+            VM.PropertyChanged += Vm_SelectedIndexChanged;
+            // initialize visibility
+            try
+            {
+                if (VM != null && colProcedure != null)
+                    colProcedure.Visibility = VM.SelectedIndex == 3 ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
+            }
+            catch { }
             this.display.HorizontalScrollBar = false;
             this.display.VerticalScrollBar = false;
             this.display.AutoFit = true;
             this.display.BackColor = System.Drawing.SystemColors.ActiveCaption;
         }
 
+        private void Vm_SelectedIndexChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
+        {
+            if (e.PropertyName == nameof(PlcPointParamsViewModel.SelectedIndex))
+            {
+                try
+                {
+                    var visible = VM.SelectedIndex == 3 ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
+                    this.Dispatcher.BeginInvoke(new Action(() =>
+                    {
+                        if (colProcedure != null)
+                            colProcedure.Visibility = visible;
+                    }));
+                }
+                catch { }
+            }
+        }
+
+        private void ProcedureCombo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
+        {
+            try
+            {
+                var combo = sender as System.Windows.Controls.ComboBox;
+                if (combo == null) return;
+                var proc = combo.SelectedItem as TeamAAS_VP.Models.ProcedureModel;
+                var point = combo.DataContext as TeamAAS_VP.Models.PLC.PlcPoint;
+                if (point != null && proc != null)
+                {
+                    // SelectedValue binding already sets VisionProcessID; sync name
+                    point.VisionProcessName = proc.Name;
+                }
+            }
+            catch { }
+        }
+
         private int _imageWidth;
         private int _imageHeight;
         private void VM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

+ 389 - 263
TeamAAS-VM/Views/SettingView.xaml

@@ -2174,218 +2174,14 @@
                                    HorizontalAlignment="Stretch" />
                     </StackPanel>
                 </TabItem.Header>
-                <StackPanel Orientation="Vertical"
-                            Margin="20">
-                    <Grid>
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="auto" />
-                            <ColumnDefinition Width="200" />
-                            <ColumnDefinition Width="*" />
-                        </Grid.ColumnDefinitions>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="Auto" />
-                            <RowDefinition Height="40" />
-                        </Grid.RowDefinitions>
-
-                        <!-- 相机拍照次数 -->
-                        <TextBlock Grid.Row="0"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="下相机拍照次数:" />
-                        <mah:NumericUpDown Grid.Row="0"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding DowmCameraNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 上相机取料拍照次数 -->
-                        <TextBlock Grid.Row="1"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="上相机取料拍照次数:" />
-                        <mah:NumericUpDown Grid.Row="1"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding UpCameraPickNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 上相机放料拍照次数 -->
-                        <TextBlock Grid.Row="2"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="上相机放料拍照次数:" />
-                        <mah:NumericUpDown Grid.Row="2"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding UpCameraPutNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 上相机锁附/组装次数 -->
-                        <TextBlock Grid.Row="3"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="上相机锁附/组装次数:" />
-                        <mah:NumericUpDown Grid.Row="3"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding UPCameracheckNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 取料固定位置拍产品相机数量 -->
-                        <TextBlock Grid.Row="4"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="取料固定位置拍产品相机数量:" />
-                        <mah:NumericUpDown Grid.Row="4"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding FixedCameraPickNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="10"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 锁附/组装固定位置拍产品相机数量 -->
-                        <TextBlock Grid.Row="5"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="锁附/组装固定位置拍产品相机数量:" />
-                        <mah:NumericUpDown Grid.Row="5"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding FixedCameraPutNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="10"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 固定相机检测锁附/组装次数 -->
-                        <TextBlock Grid.Row="6"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="固定相机检测锁附/组装次数:" />
-                        <mah:NumericUpDown Grid.Row="6"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding FixedCameracheckNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-                        <!-- 工作模式  -->
-                        <TextBlock Grid.Row="7"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="工作模式 :" />
-                        <mah:NumericUpDown Grid.Row="7"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding WorkMode,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 取料位置 -->
-                        <TextBlock Grid.Row="8"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="取料位置:" />
-                        <mah:NumericUpDown Grid.Row="8"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding PickPointNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-                        <!-- 披头矫正的模式 -->
-                        <TextBlock Grid.Row="9"
-                                   Grid.Column="0"
-                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right"
-                                   Margin="0,6,10,6"
-                                   Text="披头矫正的模式:" />
-                        <mah:NumericUpDown Grid.Row="9"
-                                           Grid.Column="1"
-                                           Margin="0,6"
-                                           Value="{Binding ScrewTeachNum,Mode=TwoWay}"
-                                           Minimum="0"
-                                           Maximum="100"
-                                           FontSize="{DynamicResource Font.Size.Body3}" />
-
-                        <!-- 保存按钮 -->
-                        <StackPanel Grid.Row="10"
-                                    Grid.ColumnSpan="3"
-                                    Orientation="Horizontal"
-                                    HorizontalAlignment="Right"
-                                    VerticalAlignment="Center"
-                                    Margin="0,10,0,0">
-                            <Button Style="{StaticResource MaterialDesignRaisedButton}"
-                                    materialDesign:ButtonAssist.CornerRadius="10"
-                                    MinWidth="120"
-                                    Command="{Binding SaveSystemParametersCommand}"
-                                    IsEnabled="{Binding IsAllowEdit}">
-                                <StackPanel Orientation="Horizontal"
-                                            HorizontalAlignment="Center">
-                                    <materialDesign:PackIcon Kind="ContentSaveCheck"
-                                                             Margin="0,0,6,0" />
-                                    <TextBlock VerticalAlignment="Center"
-                                               Text="保存系统参数" />
-                                </StackPanel>
-                            </Button>
-                        </StackPanel>
-                    </Grid>
-                    <!--刷卡参数配置-->
-                    <GroupBox Grid.Row="5"
-                              Grid.ColumnSpan="2"
-                              Header="刷卡器配置"
-                              HorizontalAlignment="Left"
-                              MinWidth="400"
-                              Margin="0,12,0,0">
-                        <Grid Margin="10">
+                <ScrollViewer HorizontalScrollBarVisibility="Auto"
+                              VerticalScrollBarVisibility="Auto">
+                    <StackPanel Orientation="Vertical"
+                                Margin="20">
+                        <Grid>
                             <Grid.ColumnDefinitions>
                                 <ColumnDefinition Width="auto" />
+                                <ColumnDefinition Width="200" />
                                 <ColumnDefinition Width="*" />
                             </Grid.ColumnDefinitions>
                             <Grid.RowDefinitions>
@@ -2395,66 +2191,396 @@
                                 <RowDefinition Height="Auto" />
                                 <RowDefinition Height="Auto" />
                                 <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="Auto" />
+                                <RowDefinition Height="40" />
                             </Grid.RowDefinitions>
-                            <TextBlock Text="PortName:"
-                                       Grid.Row="0"
+
+                            <!-- 相机拍照次数 -->
+                            <TextBlock Grid.Row="0"
                                        Grid.Column="0"
-                                       HorizontalAlignment="Right" />
-                            <TextBox Text="{Binding CardReaderConfig.PortName,Mode=TwoWay}"
-                                     Grid.Row="0"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
-                            <TextBlock Text="BaudRate:"
-                                       Grid.Row="1"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="下相机拍照次数:" />
+                            <mah:NumericUpDown Grid.Row="0"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding DowmCameraNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 上相机取料拍照次数 -->
+                            <TextBlock Grid.Row="1"
                                        Grid.Column="0"
-                                       HorizontalAlignment="Right" />
-                            <TextBox Text="{Binding CardReaderConfig.BaudRate,Mode=TwoWay}"
-                                     Grid.Row="1"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
-                            <TextBlock Text="Parity:"
-                                       Grid.Row="2"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="上相机取料拍照次数:" />
+                            <mah:NumericUpDown Grid.Row="1"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding UpCameraPickNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 上相机放料拍照次数 -->
+                            <TextBlock Grid.Row="2"
                                        Grid.Column="0"
-                                       HorizontalAlignment="Right" />
-                            <ComboBox Grid.Row="2"
-                                      Grid.Column="1"
-                                      SelectedItem="{Binding CardReaderConfig.Parity,Mode=TwoWay}"
-                                      ItemsSource="{Binding Source={StaticResource Parity}}" />
-                            <TextBlock Text="StopBits:"
-                                       Grid.Row="3"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="上相机放料拍照次数:" />
+                            <mah:NumericUpDown Grid.Row="2"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding UpCameraPutNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 上相机锁附/组装次数 -->
+                            <TextBlock Grid.Row="3"
                                        Grid.Column="0"
-                                       HorizontalAlignment="Right" />
-                            <ComboBox Grid.Row="3"
-                                      Grid.Column="1"
-                                      SelectedItem="{Binding CardReaderConfig.StopBits,Mode=TwoWay}"
-                                      ItemsSource="{Binding Source={StaticResource StopBits}}" />
-                            <TextBlock Text="DataBits:"
-                                       Grid.Row="4"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="上相机锁附/组装次数:" />
+                            <mah:NumericUpDown Grid.Row="3"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding UPCameracheckNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 取料固定位置拍产品相机数量 -->
+                            <TextBlock Grid.Row="4"
                                        Grid.Column="0"
-                                       HorizontalAlignment="Right" />
-                            <TextBox Text="{Binding CardReaderConfig.DataBits,Mode=TwoWay}"
-                                     Grid.Row="4"
-                                     Grid.Column="1"
-                                     Margin="6,0" />
-
-                            <Button Grid.Row="5"
-                                    Grid.Column="1"
-                                    Margin="0,6"
-                                    Style="{StaticResource MaterialDesignRaisedButton}"
-                                    materialDesign:ButtonAssist.CornerRadius="10"
-                                    MinWidth="120"
-                                    Command="{Binding SaveCardReaderConfigCommand}">
-                                <StackPanel Orientation="Horizontal"
-                                            HorizontalAlignment="Center">
-                                    <materialDesign:PackIcon Kind="ContentSaveCheck"
-                                                             Margin="0,0,6,0" />
-                                    <TextBlock VerticalAlignment="Center"
-                                               Text="保存刷卡器配置" />
-                                </StackPanel>
-                            </Button>
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="取料固定位置拍产品相机数量:" />
+                            <mah:NumericUpDown Grid.Row="4"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding FixedCameraPickNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="10"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 锁附/组装固定位置拍产品相机数量 -->
+                            <TextBlock Grid.Row="5"
+                                       Grid.Column="0"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="锁附/组装固定位置拍产品相机数量:" />
+                            <mah:NumericUpDown Grid.Row="5"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding FixedCameraPutNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="10"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 固定相机检测锁附/组装次数 -->
+                            <TextBlock Grid.Row="6"
+                                       Grid.Column="0"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="固定相机检测锁附/组装次数:" />
+                            <mah:NumericUpDown Grid.Row="6"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding FixedCameracheckNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+                            <!-- 工作模式  -->
+                            <TextBlock Grid.Row="7"
+                                       Grid.Column="0"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="工作模式 :" />
+                            <mah:NumericUpDown Grid.Row="7"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding WorkMode,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 取料位置 -->
+                            <TextBlock Grid.Row="8"
+                                       Grid.Column="0"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="取料位置:" />
+                            <mah:NumericUpDown Grid.Row="8"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding PickPointNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+                            <!-- 披头矫正的模式 -->
+                            <TextBlock Grid.Row="9"
+                                       Grid.Column="0"
+                                       Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Right"
+                                       Margin="0,6,10,6"
+                                       Text="披头矫正的模式:" />
+                            <mah:NumericUpDown Grid.Row="9"
+                                               Grid.Column="1"
+                                               Margin="0,6"
+                                               Value="{Binding ScrewTeachNum,Mode=TwoWay}"
+                                               Minimum="0"
+                                               Maximum="100"
+                                               FontSize="{DynamicResource Font.Size.Body3}" />
+
+                            <!-- 压力传感器配置: 插入于 Row=10 -->
+                            <GroupBox Grid.Row="10"
+                                      Grid.ColumnSpan="3"
+                                      Header="压力传感器配置"
+                                      Margin="0,8,0,8">
+                                <GroupBox.Resources>
+                                    <!-- 压力单位列表 -->
+                                    <x:Array x:Key="PressureUnits"
+                                             Type="sys:String">
+                                        <sys:String>kPa</sys:String>
+                                        <sys:String>Pa</sys:String>
+                                        <sys:String>Bar</sys:String>
+                                        <sys:String>psi</sys:String>
+                                    </x:Array>
+                                </GroupBox.Resources>
+
+                                <Grid Margin="10">
+                                    <Grid.RowDefinitions>
+                                        <RowDefinition Height="Auto" />
+                                        <RowDefinition Height="Auto" />
+                                        <RowDefinition Height="*" />
+                                    </Grid.RowDefinitions>
+
+                                    <!-- 列标题 -->
+                                    <Grid Grid.Row="1"
+                                          Margin="0,0,0,6">
+                                        <Grid.ColumnDefinitions>
+                                            <ColumnDefinition Width="30" />
+                                            <ColumnDefinition Width="120" />
+                                            <ColumnDefinition Width="120" />
+                                            <ColumnDefinition Width="*" />
+                                            <ColumnDefinition Width="30" />
+                                        </Grid.ColumnDefinitions>
+                                        <TextBlock Grid.Column="0"
+                                                   Text="#"
+                                                   VerticalAlignment="Center"
+                                                   HorizontalAlignment="Center"
+                                                   TextTrimming="CharacterEllipsis"
+                                                   FontWeight="Bold" />
+                                        <TextBlock Grid.Column="1"
+                                                   Text="压力传感器的名称"
+                                                   VerticalAlignment="Center"
+                                                   FontWeight="Bold"
+                                                   TextTrimming="CharacterEllipsis" />
+                                        <TextBlock Grid.Column="2"
+                                                   Text="是否保存压力曲线图"
+                                                   VerticalAlignment="Center"
+                                                   HorizontalAlignment="Center"
+                                                   FontWeight="Bold"
+                                                   TextTrimming="CharacterEllipsis" />
+                                        <TextBlock Grid.Column="3"
+                                                   Text="压力曲线图保存路径"
+                                                   VerticalAlignment="Center"
+                                                   HorizontalAlignment="Center"
+                                                   FontWeight="Bold"
+                                                   TextTrimming="CharacterEllipsis" />
+                                    </Grid>
+
+                                    <!-- 传感器列表 -->
+                                    <ScrollViewer Grid.Row="2"
+                                                  VerticalScrollBarVisibility="Auto"
+                                                  HorizontalScrollBarVisibility="Disabled">
+                                        <ItemsControl ItemsSource="{Binding PressureSensorConfig}">
+                                            <ItemsControl.ItemTemplate>
+                                                <DataTemplate>
+                                                    <Border BorderBrush="#DDD"
+                                                            BorderThickness="1"
+                                                            CornerRadius="4"
+                                                            Padding="6"
+                                                            Margin="0,4">
+                                                        <Grid>
+                                                            <Grid.ColumnDefinitions>
+                                                                <ColumnDefinition Width="30" />
+                                                                <ColumnDefinition Width="120" />
+                                                                <ColumnDefinition Width="120" />
+                                                                <ColumnDefinition Width="*" />
+                                                                <ColumnDefinition Width="30" />
+                                                            </Grid.ColumnDefinitions>
+
+                                                            <!-- 索引:尝试使用 LocalIndex 或 在 ViewModel 中提供 -->
+                                                            <TextBlock Grid.Column="0"
+                                                                       Text="{Binding SensorId}"
+                                                                       VerticalAlignment="Center"
+                                                                       HorizontalAlignment="Center" />
+
+                                                            <!-- 名称 -->
+                                                            <TextBox Grid.Column="1"
+                                                                     Text="{Binding SensorName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                     VerticalAlignment="Center"
+                                                                     Margin="6,0"
+                                                                     MinWidth="120" />
+
+                                                            <!-- 是否保存压力曲线图 -->
+                                                            <CheckBox Grid.Column="2"
+                                                                      IsChecked="{Binding IsSavePressureCurve, Mode=TwoWay}"
+                                                                      Margin="6,0"
+                                                                      VerticalAlignment="Center"
+                                                                      FontSize="{DynamicResource Font.Size.Body3}" />
+
+                                                            <!-- 压力曲线图保存路径 -->
+                                                            <TextBox Grid.Column="3"
+                                                                     Text="{Binding PressureCurvePath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                                     Margin="6,0"
+                                                                     VerticalAlignment="Center" />
+
+                                                            <!-- 选择路径按钮 -->
+                                                            <Button Grid.Column="4"
+                                                                    Style="{StaticResource MaterialDesignRaisedButton}"
+                                                                    Command="{Binding DataContext.BrowsePressureCurvePathCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
+                                                                    CommandParameter="{Binding}">
+                                                                <materialDesign:PackIcon Kind="FolderOpen" />
+                                                            </Button>
+                                                        </Grid>
+                                                    </Border>
+                                                </DataTemplate>
+                                            </ItemsControl.ItemTemplate>
+                                        </ItemsControl>
+                                    </ScrollViewer>
+                                </Grid>
+                            </GroupBox>
+
+
+                            <!-- 保存按钮 -->
+                            <StackPanel Grid.Row="11"
+                                        Grid.ColumnSpan="3"
+                                        Orientation="Horizontal"
+                                        HorizontalAlignment="Right"
+                                        VerticalAlignment="Center"
+                                        Margin="0,10,0,0">
+                                <Button Style="{StaticResource MaterialDesignRaisedButton}"
+                                        materialDesign:ButtonAssist.CornerRadius="10"
+                                        MinWidth="120"
+                                        Command="{Binding SaveSystemParametersCommand}"
+                                        IsEnabled="{Binding IsAllowEdit}">
+                                    <StackPanel Orientation="Horizontal"
+                                                HorizontalAlignment="Center">
+                                        <materialDesign:PackIcon Kind="ContentSaveCheck"
+                                                                 Margin="0,0,6,0" />
+                                        <TextBlock VerticalAlignment="Center"
+                                                   Text="保存系统参数" />
+                                    </StackPanel>
+                                </Button>
+                            </StackPanel>
                         </Grid>
-                    </GroupBox>
-                </StackPanel>
+                        <!--刷卡参数配置-->
+                        <GroupBox Grid.Row="5"
+                                  Grid.ColumnSpan="2"
+                                  Header="刷卡器配置"
+                                  HorizontalAlignment="Left"
+                                  MinWidth="400"
+                                  Margin="0,12,0,0">
+                            <Grid Margin="10">
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition Width="auto" />
+                                    <ColumnDefinition Width="*" />
+                                </Grid.ColumnDefinitions>
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                </Grid.RowDefinitions>
+                                <TextBlock Text="PortName:"
+                                           Grid.Row="0"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
+                                <TextBox Text="{Binding CardReaderConfig.PortName,Mode=TwoWay}"
+                                         Grid.Row="0"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
+                                <TextBlock Text="BaudRate:"
+                                           Grid.Row="1"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
+                                <TextBox Text="{Binding CardReaderConfig.BaudRate,Mode=TwoWay}"
+                                         Grid.Row="1"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
+                                <TextBlock Text="Parity:"
+                                           Grid.Row="2"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
+                                <ComboBox Grid.Row="2"
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding CardReaderConfig.Parity,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource Parity}}" />
+                                <TextBlock Text="StopBits:"
+                                           Grid.Row="3"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
+                                <ComboBox Grid.Row="3"
+                                          Grid.Column="1"
+                                          SelectedItem="{Binding CardReaderConfig.StopBits,Mode=TwoWay}"
+                                          ItemsSource="{Binding Source={StaticResource StopBits}}" />
+                                <TextBlock Text="DataBits:"
+                                           Grid.Row="4"
+                                           Grid.Column="0"
+                                           HorizontalAlignment="Right" />
+                                <TextBox Text="{Binding CardReaderConfig.DataBits,Mode=TwoWay}"
+                                         Grid.Row="4"
+                                         Grid.Column="1"
+                                         Margin="6,0" />
+
+                                <Button Grid.Row="5"
+                                        Grid.Column="1"
+                                        Margin="0,6"
+                                        Style="{StaticResource MaterialDesignRaisedButton}"
+                                        materialDesign:ButtonAssist.CornerRadius="10"
+                                        MinWidth="120"
+                                        Command="{Binding SaveCardReaderConfigCommand}">
+                                    <StackPanel Orientation="Horizontal"
+                                                HorizontalAlignment="Center">
+                                        <materialDesign:PackIcon Kind="ContentSaveCheck"
+                                                                 Margin="0,0,6,0" />
+                                        <TextBlock VerticalAlignment="Center"
+                                                   Text="保存刷卡器配置" />
+                                    </StackPanel>
+                                </Button>
+                            </Grid>
+                        </GroupBox>
+                    </StackPanel>
+                </ScrollViewer>
             </TabItem>
 
             <!--生产排班-->