Jelajahi Sumber

Merge branch 'master' of http://49.235.130.76/XXF_1122/DaisyNPILine

孝锋 徐 7 bulan lalu
induk
melakukan
e5162f64f9

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

@@ -145,6 +145,7 @@ namespace TeamAAS_VP
             containerRegistry.RegisterSingleton<IMesService, MesService>();
             containerRegistry.RegisterSingleton<Management>();
             containerRegistry.RegisterSingleton<CardLoginWindowViewModel>();
+            containerRegistry.RegisterSingleton<TorqueService>();
 
             // Register system database service and initializer
             containerRegistry.RegisterSingleton<ISystemDatabaseService, TeamAAS_VP.Data.SystemDatabaseService>();

+ 109 - 9
TeamAAS-VM/Core/Management.cs

@@ -6,6 +6,7 @@ using CSScriptLib;
 using MathNet.Numerics.Distributions;
 using MathNet.Numerics.LinearAlgebra;
 using MathNet.Numerics.RootFinding;
+using Newtonsoft.Json;
 using NPOI.SS.Formula.Functions;
 using NPOI.Util;
 using Opc.Ua;
@@ -22,6 +23,8 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
 using System.Drawing;
 using System.IO;
 using System.Linq;
@@ -111,6 +114,8 @@ namespace TeamAAS_VP.Core
         /// 超时自动停止秒数
         /// </summary>
         private int _pressureMaxDurationSeconds = 30; //超时自动停止秒数
+        Stopwatch swCT = new Stopwatch();
+        List<LockResult> lockResultsAll = new List<LockResult>();//一个产品的总结果
         #endregion
 
         #region 属性
@@ -200,7 +205,7 @@ namespace TeamAAS_VP.Core
             set { SetProperty(ref _COM, value); }
         }
 
-        private string _SignalValue;
+        private string _SignalValue = "0";
         /// <summary>
         /// 扭力测量仪获取的最大值
         /// </summary>
@@ -229,6 +234,16 @@ namespace TeamAAS_VP.Core
             get { return _NumStatistics; }
             set { SetProperty(ref _NumStatistics, value); }
         }
+
+        private double _CTtime;
+        /// <summary>
+        /// ct
+        /// </summary>
+        public double CTtime
+        {
+            get { return _CTtime; }
+            set { SetProperty(ref _CTtime, value); }
+        }
         #endregion
 
         #region 命令
@@ -1087,6 +1102,7 @@ namespace TeamAAS_VP.Core
                 await Console.Out.WriteLineAsync(data);
                 string response = data.Split('\r')[0];
                 SendTaskMessage($"{poname}Receive:{response}", MessageLevel.Info);
+                SignalValue = "";
                 SignalValue = response;
             }
             catch (Exception ex)
@@ -1737,6 +1753,7 @@ namespace TeamAAS_VP.Core
                                 var _ = lockResult.SaveToCsvAsync(curveFileFullPath);
                             }
 
+                            lockResultsAll.Add(lockResult);
                             App.Current.Dispatcher.Invoke(() =>
                             {
                                 _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
@@ -1748,16 +1765,17 @@ namespace TeamAAS_VP.Core
                             //吸嘴数量+1
                             NumStatistics.NozzleNum = await _systemDatabaseService.IncrementLatestNozzleLockCountAsync(currentUserName);
 
-                            await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
-                            // 停止采集压力并保存
-                            await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
-                        }
-                        else
-                        {
-                            SendTaskMessage(Lang.停止锁付信号已关闭, MessageLevel.Alarm);
-                        }
+                        
+                        await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
+                        // 停止采集压力并保存
+                        await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
+                    }
+                    else
+                    {
+                        SendTaskMessage(Lang.停止锁付信号已关闭, MessageLevel.Alarm);
                     }
                 }
+            }
                 // 多相机坐标合并
                 else if (addressConfig.In_RequestPosition.Address.Contains(tuple.nodeId))
                 {
@@ -1849,6 +1867,7 @@ namespace TeamAAS_VP.Core
                         }
                     }
                 }
+                
                 // 过站检查
                 else
                 {
@@ -1867,8 +1886,10 @@ namespace TeamAAS_VP.Core
                                     return;
                                 }
                                 var code = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, i));
+                                //询问mes
                                 if (state == 1)
                                 {
+                                    swCT.Restart();
                                     //这里缺少从MES获取产品配方的内容,需要补充
 
                                     _LastMesCheckTime[i] = DateTime.UtcNow;
@@ -1908,6 +1929,10 @@ namespace TeamAAS_VP.Core
                                     //假设上传成功,这里缺少上传失败的处理
 
                                     await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
+                                    swCT.Stop();
+                                    CTtime = Math.Round(swCT.Elapsed.TotalSeconds, 3);
+                                    WriteProductLog(lockResultsAll, code, CTtime);
+                                    lockResultsAll.Clear();
                                 }
                                 else
                                 {
@@ -2133,6 +2158,81 @@ namespace TeamAAS_VP.Core
         }
         #endregion
 
+
+        #region 产品锁付记录进行存储
+        /// <summary>
+        /// 产品锁付记录进行存储
+        /// </summary>
+        /// <param name="result">结果</param>
+        public void WriteProductLog(List<LockResult> lockResults,string rfid,double ct)
+        {
+            try
+            {
+                string result = "";//产品的总结果
+                foreach (var item in lockResults)
+                {
+                    result = "OK";
+                    if (!item.LockPassed)
+                    {
+                        result = "NG";
+                        break;
+                    }
+                }
+                DateTime dt = DateTime.Now;
+                int number = lockResults.Count;//螺丝数量
+                string path = $"E:\\Data\\生产数据\\{dt.ToString("yyyy-MM")}\\{dt.ToString("yyyy-MM-dd")}.csv";
+                StringBuilder sb = new StringBuilder();
+                //具体的ct需要优化
+                sb.Append($"{dt.ToString("yyyy-MM-dd HH:mm:ss")},{lockResults[0].ProductName},{Math.Round(ct, 3)},{rfid},{result},{lockResults[number-1].NozzleNumber},{lockResults[number - 1].HeadNumber},");
+                foreach (var item in lockResults)
+                {
+                    try
+                    {
+                        sb.Append($"{item.LockPassed},{item.ResultDetails},{item.LockTorque},{item.TargetTorqueUpperLimit},{item.TargetTorqueLowerLimit},{item.LockTurns},{item.TargetTurnsUpperLimit},{item.TargetTurnsLowerLimit},{item.Pressure},{item.PositionX},{item.PositionY},{item.StartPositionZ},{item.EndPositionZ},{item.LockDescentSpeed},");
+                    }
+                    catch (Exception)
+                    {
+                        sb.Append($",,,,,,,,,,,,,,");
+                    }
+                }
+                //========================
+                if (!Directory.Exists(Path.GetDirectoryName(path)))   //判断文件夹是否
+                {
+                    Directory.CreateDirectory(Path.GetDirectoryName(path));    //创建文件夹
+                }
+
+                if (File.Exists(path))
+                {
+                    // 使用 StreamWriter 以追加模式打开文件
+                    StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
+                    sw.WriteLine(sb.ToString().TrimEnd(','));
+                    sw.Close();
+                    sw.Dispose();
+                }
+                else
+                {
+                    StreamWriter sw = new StreamWriter(path, true, Encoding.UTF8);
+                    StringBuilder sb1 = new StringBuilder();
+                    StringBuilder sb_up = new StringBuilder();
+                    StringBuilder sb_down = new StringBuilder();
+                    sb1.Append("时间,产品名称,CT,RFID,产品结果,吸嘴数量,披头数量,");
+                    for (int i = 0; i < number; i++)
+                    {
+                        sb1.Append($"螺丝{i + 1}结果,螺丝{i + 1}结果详情,螺丝{i + 1}扭矩,螺丝{i + 1}扭矩上限,螺丝{i + 1}扭矩下限,螺丝{i + 1}圈数,螺丝{i + 1}圈数上限,螺丝{i + 1}圈数下限,螺丝{i + 1}压力值,螺丝{i + 1}锁附X,螺丝{i + 1}锁附Y,螺丝{i + 1}开始位置Z,螺丝{i + 1}结束位置Z,螺丝{i + 1}锁附下降速度,");
+                    }
+                    sw.WriteLine(sb1.ToString().TrimEnd(','));
+                    sw.WriteLine(sb.ToString().TrimEnd(','));
+                    sw.Close();
+                    sw.Dispose();
+                }
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogError("写入产品记录时出错!", ex);
+            }
+        }
+        #endregion
+
         #endregion
     }
 }

+ 3 - 1
TeamAAS-VM/Models/LockResult.cs

@@ -334,6 +334,7 @@ namespace TeamAAS_VP.Models
             return new LockResult
             {
                 Number = this.Number,
+                ProductName = this.ProductName,
                 ProductNumber = this.ProductNumber,
                 Timestamp = this.Timestamp,
                 LockTurns = this.LockTurns,
@@ -388,11 +389,12 @@ namespace TeamAAS_VP.Models
             using (var writer = new System.IO.StreamWriter(filePath, false, System.Text.Encoding.UTF8))
             {
                 // 写入锁付结果信息表头(已新增字段)
-                writer.WriteLine("Number,ProductNumber,Timestamp,LockTurns,LockTorque,LockDuration,LockPassed,ScrewdriverProgramNumber,Pressure,TargetTorque,TargetTurnsUpperLimit,TargetTurnsLowerLimit,TargetLockSpeed,StartPositionX,StartPositionY,StartPositionZ,EndPositionZ,LockDescentSpeed,FeederNumber,FeederBatchNumber,NozzleNumber,HeadNumber,ResultDetails,ScrewdriverGetDataSucceed,OperatorName,ProductImagePath,LockCurveImagePath");
+                writer.WriteLine("Number,ProductName,ProductNumber,Timestamp,LockTurns,LockTorque,LockDuration,LockPassed,ScrewdriverProgramNumber,Pressure,TargetTorque,TargetTurnsUpperLimit,TargetTurnsLowerLimit,TargetLockSpeed,StartPositionX,StartPositionY,StartPositionZ,EndPositionZ,LockDescentSpeed,FeederNumber,FeederBatchNumber,NozzleNumber,HeadNumber,ResultDetails,ScrewdriverGetDataSucceed,OperatorName,ProductImagePath,LockCurveImagePath");
 
                 // 写入锁付结果数据行(所有字段均做 CSV 转义)
                 writer.WriteLine(string.Join(",",
                     EscapeCsv(Number),
+                    EscapeCsv(ProductName),
                     EscapeCsv(ProductNumber),
                     EscapeCsv(Timestamp),
                     EscapeCsv(LockTurns),

+ 169 - 0
TeamAAS-VM/Models/PLC/PlcAddressConfig.cs

@@ -298,6 +298,111 @@ namespace TeamAAS_VP.Models.PLC
             get { return _Out_ScrewFeederIsChanged; }
             set { SetProperty(ref _Out_ScrewFeederIsChanged, value); }
         }
+
+        private PlcAddress _Check_Screw ;
+        /// <summary>
+        /// 点检扭力  电批正转
+        /// </summary>
+        public PlcAddress Check_ScrewTorque
+        {
+            get { return _Check_Screw ; }
+            set { SetProperty(ref _Check_Screw, value); }
+        }
+
+        private PlcAddress _Screw_OK;
+        public PlcAddress Screw_OK
+        {
+            get { return _Screw_OK; }
+            set { SetProperty(ref _Screw_OK, value); }
+        }
+
+        private PlcAddress _Screw_NG;
+        public PlcAddress Screw_NG
+        {
+            get { return _Screw_NG; }
+            set { SetProperty(ref _Screw_NG, value); }
+        }
+
+        private PlcAddress _OP_AutoManual;
+        /// <summary>
+        /// PLC手动模式与自动模式切换
+        /// </summary>
+        public PlcAddress OP_AutoManual
+        {
+            get { return _OP_AutoManual; }
+            set { _OP_AutoManual = value; }
+        }
+
+        private PlcAddress _ManuToHome;
+        /// <summary>
+        /// 关闭真空
+        /// </summary>
+        public PlcAddress ManuToHome
+        {
+            get { return _ManuToHome; }
+            set { _ManuToHome = value; }
+        }
+
+        private PlcAddress _ManuTOWork;
+        /// <summary>
+        /// 打开真空
+        /// </summary>
+        public PlcAddress ManuTOWork
+        {
+            get { return _ManuTOWork; }
+            set { _ManuTOWork = value; }
+        }
+
+        private PlcAddress _InWork;
+        /// <summary>
+        /// 真空关闭反馈
+        /// </summary>
+        public PlcAddress InWork
+        {
+            get { return _InWork; }
+            set { _InWork = value; }
+        }
+
+        private PlcAddress _Screw_Backward;
+        /// <summary>
+        /// 电批反转  需要一直给true
+        /// </summary>
+        public PlcAddress Screw_Backward
+        {
+            get { return _Screw_Backward; }
+            set { _Screw_Backward = value; }
+        }
+
+        private PlcAddress _Manu_XAxis_Velocity;
+        /// <summary>
+        /// 设置X轴速度
+        /// </summary>
+        public PlcAddress Manu_XAxis_Velocity
+        {
+            get { return _Manu_XAxis_Velocity; }
+            set { _Manu_XAxis_Velocity = value; }
+        }
+
+        private PlcAddress _Manu_YAxis_Velocity;
+        /// <summary>
+        /// 设置Y轴速度
+        /// </summary>
+        public PlcAddress Manu_YAxis_Velocity
+        {
+            get { return _Manu_YAxis_Velocity; }
+            set { _Manu_YAxis_Velocity = value; }
+        }
+
+        private PlcAddress _Manu_ZAxis_Velocity;
+        /// <summary>
+        /// 设置Z轴速度
+        /// </summary>
+        public PlcAddress Manu_ZAxis_Velocity
+        {
+            get { return _Manu_ZAxis_Velocity; }
+            set { _Manu_ZAxis_Velocity = value; }
+        }
+
         #endregion
 
         #region 从PLC读取的地址
@@ -658,6 +763,70 @@ namespace TeamAAS_VP.Models.PLC
             Out_MesStatus.DataType = "int16";
             Out_MesStatus.Description = Lang.过站信息1允许工作2本站放行3数据上传完成;
 
+            Check_ScrewTorque = Ensure(Check_ScrewTorque);
+            Check_ScrewTorque.Address = "ns=4;s=DB_DriveControl|ScrewCtrl[1].Cmd.ManuStart";
+            Check_ScrewTorque.DataType = "Bool";
+            Check_ScrewTorque.Description = "电批正转";
+
+            //首先到废料桶上方投料
+            //有三个示教的地方
+            //
+            //Machine.OP_AutoManual  ns=4;s=DB_Control|Machine.OP_AutoManual 手自动  都是bool
+            //ns=4;s=DB_DriveControl|VacCtrl[1].Cmd.ManuToHome 关闭真空 只需要给true就行
+            //ns=4;s=DB_DriveControl|VacCtrl[1].Cmd.ManuTOWork 打开真空 只需要给true就行
+            //ns=4;s=DB_DriveControl|VacCtrl[1].Status.InWork 真空到位反馈  吸到料
+            //ns=4;s=DB_DriveControl|ScrewCtrl[1].Cmd.ManuBackward  电批反转
+            //ns=4;s=DB_DriveControl|AxisCtrl[1].Parm.ManuVelocity  Manu_Axis_Velocity
+            Manu_XAxis_Velocity = Ensure(Manu_XAxis_Velocity);
+            Manu_XAxis_Velocity.Address = "ns=4;s=DB_DriveControl|AxisCtrl[1].Parm.ManuVelocity";
+            Manu_XAxis_Velocity.DataType = "Float";
+            Manu_XAxis_Velocity.Description = "手动设置X轴速度";
+
+            Manu_YAxis_Velocity = Ensure(Manu_YAxis_Velocity);
+            Manu_YAxis_Velocity.Address = "ns=4;s=DB_DriveControl|AxisCtrl[2].Parm.ManuVelocity";
+            Manu_YAxis_Velocity.DataType = "Float";
+            Manu_YAxis_Velocity.Description = "手动设置Y轴速度";
+
+            Manu_ZAxis_Velocity = Ensure(Manu_ZAxis_Velocity);
+            Manu_ZAxis_Velocity.Address = "ns=4;s=DB_DriveControl|AxisCtrl[3].Parm.ManuVelocity";
+            Manu_ZAxis_Velocity.DataType = "Float";
+            Manu_ZAxis_Velocity.Description = "手动设置Z轴速度";
+
+            OP_AutoManual = Ensure(OP_AutoManual);
+            OP_AutoManual.Address = "ns=4;s=DB_Control|Machine.OP_AutoManual";
+            OP_AutoManual.DataType = "Bool";
+            OP_AutoManual.Description = "手自动切换";
+
+            ManuToHome = Ensure(ManuToHome);
+            ManuToHome.Address = "ns=4;s=DB_DriveControl|VacCtrl[1].Cmd.ManuToHome";
+            ManuToHome.DataType = "Bool";
+            ManuToHome.Description = "关闭真空";
+
+            ManuTOWork = Ensure(ManuTOWork);
+            ManuTOWork.Address = "ns=4;s=DB_DriveControl|VacCtrl[1].Cmd.ManuToWork";
+            ManuTOWork.DataType = "Bool";
+            ManuTOWork.Description = "打开真空";
+
+            InWork = Ensure(InWork);
+            InWork.Address = "ns=4;s=DB_DriveControl|VacCtrl[1].Status.InWork";
+            InWork.DataType = "Bool";
+            InWork.Description = "真空到位反馈";
+
+            Screw_OK = Ensure(Screw_OK);
+            Screw_OK.Address = "ns=4;s=DB_DriveControl|ScrewCtrl[1].Status.OK";
+            Screw_OK.DataType = "Bool";
+            Screw_OK.Description = "电批OK";
+
+            Screw_NG = Ensure(Screw_NG);
+            Screw_NG.Address = "ns=4;s=DB_DriveControl|ScrewCtrl[1].Status.NG";
+            Screw_NG.DataType = "Bool";
+            Screw_NG.Description = "电批NG";
+
+            Screw_Backward = Ensure(Screw_Backward);
+            Screw_Backward.Address = "ns=4;s=DB_DriveControl|ScrewCtrl[1].Cmd.ManuBackward";
+            Screw_Backward.DataType = "Bool";
+            Screw_Backward.Description = "电批反转";
+
             // Out_PickCamera 初始化并赋地址
             Out_PickCamera = EnsurePoint(Out_PickCamera);
             Out_PickCamera.Description = Lang.取料拍照点位参数;

+ 83 - 0
TeamAAS-VM/Models/Torque/PlcPoint_Torque.cs

@@ -0,0 +1,83 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TeamAAS_VP.Core.PLCs;
+
+namespace TeamAAS_VP.Models.Torque
+{
+    public class PlcPoint_Torque : BindableBase
+    {
+        private int _Number;
+        public int Number
+        {
+            get { return _Number; }
+            set { SetProperty(ref _Number, value); }
+        }
+
+        private string _Label;
+        public string Label
+        {
+            get { return _Label; }
+            set { SetProperty(ref _Label, value); }
+        }
+
+        private float _X_Position;
+        public float X_Position
+        {
+            get { return _X_Position; }
+            set { SetProperty(ref _X_Position, value); }
+        }
+
+        private float _Y_Position;
+        public float Y_Position
+        {
+            get { return _Y_Position; }
+            set { SetProperty(ref _Y_Position, value); }
+        }
+
+
+        private float _Z_Position_Start;
+        public float Z_Position_Start
+        {
+            get { return _Z_Position_Start; }
+            set { SetProperty(ref _Z_Position_Start, value); }
+        }
+
+
+        private float _Z_Position_Stop;
+        public float Z_Position_Stop
+        {
+            get { return _Z_Position_Stop; }
+            set { SetProperty(ref _Z_Position_Stop, value); }
+        }
+
+
+        public PlcPoint_Torque()
+        {
+            Number = 0;
+            X_Position = 0;
+            Y_Position = 0;
+            Z_Position_Start = 0;
+            Z_Position_Stop = 0;
+        }
+
+        public PlcPoint_Torque Clone()
+        {
+            return new PlcPoint_Torque
+            {
+                Number = this.Number,
+                Label = this.Label,
+                X_Position = this.X_Position,
+                Y_Position = this.Y_Position,
+                Z_Position_Start = this.Z_Position_Start,
+                Z_Position_Stop = this.Z_Position_Stop,
+
+            };
+        }
+
+
+    }
+}

+ 31 - 0
TeamAAS-VM/Models/Torque/TorqueProduceModel.cs

@@ -0,0 +1,31 @@
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TeamAAS_VP.Models.PLC;
+
+namespace TeamAAS_VP.Models.Torque
+{
+    public class TorqueProduceModel:BindableBase
+    {
+        private ObservableCollection<PlcPoint_Torque> _TorquePoints = new ObservableCollection<PlcPoint_Torque>();
+        /// <summary>
+        /// 投废料点位
+        /// </summary>
+        public ObservableCollection<PlcPoint_Torque> TorquePoints
+        {
+            get { return _TorquePoints; }
+            set { SetProperty(ref _TorquePoints, value); }
+        }
+
+        /// <summary>
+        /// 扭力阈值
+        /// </summary>
+        public float TorqueValue { get; set; } = 0;
+
+
+    }
+}

+ 15 - 0
TeamAAS-VM/Models/Torque/Torque_TaskStatus.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TeamAAS_VP.Models.Torque
+{
+    public class Torque_TaskStatus
+    {
+        public bool Result { get; set; }
+
+        public string Message { get; set; }
+    }
+}

+ 2 - 0
TeamAAS-VM/Models/TorqueTest.cs

@@ -18,5 +18,7 @@ namespace TeamAAS_VP.Models
         /// 扭力阈值
         /// </summary>
         public double TorqueValue { get; set; }
+
+        public double ZDistance { get; set; }
     }
 }

+ 18 - 0
TeamAAS-VM/Resources/Languages/Lang.Designer.cs

@@ -1878,6 +1878,15 @@ namespace TeamAAS_VP.Resources.Languages {
             }
         }
         
+        /// <summary>
+        ///   查找类似 下压距离 的本地化字符串。
+        /// </summary>
+        public static string 下压距离 {
+            get {
+                return ResourceManager.GetString("下压距离", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   查找类似 下相机二次定位点位 的本地化字符串。
         /// </summary>
@@ -7944,6 +7953,15 @@ namespace TeamAAS_VP.Resources.Languages {
             }
         }
         
+        /// <summary>
+        ///   查找类似  的本地化字符串。
+        /// </summary>
+        public static string 点检螺丝 {
+            get {
+                return ResourceManager.GetString("点检螺丝", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   查找类似 点编号 的本地化字符串。
         /// </summary>

+ 6 - 0
TeamAAS-VM/Resources/Languages/Lang.resx

@@ -4061,6 +4061,12 @@
   <data name="视觉静态精度分析" xml:space="preserve">
     <value>视觉静态精度分析</value>
   </data>
+  <data name="点检螺丝" xml:space="preserve">
+    <value></value>
+  </data>
+  <data name="下压距离" xml:space="preserve">
+    <value>下压距离</value>
+  </data>
   <data name="ProcedureSaveImagePathModel_Month_Day_Formula_ProductSN_Time" xml:space="preserve">
     <value>年月/日/配方名/产品SN/产品SN+时间</value>
   </data>

+ 225 - 0
TeamAAS-VM/Services/TorqueService.cs

@@ -0,0 +1,225 @@
+using MathNet.Numerics;
+using Prism.Events;
+using Prism.Ioc;
+using Prism.Mvvm;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Core;
+using TeamAAS_VP.Core.PLCs;
+using TeamAAS_VP.Events;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+using TeamAAS_VP.Models.PLC;
+using TeamAAS_VP.Models.Torque;
+
+namespace TeamAAS_VP.Services
+{
+    public class TorqueService : BindableBase
+    {
+
+
+        IEventAggregator _eventAggregator;
+        IConfigService _configService;
+        IContainerProvider _container;
+        IRobotService _robotService;
+        IPlcService _plcService;
+        private Management management;
+
+        /// <summary>
+        /// 扭矩日志月份目录
+        /// </summary>
+        private string TorqueParametrPath
+        {
+            get
+            {
+                // 示例:..//Log//LogTorque//2026-01
+                return $"..//Log//LogTorque//{DateTime.Now:yyyy-MM}";
+            }
+        }
+
+        /// <summary>
+        /// 当天扭矩 CSV 文件完整路径
+        /// </summary>
+        private string CurrentVariableCSV
+        {
+            get
+            {
+                // 示例:..//Log//LogTorque//2026-01//2026-01-22.csv
+                return $"..//Log//LogTorque//{DateTime.Now:yyyy-MM}//{DateTime.Now:yyyy-MM-dd}.csv";
+            }
+        }
+
+
+        public async void Save_Torque_Log(string fileName, string content)
+        {
+            try
+            {
+                if (!File.Exists(TorqueParametrPath))
+                {
+                    Directory.CreateDirectory(TorqueParametrPath);
+                }
+                bool Is_Exists = File.Exists(CurrentVariableCSV);
+                if (!Is_Exists)
+                {
+                    Directory.CreateDirectory(CurrentVariableCSV);
+                }
+
+                using (FileStream fs = new FileStream(CurrentVariableCSV, FileMode.Append, FileAccess.Write))
+                {
+                    using (StreamWriter sw = new StreamWriter(fs))
+                    {
+                        if (!Is_Exists)
+                        {
+                            //初始化文件,写入标题行
+                            sw.WriteLine("Time,...");
+                            sw.WriteLine("Time,...");
+                        }
+                        else
+                        {
+                            sw.WriteLine("Time,...");
+                        }
+                    }
+                }
+
+            }
+            catch (Exception)
+            {
+
+            }
+        }
+
+        public TorqueService(IEventAggregator ea, IConfigService configService,
+            IContainerProvider container, IRobotService robotService, IPlcService plcService)
+        {
+            _eventAggregator = ea;
+            _configService = configService;
+            _container = container;
+            _robotService = robotService;
+            _plcService = plcService;
+            management = _container.Resolve<Management>();
+        }
+
+        public async Task<bool> Throw_Screw_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint)
+        {
+            List<bool> result = new List<bool>();
+            var point = new RPoint()
+            {
+                X = PlcPoint.TorquePoints[0].X_Position,
+                Y = PlcPoint.TorquePoints[0].Y_Position,
+                Z = PlcPoint.TorquePoints[0].Z_Position_Start,
+            };
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Manu_ZAxis_Velocity.Address, (float)99.0));
+
+            float Z_Distance = -(PlcPoint.TorquePoints[0].Z_Position_Start - PlcPoint.TorquePoints[0].Z_Position_Stop);
+
+            result.Add(await Robot.JumpAsync(point, 0));
+
+            result.Add(await plc.WriteNodeAsync<bool>(addressConfig.ManuToHome.Address, true));
+
+            return !result.Contains(false);
+        }
+
+        public async Task<bool> Pick_Screw_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint)
+        {
+            List<bool> result = new List<bool>();
+            var point = new RPoint()
+            {
+                X = PlcPoint.TorquePoints[1].X_Position,
+                Y = PlcPoint.TorquePoints[1].Y_Position,
+                Z = PlcPoint.TorquePoints[1].Z_Position_Start,
+            };
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Screw_Backward.Address, true));
+
+            result.Add(await Robot.JumpAsync(point, 0));
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.ManuTOWork.Address, true));
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Screw_Backward.Address, false));
+
+            result.Add(await BackZero_Async(Robot, point));
+
+            result.Add(await Task.Run(() =>
+            {
+                return (bool)plc.ReadNode(addressConfig.InWork.Address);
+            }));
+
+            return !result.Contains(false);
+        }
+
+        public async Task<bool> Screw_Torque_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint)
+        {
+            List<bool> result = new List<bool>();
+            var point = new RPoint()
+            {
+                X = PlcPoint.TorquePoints[2].X_Position,
+                Y = PlcPoint.TorquePoints[2].Y_Position,
+                Z = PlcPoint.TorquePoints[2].Z_Position_Start,
+            };
+            //float Z_Distance = -(PlcPoint.TorquePoints[2].Z_Position_Start - PlcPoint.TorquePoints[2].Z_Position_Stop);
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Manu_ZAxis_Velocity.Address, (float)5.0));
+
+            result.Add(await Robot.JumpAsync(point, 0));
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Check_ScrewTorque.Address, true));
+
+            //result.Add(await Robot.JogAsync("Z", Z_Distance));
+            point.Z = PlcPoint.TorquePoints[2].Z_Position_Stop;
+
+            Robot.Go(point);
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.ManuToHome.Address, true));
+
+            result.Add(await plc.WriteNodeAsync(addressConfig.Manu_ZAxis_Velocity.Address, (float)100.0));
+
+            result.Add(await BackZero_Async(Robot, point));
+
+            return !result.Contains(false);
+        }
+
+
+        public async Task<bool> Safety_Position_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, TorqueProduceModel PlcPoint)
+        {
+            List<bool> result = new List<bool>();
+            var point = new RPoint()
+            {
+                X = PlcPoint.TorquePoints[3].X_Position,
+                Y = PlcPoint.TorquePoints[3].Y_Position,
+                Z = PlcPoint.TorquePoints[3].Z_Position_Start,
+            };
+
+            result.Add(await Robot.JumpAsync(point, 0));
+
+            return !result.Contains(false);
+        }
+
+        public async Task<bool> BackZero_Async(IRobot Robot, RPoint point)
+        {
+            point.Z = 0;
+            return Robot.Go(point);
+        }
+
+        public async Task Signal_Move_Async(IRobot Robot, OpcUaClientPLC plc, PlcAddressConfig addressConfig, PlcPoint_Torque target)
+        {
+            var point = new RPoint()
+            {
+                X = target.X_Position,
+                Y = target.Y_Position,
+                Z = target.Z_Position_Start,
+            };
+
+            await Robot.JumpAsync(point, 0);
+
+        }
+
+    }
+
+}

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

@@ -537,9 +537,12 @@
     <Compile Include="Models\HeadChangeRecord.cs" />
     <Compile Include="Models\NozzleChangeRecord.cs" />
     <Compile Include="Models\NumberStatistics.cs" />
+    <Compile Include="Models\Torque\PlcPoint_Torque.cs" />
     <Compile Include="Models\PhotoCaptureRecord.cs" />
     <Compile Include="Models\ScrewFeederBatchRecord.cs" />
     <Compile Include="Models\TorqueTest.cs" />
+    <Compile Include="Models\Torque\Torque_TaskStatus.cs" />
+    <Compile Include="Models\Torque\TorqueProduceModel.cs" />
     <Compile Include="Resources\Languages\Lang.Designer.cs">
       <AutoGen>True</AutoGen>
       <DesignTime>True</DesignTime>
@@ -551,6 +554,7 @@
     <Compile Include="ViewModels\Home\ChangeNozzleViewModel.cs" />
     <Compile Include="ViewModels\Home\ChangeHeaderViewModel.cs" />
     <Compile Include="ViewModels\Home\AddScrewViewModel.cs" />
+    <Compile Include="Services\TorqueService.cs" />
     <Compile Include="ViewModels\Home\TorqueCheckViewModel.cs" />
     <Compile Include="ViewModels\Product\ImageDisplayViewModel.cs" />
     <Compile Include="ViewModels\Setting\AddScrewFeederViewModel.cs" />

+ 305 - 46
TeamAAS-VM/ViewModels/Home/TorqueCheckViewModel.cs

@@ -1,5 +1,7 @@
-using NPOI.OpenXml4Net.OPC.Internal;
+using MathNet.Numerics;
+using NPOI.OpenXml4Net.OPC.Internal;
 using NPOI.SS.Formula.Functions;
+using OxyPlot;
 using Prism.Commands;
 using Prism.Events;
 using Prism.Ioc;
@@ -7,17 +9,24 @@ using Prism.Mvvm;
 using Prism.Services.Dialogs;
 using System;
 using System.Collections.Generic;
+using System.Collections.ObjectModel;
 using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
+using TeamAAS_VP.Controls;
 using TeamAAS_VP.Core;
+using TeamAAS_VP.Core.PLCs;
+using TeamAAS_VP.Core.ScrewDriver;
+using TeamAAS_VP.Data;
 using TeamAAS_VP.Enums;
 using TeamAAS_VP.Events;
 using TeamAAS_VP.Interfaces;
 using TeamAAS_VP.Models;
+using TeamAAS_VP.Models.PLC;
+using TeamAAS_VP.Models.Torque;
 using TeamAAS_VP.Resources.Languages;
 using TeamAAS_VP.Services;
 using FileHelper = TeamAAS_VP.Core.FileHelper;
@@ -26,12 +35,18 @@ namespace TeamAAS_VP.ViewModels.Home
 {
     public class TorqueCheckViewModel : BindableBase, IDialogAware
     {
+        // 点检扭矩参数存放日志地址
+        public static readonly string CheckTorqueConfigurationPath = "..//Log//ScrewFeedersConfiguration.cfg";
         IEventAggregator _eventAggregator;
         IConfigService _configService;
         IContainerProvider _container;
         IRobotService _robotService;
+        IPlcService _plcService;
+        TorqueService _torqueService;
+        float Value { get; set; } = 0;
 
         #region 属性
+
         private Management _management;
         public Management management
         {
@@ -81,15 +96,17 @@ namespace TeamAAS_VP.ViewModels.Home
             }
         }
 
-        private TorqueTest _tc = new TorqueTest();
-        public TorqueTest Tc
+        private float _Z_Distance;
+
+        public float Z_Distance
         {
-            get { return _tc; }
-            set { SetProperty(ref _tc, value); }
+            get { return _Z_Distance; }
+            set { SetProperty(ref _Z_Distance, value); }
         }
 
-        private double _torqueValue;
-        public double torqueValue
+
+        private float _torqueValue;
+        public float TorqueValue
         {
             get { return _torqueValue; }
             set { SetProperty(ref _torqueValue, value); }
@@ -135,6 +152,56 @@ namespace TeamAAS_VP.ViewModels.Home
             get { return _FontColor; }
             set { SetProperty(ref _FontColor, value); }
         }
+
+        private int _SelectedIndex;
+        public int SelectedIndex
+        {
+            get { return _SelectedIndex; }
+            set { SetProperty(ref _SelectedIndex, value); }
+        }
+
+        private ObservableCollection<PlcPoint_Torque> _Points = new ObservableCollection<PlcPoint_Torque>();
+        /// <summary>
+        /// 点位集合
+        /// </summary>
+        public ObservableCollection<PlcPoint_Torque> Points
+        {
+            get { return _Points; }
+            set { SetProperty(ref _Points, value); }
+        }
+
+        private TorqueProduceModel _AllProductParameter = new TorqueProduceModel();
+
+        /// <summary>
+        /// 所有产品的参数信息
+        /// </summary>
+        public TorqueProduceModel AllProductParameter
+        {
+            get { return _AllProductParameter; }
+            set { SetProperty(ref _AllProductParameter, value); }
+        }
+
+        private PlcPoint_Torque _selectedPointInDataGrid;
+        public PlcPoint_Torque SelectedPointInDataGrid
+        {
+            get { return _selectedPointInDataGrid; }
+            set
+            {
+                SetProperty(ref _selectedPointInDataGrid, value);
+                // 可以同步到 SelectPoint 属性
+                SelectedPoint = value;
+                AllProductParameter.TorquePoints = _Points;
+            }
+        }
+
+        private PlcPoint_Torque _SelectedPoint;
+        public PlcPoint_Torque SelectedPoint
+        {
+            get { return _SelectedPoint; }
+            set { SetProperty(ref _SelectedPoint, value); }
+        }
+
+
         #endregion
 
         #region 命令
@@ -142,6 +209,10 @@ namespace TeamAAS_VP.ViewModels.Home
         public DelegateCommand CancelCommand =>
             _CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand));
 
+        private DelegateCommand _LoadedCommand;
+        public DelegateCommand LoadedCommand =>
+            _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
+
         private DelegateCommand _ConfirmCommand;
         public DelegateCommand ConfirmCommand =>
             _ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand));
@@ -166,17 +237,37 @@ namespace TeamAAS_VP.ViewModels.Home
         public DelegateCommand WorkCommand =>
             _WorkCommand ?? (_WorkCommand = new DelegateCommand(ExecuteWorkCommand));
 
+        private DelegateCommand _AddPointCommand;
+        public DelegateCommand AddPointCommand =>
+            _AddPointCommand ?? (_AddPointCommand = new DelegateCommand(ExecuteAddPointCommand));
+
+        private DelegateCommand _SavePointsCommand;
+        public DelegateCommand SavePointsCommand =>
+            _SavePointsCommand ?? (_SavePointsCommand = new DelegateCommand(ExecuteSavePointsCommand));
+
+        private DelegateCommand _DeletePointCommand;
+        public DelegateCommand DeletePointCommand =>
+            _DeletePointCommand ?? (_DeletePointCommand = new DelegateCommand(ExecuteDeletePointCommand, CanExecuteDeletePointCommand).ObservesProperty(() => SelectedPointInDataGrid));
+
         #endregion
 
         #region 方法
-        public TorqueCheckViewModel(IEventAggregator ea, IConfigService configService, IContainerProvider container, IRobotService robotService)
+
+        public TorqueCheckViewModel(IEventAggregator ea, IConfigService configService, TorqueService torqueService,
+            IContainerProvider container, IRobotService robotService, IPlcService plcService)
         {
             _eventAggregator = ea;
             _configService = configService;
             _container = container;
             _robotService = robotService;
+            _plcService = plcService;
+            _torqueService = torqueService;
             management = _container.Resolve<Management>();
         }
+        bool CanExecuteDeletePointCommand()
+        {
+            return SelectedPointInDataGrid != null;
+        }
 
         void ExecuteCancelCommand()
         {
@@ -294,81 +385,140 @@ namespace TeamAAS_VP.ViewModels.Home
             {
                 return;
             }
-
+            if (SelectedPoint == null)
+            {
+                MessageBox.Show("请选择示教点位");
+                return;
+            }
             var curpos = await Robot.GetRobotPosAsync();
-            Tc.Xpoint = curpos.X;
-            Tc.Ypoint = curpos.Y;
-            Tc.Zpoint = curpos.Z;
-            FileHelper.WriteJsonFile(Tc, FilePath.TorqueCheckPath);
+            SelectedPoint.X_Position = curpos.X;
+            SelectedPoint.Y_Position = curpos.Y;
+            SelectedPoint.Z_Position_Start = curpos.Z;
+            //SelectedPoint.Z_Position_Stop = curpos.Z - (float)this.Z_Distance;
+            SelectedPoint.Z_Position_Stop = 0;
+
+            AllProductParameter.TorqueValue = this.TorqueValue;
+            AllProductParameter.TorquePoints = Points;
+
+            FileHelper.WriteJsonFile(AllProductParameter, FilePath.TorqueCheckPath);
             _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = $"{Lang.完成}!", Duration = 0.4 });
         }
 
         /// <summary>
         /// 修改
         /// </summary>
-        void ExecuteModifyCommand()
+        async void ExecuteModifyCommand()
         {
             if (MessageBox.Show($"确认要修改扭力阈值吗?", "修改", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
             {
                 return;
             }
-            Tc.TorqueValue = torqueValue;
-            FileHelper.WriteJsonFile(Tc, FilePath.TorqueCheckPath);
+
+            var res = FileHelper.ReadJsonFile<TorqueProduceModel>(FilePath.TorqueCheckPath);
+
+            res.TorqueValue = this.TorqueValue;
+
+            FileHelper.WriteJsonFile(res, FilePath.TorqueCheckPath);
             _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = Lang.完成, Duration = 0.4 });
         }
 
-        void ExecuteWorkCommand()
+        async void ExecuteWorkCommand()
         {
+            if (!File.Exists(FilePath.TorqueCheckPath))
+            {
+                MessageBox.Show("还未示教,请先示教");
+                return;
+            }
+            if (Robot == null || !Robot.IsConnected)
+            {
+                return;
+            }
+            if (MessageBox.Show($"确认要进行点检吗?", "执行点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+            {
+                return;
+            }
             try
             {
-                MoveRobot();
-                Thread.Sleep(500);
-                DisplayResult();
+                if (await MoveRobot())
+                {
+                    
+                }                    
             }
             catch (Exception ex)
             {
                 LogHelper.WriteLogError("执行点检时出错!", ex);
             }
         }
-        public async void MoveRobot()
-        {
-            if (!File.Exists(FilePath.TorqueCheckPath))
-            {
-                MessageBox.Show("还未示教,请先示教");
-                return;
-            }
-            var res = FileHelper.ReadJsonFile<TorqueTest>(FilePath.TorqueCheckPath);
 
-            var point = new RPoint()
-            {
-                X = (float)res.Xpoint,
-                Y = (float)res.Ypoint,
-                Z = (float)res.Zpoint,
-            };
-            if (Robot == null || !Robot.IsConnected) return;
+        /// <summary>
+        /// 点检扭矩总体流程
+        /// </summary>
+        /// <returns></returns>
+        public async Task<bool> MoveRobot()
+        {
+            var Plc_Point = FileHelper.ReadJsonFile<TorqueProduceModel>(FilePath.TorqueCheckPath);
+            PlcAddressConfig addressConfig = _configService.GetPlcAddresses();
+            OpcUaClientPLC plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
             try
             {
-                //确认要执行该点位的该运动指令吗
-                if (MessageBox.Show($"确认要进行点检吗?", "执行点位", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+                if (Plc_Point == null || addressConfig == null || plc == null)
+                {
+                    return false;
+                }
+                //切换手动模式
+                if (await plc.WriteNodeAsync<bool>(addressConfig.OP_AutoManual.Address, false))
                 {
-                    return;
+                    //回设置的零点             
+                    if (await _torqueService.Safety_Position_Async(Robot, plc, addressConfig, Plc_Point))
+                    {
+                        //执行抛螺丝动作
+                        if (await _torqueService.Throw_Screw_Async(Robot, plc, addressConfig, Plc_Point))
+                        {
+                            //执行取螺丝动作
+                            if (await _torqueService.Pick_Screw_Async(Robot, plc, addressConfig, Plc_Point))
+                            {
+                                //执行锁螺丝点位操作
+                                if (await _torqueService.Screw_Torque_Async(Robot, plc, addressConfig, Plc_Point))
+                                {
+                                    //获取电批结果并显示曲线
+                                    if (await WatchAsync(plc, addressConfig))
+                                    {
+                                        await DisplayResult();
+                                        return true;
+                                    }
+                                    MessageBox.Show("未获取到电批结果"); return false;
+                                }
+                                MessageBox.Show("执行锁螺丝点位操作失败"); return false;
+                            }
+                            MessageBox.Show("执行取螺丝动作失败"); return false;
+                        }
+                        MessageBox.Show("执行抛螺丝动作失败"); return false;
+                    }
+                    MessageBox.Show("执行回安全点失败"); return false;
                 }
-                await Robot.JumpAsync(point, 0);
+                MessageBox.Show("点检失败");return false;
             }
             catch (Exception ex)
             {
                 LogHelper.WriteLogError("执行点检移动时出错!", ex);
+                return false;
+            }
+            finally
+            {
+                await _torqueService.Safety_Position_Async(Robot, plc, addressConfig, Plc_Point);
             }
         }
-        public void DisplayResult()
+
+        public async Task DisplayResult()
         {
             try
             {
+                Thread.Sleep(100);
                 TValue = management.SignalValue;
                 double tvalue = double.Parse(TValue.Split(' ')[0]);
-                PValue = $"{management.Value} N.m";
-                double pvalue = management.Value;
-                SubValue = $"{Math.Abs(tvalue - pvalue)} N.m";
+                double pvalue = Value;
+                PValue = $"{Math.Round(pvalue, 3)} kgf.cm";
+                SubValue = $"{Math.Round(Math.Abs(tvalue - pvalue), 3)} kgf.cm";
                 double sub = Math.Abs(tvalue - pvalue);
 
                 var res = FileHelper.ReadJsonFile<TorqueTest>(FilePath.TorqueCheckPath);
@@ -387,7 +537,7 @@ namespace TeamAAS_VP.ViewModels.Home
                 }
                 else
                 {
-                    if (sub <= torqueValue)
+                    if (sub <= TorqueValue)
                     {
                         FontColor = "Green";
                         Result = "OK";
@@ -404,6 +554,50 @@ namespace TeamAAS_VP.ViewModels.Home
                 LogHelper.WriteLogError("执行点检显示时出错!", ex);
             }
         }
+
+        public void Save_Torque_Parameter()
+        { 
+        }
+
+        public async Task<bool> WatchAsync(OpcUaClientPLC plc, PlcAddressConfig addressConfig)
+        {
+            Thread.Sleep(100);
+            object oking = null;
+            object nging = null;
+            int count = 0;
+
+            while (count++ < 10)
+            {
+                oking = plc.ReadNode(addressConfig.Screw_OK.Address);
+                nging = plc.ReadNode(addressConfig.Screw_NG.Address);
+
+                if (oking != null && nging != null)
+                {
+                    bool okin = (bool)oking; bool ngin = (bool)nging;
+                    //电批OKNG
+                    if (okin || ngin)
+                    {
+                        //获取电批结果
+                        bool isSucced = management.ScrewDriver.GetData();
+                        LockResult lockResult = new LockResult();
+                        lockResult.LockTurns = (float)management.ScrewDriver.Truns;
+                        lockResult.LockTorque = (float)management.ScrewDriver.TorqueValue;
+                        lockResult.WaveDatas = management.ScrewDriver.WaveDatas;
+                        App.Current.Dispatcher.Invoke(() =>
+                        {
+                            _eventAggregator.GetEvent<LockFinishNotification>().Publish(lockResult);
+                        });
+                        //await _systemDatabaseService.RecordLockResultAsync(lockResult);
+                        await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
+
+                        Value = lockResult.LockTorque;
+                        await plc.WriteNodeAsync(addressConfig.Check_ScrewTorque.Address, false);
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
         #endregion
 
         public string Title { get; set; } = "扭力点检";
@@ -427,14 +621,14 @@ namespace TeamAAS_VP.ViewModels.Home
                 var res = FileHelper.ReadJsonFile<TorqueTest>(FilePath.TorqueCheckPath);
                 if (res != null)
                 {
-                    res.TorqueValue = torqueValue;
+                    res.TorqueValue = TorqueValue;
                 }
                 else
                 {
                     MessageBox.Show("还未示教,请先示教");
                 }
             }
-            catch (Exception ex)
+            catch (Exception)
             {
                 MessageBox.Show("还未示教,请先示教");
             }
@@ -454,5 +648,70 @@ namespace TeamAAS_VP.ViewModels.Home
                 Robot.EnterDebugMode = true;
             }
         }
+
+        private void ExecuteLoadedCommand()
+        {
+            var res = FileHelper.ReadJsonFile<TorqueProduceModel>(FilePath.TorqueCheckPath);
+            this.Points = res.TorquePoints;
+            this.TorqueValue = res.TorqueValue;
+        }
+
+        #region 添加点位与删除点位
+
+        /// <summary>
+        /// 增加点位
+        /// </summary>
+        private void ExecuteAddPointCommand()
+        {
+            //添加点位
+            Points.Add(new PlcPoint_Torque()
+            {
+                Number = Points.Count + 1,
+            });
+        }
+
+        /// <summary>
+        /// 移除点位
+        /// </summary>
+        private void ExecuteDeletePointCommand()
+        {
+            if (SelectedPoint == null)
+            {
+                return;
+            }
+            // 确认删除
+            if (MessageBox.Show(Lang.确认要删除选中的点位吗, Lang.删除点位, MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
+            {
+                return;
+            }
+            int removedIndex = Points.IndexOf(SelectedPoint);
+            Points.Remove(SelectedPoint);
+            //重新编号
+            for (int i = 0; i < Points.Count; i++)
+            {
+                Points[i].Number = i + 1;
+            }
+            // adjust selection
+            if (Points.Count > 0)
+            {
+                int newIndex = Math.Min(removedIndex, Points.Count - 1);
+                SelectedPointInDataGrid = Points[newIndex];
+            }
+            else
+            {
+                SelectedPointInDataGrid = null;
+            }
+        }
+        #endregion
+
+        private void ExecuteSavePointsCommand()
+        {
+            AllProductParameter.TorqueValue = this.TorqueValue;
+            AllProductParameter.TorquePoints = Points;
+
+            FileHelper.WriteJsonFile(AllProductParameter, FilePath.TorqueCheckPath);
+            MessageBox.Show("参数保存成功");
+        }
+
     }
 }

+ 262 - 46
TeamAAS-VM/Views/Home/TorqueCheck.xaml

@@ -15,12 +15,14 @@
              xmlns:valRules="clr-namespace:TeamAAS_VP.Identity"
              xmlns:validationRule="clr-namespace:TeamAAS_VP.ValidationRules"
              xmlns:ext="clr-namespace:TeamAAS_VP.Extension"
+             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
              xmlns:lex="http://wpflocalizeextension.codeplex.com"
              xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Home"
              lex:LocalizeDictionary.DesignCulture="zh-CN"
              lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
              lex:ResxLocalizationProvider.DefaultDictionary="Lang"
              d:Background="White"
+             AllowDrop="True"
              d:DataContext="{d:DesignInstance Type=vm:TorqueCheckViewModel}"
              prism:ViewModelLocator.AutoWireViewModel="True"
              FontFamily="{DynamicResource DefaultFont}">
@@ -47,13 +49,17 @@
         </Setter.Value>
     </Setter>-->
             <Setter Property="WindowStyle"
-                    Value="None" />
+                    Value="SingleBorderWindow" />
+            <Setter Property="ResizeMode"
+                    Value="NoResize" />
+            <Setter Property="SizeToContent"
+                    Value="Manual" />
             <Setter Property="AllowDrop"
                     Value="True" />
             <Setter Property="BorderThickness"
                     Value="0" />
             <Setter Property="ShowInTaskbar"
-                    Value="False" />
+                    Value="True" />
             <Setter Property="SizeToContent"
                     Value="WidthAndHeight" />
             <Setter Property="WindowState"
@@ -77,11 +83,212 @@
             <materialDesign:DrawerHost.LeftDrawerContent>
                 <Grid Width="auto">
                     <Grid.RowDefinitions>
-                        <RowDefinition Height="*" />
-                        <RowDefinition Height="*" />
-                        <RowDefinition Height="*" />
+                        <RowDefinition Height="auto" />
+                        <RowDefinition Height="auto" />
+                        <RowDefinition Height="auto" />
                     </Grid.RowDefinitions>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="auto" />
+                        <ColumnDefinition Width="auto" />
+                    </Grid.ColumnDefinitions>
+
+                    <!--点位列表操作按钮面板-->
+                    <StackPanel Grid.Row="2"
+                                Orientation="Horizontal">
+                        <!--<Button Content="{lex:Loc 添加点}"
+                                Margin="5,2"
+                                MinWidth="80"
+                                materialDesign:ButtonAssist.CornerRadius="5"
+                                Command="{Binding AddPointCommand}" />
+                        <Button Content="{lex:Loc 删除点}"
+                                Margin="5,2"
+                                MinWidth="80"
+                                materialDesign:ButtonAssist.CornerRadius="5"
+                                Command="{Binding DeletePointCommand}" />-->
+                        <Button Content="{lex:Loc 保存}"
+                                Margin="20"
+                                MinWidth="100"
+                                materialDesign:ButtonAssist.CornerRadius="5"
+                                Command="{Binding SavePointsCommand}" />
+                    </StackPanel>
+
+                    <!--    参数区      -->
+                    <DataGrid x:Name="dgPoints"
+                              Grid.Column="0"
+                              Grid.Row="0"
+                              Grid.RowSpan="2"
+                              AutoGenerateColumns="False"
+                              CanUserAddRows="False"
+                              CanUserDeleteRows="False"
+                              ColumnWidth="*"
+                              SelectionUnit="FullRow"
+                              SelectionMode="Single"
+                              SelectedItem="{Binding SelectedPointInDataGrid,Mode=TwoWay}"
+                              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"
+                                                IsReadOnly="True"
+                                                Binding="{Binding Label, Mode=TwoWay}" />
+                            <!--X 坐标-->
+                            <DataGridTemplateColumn Header="X位置"
+                                                    MinWidth="60"
+                                                    Width="Auto">
+                                <DataGridTemplateColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding X_Position, StringFormat={}{0:F3}}"
+                                                   HorizontalAlignment="Center"
+                                                   VerticalAlignment="Center" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellTemplate>
+                                <DataGridTemplateColumn.CellEditingTemplate>
+                                    <DataTemplate>
+                                        <mah:NumericUpDown Value="{Binding X_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                           Minimum="-200.000"
+                                                           Maximum="500.000"
+                                                           Interval="0.1"
+                                                           StringFormat="F3"
+                                                           HorizontalAlignment="Stretch"
+                                                           VerticalAlignment="Center"
+                                                           Margin="0"
+                                                           Padding="2" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellEditingTemplate>
+                            </DataGridTemplateColumn>
+
+                            <!--Y 坐标-->
+                            <DataGridTemplateColumn Header="{lex:Loc Y位置}"
+                                                    MinWidth="60"
+                                                    Width="Auto">
+                                <DataGridTemplateColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding Y_Position, StringFormat={}{0:F3}}"
+                                                   HorizontalAlignment="Center"
+                                                   VerticalAlignment="Center" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellTemplate>
+                                <DataGridTemplateColumn.CellEditingTemplate>
+                                    <DataTemplate>
+                                        <mah:NumericUpDown Value="{Binding Y_Position, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                           Minimum="-200.000"
+                                                           Maximum="500.000"
+                                                           Interval="0.1"
+                                                           StringFormat="F3"
+                                                           HorizontalAlignment="Stretch"
+                                                           VerticalAlignment="Center"
+                                                           Margin="0"
+                                                           Padding="2" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellEditingTemplate>
+                            </DataGridTemplateColumn>
+
+                            <!--Z 起点坐标-->
+                            <DataGridTemplateColumn Header="{lex:Loc Z起点位置}"
+                                                    MinWidth="60"
+                                                    Width="Auto">
+                                <DataGridTemplateColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding Z_Position_Start, StringFormat={}{0:F3}}"
+                                                   HorizontalAlignment="Center"
+                                                   VerticalAlignment="Center" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellTemplate>
+                                <DataGridTemplateColumn.CellEditingTemplate>
+                                    <DataTemplate>
+                                        <mah:NumericUpDown Value="{Binding Z_Position_Start, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                           Minimum="-200.000"
+                                                           Maximum="500.000"
+                                                           Interval="0.1"
+                                                           StringFormat="F3"
+                                                           HorizontalAlignment="Stretch"
+                                                           VerticalAlignment="Center"
+                                                           Margin="0"
+                                                           Padding="2" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellEditingTemplate>
+                            </DataGridTemplateColumn>
+
+                            <!--Z 终点坐标-->
+                            <DataGridTemplateColumn Header="{lex:Loc Z终点位置}"
+                                                    MinWidth="60"
+                                                    Width="Auto">
+                                <DataGridTemplateColumn.CellTemplate>
+                                    <DataTemplate>
+                                        <TextBlock Text="{Binding Z_Position_Stop, StringFormat={}{0:F3}}"
+                                                   HorizontalAlignment="Center"
+                                                   VerticalAlignment="Center" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellTemplate>
+                                <DataGridTemplateColumn.CellEditingTemplate>
+                                    <DataTemplate>
+                                        <mah:NumericUpDown Value="{Binding Z_Position_Stop, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
+                                                           Minimum="-200.000"
+                                                           Maximum="0"
+                                                           Interval="0.1"
+                                                           StringFormat="F3"
+                                                           HorizontalAlignment="Stretch"
+                                                           VerticalAlignment="Center"
+                                                           Margin="0"
+                                                           Padding="2" />
+                                    </DataTemplate>
+                                </DataGridTemplateColumn.CellEditingTemplate>
+                            </DataGridTemplateColumn>
+                        </DataGrid.Columns>
+                    </DataGrid>
+
+                    <!--   示教区    -->
                     <StackPanel Orientation="Horizontal"
+                                Grid.Column="1"
                                 HorizontalAlignment="Center"
                                 VerticalAlignment="Center"
                                 Margin="5">
@@ -99,7 +306,8 @@
                                 CommandParameter="False" />
                     </StackPanel>
 
-                    <Grid Grid.Row="1">
+                    <Grid Grid.Row="1"
+                          Grid.Column="1" >
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
                             <ColumnDefinition Width="auto" />
@@ -206,11 +414,13 @@
                         </Button>
                     </Grid>
 
-                    <Grid Grid.Row="2">
+                    <Grid Grid.Row="2"
+                          Grid.Column="1">
                         <Grid.RowDefinitions>
                             <RowDefinition />
                             <RowDefinition />
                             <RowDefinition />
+                            <RowDefinition />
                         </Grid.RowDefinitions>
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition />
@@ -227,34 +437,38 @@
                                 </MultiBinding>
                             </TextBlock.Text>
                         </TextBlock>
-
-                        <TextBlock Grid.Row="1"
-                                   Grid.Column="0"
-                                   Text="{lex:Loc 步进距离,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}"
-                                   Margin="10"
-                                   VerticalAlignment="Center"
-                                   HorizontalAlignment="Right" />
-                        <uControl:myNumericUpDowm x:Name="txtDistance"
-                                                  Grid.Row="1"
-                                                  Grid.Column="1"
-                                                  MinWidth="100"
-                                                  Value="{Binding DataContext.Distance,RelativeSource={RelativeSource AncestorType={x:Type UserControl}},Mode=TwoWay}"
-                                                  Interval="0.1"
-                                                  Minimum="0"
-                                                  Maximum="100"
-                                                  StringFormat="{}{0:N3} mm"
-                                                  Margin="10"
-                                                  materialDesign:HintAssist.Hint="{lex:Loc 步进距离}" />
-
-
-                        <Button Grid.Row="2"
-                                Grid.ColumnSpan="2"
-                                Content="{lex:Loc 示教}"
-                                Margin="0,10"
-                                HorizontalAlignment="Center"
-                                materialDesign:ButtonAssist.CornerRadius="10"
-                                Style="{StaticResource MaterialDesignRaisedDarkButton}"
-                                Command="{Binding TechPointCommand}" />
+                        <StackPanel Orientation="Horizontal"
+                                    Margin="10,3"
+                                    HorizontalAlignment="Stretch"
+                                    Grid.Row="2"
+                                    Grid.ColumnSpan="2">
+                            <TextBlock Text="{lex:Loc 步进距离,Converter={StaticResource StringFormatConverter},ConverterParameter='{}{0}: '}"
+                                       Margin="10"
+                                       VerticalAlignment="Center"
+                                       HorizontalAlignment="Center" />
+                            <uControl:myNumericUpDowm x:Name="txtDistance"
+                                                      MinWidth="100"
+                                                      Value="{Binding DataContext.Distance,RelativeSource={RelativeSource AncestorType={x:Type UserControl}},Mode=TwoWay}"
+                                                      Interval="0.1"
+                                                      Minimum="0"
+                                                      Maximum="100"
+                                                      StringFormat="{}{0:N3} mm"
+                                                      Margin="10"
+                                                      materialDesign:HintAssist.Hint="{lex:Loc 步进距离}" />
+                        </StackPanel>
+                        <StackPanel Orientation="Horizontal"
+                                    Margin="10,3"
+                                    HorizontalAlignment="Center"
+                                    Grid.Row="3"
+                                    Grid.ColumnSpan="2">
+                            <Button Content="{lex:Loc 示教}"
+                                    Margin="0,10"
+                                    HorizontalAlignment="Right"
+                                    Width="100"
+                                    materialDesign:ButtonAssist.CornerRadius="10"
+                                    Style="{StaticResource MaterialDesignRaisedDarkButton}"
+                                    Command="{Binding TechPointCommand}" />
+                        </StackPanel>
                     </Grid>
                 </Grid>
             </materialDesign:DrawerHost.LeftDrawerContent>
@@ -262,10 +476,10 @@
             <Grid Grid.Column="1">
                 <Grid.RowDefinitions>
                     <RowDefinition Height="auto" />
-                    <RowDefinition />
+                    <RowDefinition Height="auto"/>
                     <RowDefinition />
                     <RowDefinition Height="auto" />
-                    <RowDefinition />
+                    <RowDefinition/>
                     <RowDefinition Height="auto" />
                 </Grid.RowDefinitions>
                 <ToggleButton HorizontalAlignment="Left"
@@ -285,13 +499,13 @@
                     <TextBlock Text="{lex:Loc 扭力阈值}"
                                VerticalAlignment="Center"
                                Margin="5,2" />
-                    <TextBox Text="{Binding torqueValue}"
+                    <TextBox Text="{Binding TorqueValue}"
                              VerticalAlignment="Center"
                              HorizontalAlignment="Center"
-                             Width="80"
+                             Width="35"
                              Margin="5,2" />
                     <Button Content="{lex:Loc 修改}"
-                            Margin="15,2"
+                            Margin="5,2"
                             HorizontalAlignment="Center"
                             materialDesign:ButtonAssist.CornerRadius="10"
                             Style="{StaticResource MaterialDesignRaisedDarkButton}"
@@ -329,12 +543,13 @@
                 </Grid>
 
                 <Button Content="{lex:Loc 执行}"
+                        Grid.RowSpan="2"
                         VerticalContentAlignment="Center"
                         materialDesign:ButtonAssist.CornerRadius="10"
                         Style="{StaticResource MaterialDesignRaisedDarkButton}"
                         Command="{Binding WorkCommand}"
-                        Margin="10,5"
-                        Grid.Row="3"/>
+                        Margin="15,5"
+                        Grid.Row="3" />
 
                 <TextBlock Text="{Binding Result}"
                            HorizontalAlignment="Center"
@@ -344,21 +559,22 @@
                            Foreground="{Binding FontColor}" />
 
                 <StackPanel Orientation="Horizontal"
-                            Margin="10,3"
-                            HorizontalAlignment="Right"
+                            
+                            Margin="5"
+                            HorizontalAlignment="Center"
                             Grid.Row="5">
                     <Button Content="{lex:Loc 确定}"
                             VerticalContentAlignment="Center"
                             materialDesign:ButtonAssist.CornerRadius="10"
                             Style="{StaticResource MaterialDesignRaisedDarkButton}"
                             Command="{Binding ConfirmCommand}"
-                            Margin="10,3" />
+                            Margin="5" />
                     <Button Content="{lex:Loc 取消}"
                             VerticalContentAlignment="Center"
                             materialDesign:ButtonAssist.CornerRadius="10"
                             Style="{StaticResource MaterialDesignRaisedDarkButton}"
                             Command="{Binding CancelCommand}"
-                            Margin="10,3" />
+                            Margin="5" />
                 </StackPanel>
 
             </Grid>

+ 1 - 0
TeamAAS-VM/Views/Home/TorqueCheck.xaml.cs

@@ -24,5 +24,6 @@ namespace TeamAAS_VP.Views.Home
         {
             InitializeComponent();
         }
+
     }
 }

+ 1 - 1
TeamAAS-VM/Views/HomeView.xaml

@@ -328,7 +328,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" />

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

@@ -127,5 +127,6 @@ namespace TeamAAS_VP.Views.Product
                 }
             }
         }
+
     }
 }