KWD il y a 3 mois
Parent
commit
03f8ea26cd

+ 132 - 26
TeamAAS-VM/Core/Management.cs

@@ -1223,7 +1223,23 @@ namespace TeamAAS_VP.Core
                 monitorNodeIds.Add(string.Format(addressConfig.In_MesCheck.Address, i));
             }
             //订阅PLC地址变化
+            //plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
+
             plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
+
+            // 2. 监听重连事件,重连成功后自动重新订阅
+            plc.ConnectChangedEvent -= Plc_ConnectChanged; // 防止重复注册
+            plc.ConnectChangedEvent += Plc_ConnectChanged;
+
+            // 定义重连处理方法(写在同一个类里即可)
+            void Plc_ConnectChanged(object sender, bool isConnected)
+            {
+                if (isConnected)
+                {
+                    // 重连成功后,重新订阅节点
+                    plc.SubscribeNodes("AutoSensor", monitorNodeIds, PlcCommandTrigger, OpcUaSubscriptionMode.CustomPolling);
+                }
+            }
         }
 
         /// <summary>
@@ -1261,8 +1277,8 @@ namespace TeamAAS_VP.Core
             {
                 foreach (var item in current.PickPoints)
                 {
-                    //await item.WriteToPlcAddress(addressConfig.Out_Pick, plc, item.Feeder);
-                    await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
+                    await item.WriteToPlcAddress(addressConfig.Out_Pick, plc, item.Feeder);
+                    //await item.WriteToPlcAddress(addressConfig.Out_Pick, plc);
                 }
             }
             if (current.SecPosCameraPoints != null && current.SecPosCameraPoints.Count > 0)
@@ -1398,13 +1414,19 @@ namespace TeamAAS_VP.Core
             {
                 if (tuple.key != "AutoSensor")
                 {
+                    SendTaskMessage("PLC指令错误", MessageLevel.Debug);
                     return;
                 }
 
                 var addressConfig = _configService.GetPlcAddresses();
 
                 var plc = _plcService.GetPlcByNumber(addressConfig.PlcNo) as OpcUaClientPLC;
-                if (plc == null || !plc.IsConnected) return;
+                if (plc == null || !plc.IsConnected)
+                {
+                    SendTaskMessage("plc为空", MessageLevel.Debug);
+                    return;
+                }
+
                 // 获取当前产品
                 var currentProduct = _productService.GetCurrentProduct();
                 if (currentProduct == null)
@@ -1676,10 +1698,21 @@ namespace TeamAAS_VP.Core
                                 {
                                     UpCameraPutResults[1] = new PointF((float)visionResult.X, (float)visionResult.Y);
                                 }
-                                else
+                                else if(systemConfig.WorkMode==2)
                                 {
                                     UpCameraPutResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
                                 }
+                                else if(systemConfig.WorkMode==3)
+                                {
+                                    if (cameraIndex <= 3)
+                                    {
+                                        UpCameraPutResults[1] = new PointF((float)visionResult.X, (float)visionResult.Y);
+                                    }
+                                    else
+                                    {
+                                        UpCameraPutResults[cameraIndex] = new PointF((float)visionResult.X, (float)visionResult.Y);
+                                    }
+                                }
                                 if (resultToMes.Contains($"Screw{cameraIndex}_Fail"))
                                 {
                                     resultToMes.Remove($"Screw{cameraIndex}_Fail");
@@ -2339,6 +2372,18 @@ namespace TeamAAS_VP.Core
                             {
                                 lastRes = true;
                             }
+                            if (dataToMes.Keys.Contains($"Torque{lockResult.Number}"))
+                            {
+                                dataToMes.Remove($"Torque{lockResult.Number}");
+                            }
+                            if (dataToMes.Keys.Contains($"Turn{lockResult.Number}"))
+                            {
+                                dataToMes.Remove($"Turn{lockResult.Number}");
+                            }
+                            if (dataToMes.Keys.Contains($"Pressure{lockResult.Number}"))
+                            {
+                                dataToMes.Remove($"Pressure{lockResult.Number}");
+                            }
                             lockResult.LockPassed = lastRes;
                             dataToMes.Add($"Torque{lockResult.Number}", $"{lockResult.LockTorque:F2}");
                             dataToMes.Add($"Turn{lockResult.Number}", $"{lockResult.LockTurns:F2}");
@@ -2392,7 +2437,7 @@ namespace TeamAAS_VP.Core
                             return;
                         }
                         if (state == 1)
-                        {
+                        {                           
                             SendTaskMessage(Lang.收到多相机坐标合并请求开始合并, MessageLevel.Debug);
                             //位置编号
                             Int16 positionIndex = plc.ReadNode<Int16>(addressConfig.In_ProductNum.Address);
@@ -2426,10 +2471,10 @@ namespace TeamAAS_VP.Core
                                     await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
                                     return;
                                 }
-                                //验证当前锁附点位与设置锁附点位的差值是否超限,超限则报警并停止流程
-                                //目前验证已OK 缺少切换按钮
-                                if (_configService.GetDeviceInfo().ScrewOverrun)
+                                if (_configService.GetDeviceInfo().EnableXY)
                                 {
+                                    //验证当前锁附点位与设置锁附点位的差值是否超限,超限则报警并停止流程
+                                    //目前验证已OK 缺少切换按钮
                                     try
                                     {
                                         var ScrewLimit = currentProduct.GlobalParamListCollection.FirstOrDefault((p) => p.Number == positionIndex - 1);
@@ -2476,32 +2521,82 @@ namespace TeamAAS_VP.Core
                                     point.X_Position = (float)worldPoint[0];
                                     point.Y_Position = (float)worldPoint[1];
                                     SendTaskMessage($"点:{i},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
-                                    if (_configService.GetDeviceInfo().ScrewOverrun)
+                                    try
                                     {
-                                        try
-                                        {
-                                            var ScrewLimit = currentProduct.GlobalParamListCollection.FirstOrDefault((p) => p.Number == positionIndex - 1);
-                                            //判断实际偏差与设置的点位差数是否偏差过大
-                                            float XOffsetPoint = Math.Abs(localPoint.X - (float)worldPoint[0]);
-                                            float YOffsetPoint = Math.Abs(localPoint.Y - (float)worldPoint[1]);
-                                            if ((XOffsetPoint >= float.Parse(ScrewLimit.Param1) && XOffsetPoint <= float.Parse(ScrewLimit.Param2)) ||
-                                                (YOffsetPoint >= float.Parse(ScrewLimit.Param3) && YOffsetPoint <= float.Parse(ScrewLimit.Param4)))
-                                            {
-                                                SendTaskMessage($"当前锁附点位{i}与设置锁附点位差值超限,X偏差:{XOffsetPoint},Y偏差{YOffsetPoint}", MessageLevel.Error);
-                                                await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
-                                                return;
-                                            }
-                                        }
-                                        catch (Exception ex)
+                                        var ScrewLimit = currentProduct.GlobalParamListCollection.FirstOrDefault((p) => p.Number == positionIndex - 1);
+                                        //判断实际偏差与设置的点位差数是否偏差过大
+                                        float XOffsetPoint = Math.Abs(localPoint.X - (float)worldPoint[0]);
+                                        float YOffsetPoint = Math.Abs(localPoint.Y - (float)worldPoint[1]);
+                                        if ((XOffsetPoint >= float.Parse(ScrewLimit.Param1) && XOffsetPoint <= float.Parse(ScrewLimit.Param2)) ||
+                                            (YOffsetPoint >= float.Parse(ScrewLimit.Param3) && YOffsetPoint <= float.Parse(ScrewLimit.Param4)))
                                         {
-                                            SendTaskMessage($"当前锁附点位与设置锁附点位差值超限:" + ex.Message, MessageLevel.Error);
+                                            SendTaskMessage($"当前锁附点位{i}与设置锁附点位差值超限,X偏差:{XOffsetPoint},Y偏差{YOffsetPoint}", MessageLevel.Error);
                                             await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
+                                            return;
                                         }
                                     }
+                                    catch (Exception ex)
+                                    {
+                                        SendTaskMessage($"当前锁附点位与设置锁附点位差值超限:" + ex.Message, MessageLevel.Error);
+                                        await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
+                                    }
                                     await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
                                 }
                                 await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)currentProduct.ScrewPoints.Count);
                             }
+                            //拍2打所有
+                            else if (systemConfig.WorkMode == 3)
+                            {
+                                if (positionIndex <= 3)
+                                {
+                                    List<PlcPoint> plcPoints = new List<PlcPoint>();
+                                    foreach (var item in currentProduct.ScrewPoints)
+                                    {
+                                        if (item.IsUse)
+                                        {
+                                            plcPoints.Add(item);
+                                        }
+                                    }
+                                    var point = plcPoints[positionIndex - 1];
+                                    if (point == null)
+                                    {
+                                        SendTaskMessage($"点:{positionIndex}不存在", MessageLevel.Info);
+                                        await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)2);
+                                        return;
+                                    }
+                                    point = point.Clone();
+                                    point.X_Position = UpCameraPutResults[1].X + DowmCameraResults[1].X;
+                                    point.Y_Position = UpCameraPutResults[1].Y + DowmCameraResults[1].Y;
+                                    SendTaskMessage($"点:{positionIndex},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
+                                    await point.WriteToPlcAddress(addressConfig.Out_Screw, plc, positionIndex);
+                                }
+                                else
+                                {
+                                    //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
+                                    PointF worldP1 = new PointF(UpCameraPutResults[4].X, UpCameraPutResults[4].Y);
+                                    PointF worldP2 = new PointF(UpCameraPutResults[5].X, UpCameraPutResults[5].Y);
+                                    PointF localP1 = new PointF(currentProduct.ScrewCameraLocalPos1.X_Position, currentProduct.ScrewCameraLocalPos1.Y_Position);
+                                    PointF localP2 = new PointF(currentProduct.ScrewCameraLocalPos2.X_Position, currentProduct.ScrewCameraLocalPos2.Y_Position);
+                                    CoordinateTransformer local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
+
+                                    for (int i = 0; i < currentProduct.ScrewPoints.Count; i++)
+                                    {
+                                        var localPoint = new PointF(currentProduct.ScrewPoints[i].X_Position + currentProduct.ScrewPoints[i].X_Offset,
+                                            currentProduct.ScrewPoints[i].Y_Position + currentProduct.ScrewPoints[i].Y_Offset);
+                                        var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
+                                        var point = currentProduct.ScrewPoints[i].Clone();
+
+                                        //锁付点位在Local中已经加了偏移,这里写回PLC时需要将偏移清零,否则写入PLC端时会重复计算偏移
+                                        point.X_Offset = 0;
+                                        point.Y_Offset = 0;
+                                        point.X_Position = (float)worldPoint[0];
+                                        point.Y_Position = (float)worldPoint[1];
+                                        SendTaskMessage($"点:{i},{point.X_Position:F3},{point.Y_Position:F4}", MessageLevel.Info);
+                                        await point.WriteToPlcAddress(addressConfig.Out_Screw, plc);
+                                    }
+                                    await plc.WriteNodeAsync(addressConfig.Out_WorkNum.Address, (Int16)currentProduct.ScrewPoints.Count);
+                                }                              
+                            }
                             await plc.WriteNodeAsync(addressConfig.Out_CameraDone.Address, (Int16)1);
                         }
                         else
@@ -2729,6 +2824,15 @@ namespace TeamAAS_VP.Core
                         {
                             if (tuple.value is Int16 state)
                             {
+
+                                //var oldState = _LastMesCheck[i];
+                                //_LastMesCheck[i] = state;
+                                //SendTaskMessage($"站点{i},收到PLC状态为:{state},旧状态为:{oldState}",MessageLevel.Info);
+                                //if (oldState == state)
+                                //{
+                                //    return;
+                                //}
+
                                 if (_LastMesCheck[i] != state)
                                 {
                                     _LastMesCheck[i] = state;
@@ -3638,7 +3742,8 @@ namespace TeamAAS_VP.Core
                                                 return;
                                             }
                                             // 后面还有一些判断条件也需跟当前AE对接
-                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+
+
                                         }
 
                                         LogHelper.WriteLogMes($"【mes结束QUERY】");
@@ -3664,6 +3769,7 @@ namespace TeamAAS_VP.Core
                                     await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)0);
                                     return;
                                 }
+                               // _LastMesCheck[i] = 0;
                             }
                         }
                     }

+ 1 - 0
TeamAAS-VM/Core/PLCs/OPCuaClientPLC.cs

@@ -83,6 +83,7 @@ namespace TeamAAS_VP.Core.PLCs
         /// 在未显式传入订阅选项时,`SubscribeNodes` 将使用该模式决定采用 OPC UA 原生订阅还是客户端轮询订阅。
         /// 默认值为 <see cref="OpcUaSubscriptionMode.Native"/>。
         /// </summary>
+        //public OpcUaSubscriptionMode DefaultSubscriptionMode { get; set; } = OpcUaSubscriptionMode.CustomPolling;
         public OpcUaSubscriptionMode DefaultSubscriptionMode { get; set; } = OpcUaSubscriptionMode.Native;
 
         /// <summary>

+ 8 - 0
TeamAAS-VM/Models/DeviceInfo.cs

@@ -51,6 +51,12 @@ namespace TeamAAS_VP.Models
         /// </summary>
         public bool EnableMES { get => _enableMes; set => SetProperty(ref _enableMes, value); }
 
+        private bool _enableXY;
+        /// <summary>
+        /// 是否启用锁螺丝XY超限 通讯功能,默认不启用
+        /// </summary>
+        public bool EnableXY { get => _enableXY; set => SetProperty(ref _enableXY, value); }
+
         private string _mesUrl;
         /// <summary>
         /// URL
@@ -133,6 +139,7 @@ namespace TeamAAS_VP.Models
             LogUrl = string.Empty;
             ApiKey = string.Empty;
             EnableMES = false;
+            EnableXY = false;
             SaveCsvPPID = true;
         }
 
@@ -150,6 +157,7 @@ namespace TeamAAS_VP.Models
                 comp = this.comp,
                 MesUrl = this.MesUrl,
                 EnableMES = this.EnableMES,
+                EnableXY = this.EnableXY,
                 SaveCsv = this.SaveCsv,
                 ScrewOverrun=this.ScrewOverrun,
                 SaveCsvPath = this.SaveCsvPath,

+ 1 - 1
TeamAAS-VM/Models/SystemConfiguration.cs

@@ -99,7 +99,7 @@ namespace TeamAAS_VP.Models
 
         private Int16 _WorkMode = 0;
         /// <summary>
-        /// 工作模式 =1 拍1打1 =2 拍1打所有
+        /// 工作模式 =1 拍1打1 =2 拍1打所有 =3先拍1打1打3颗再拍2打所有
         /// </summary>
         public Int16 WorkMode
         {

+ 84 - 84
TeamAAS-VM/Services/ConfigService.cs

@@ -71,7 +71,7 @@ namespace TeamAAS_VP.Services
         // 锟斤拷源锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷
         private ObservableCollection<LightControllerConfig> LightControllers { get; set; }
 
-        // Device info - 鏀�寔澶氳�澶
+        // Device info - 鏀�寔澶氳�澶?
         private List<DeviceInfo> _deviceInfoList;
         public CTQ_Data CtqData { get; set; }
 
@@ -101,7 +101,7 @@ namespace TeamAAS_VP.Services
 
         /// <summary>
         /// 锟斤拷始锟斤拷一锟斤拷锟铰碉拷 <see cref="ConfigService"/> 实锟斤拷锟斤拷
-        /// 锟斤拷锟届函锟斤拷锟斤拷锟斤拷锟皆讹拷锟斤拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷锟斤拷锟斤拷锟节癸拷锟斤拷锟节硷拷锟斤拷锟I/O 锟斤拷锟斤拷锟斤拷锟斤拷锟缴碉拷锟斤拷 <see cref="LoadAll"/> 锟斤拷 <see cref="LoadAllAsync"/> 锟斤拷式锟斤拷锟截★拷
+        /// 锟斤拷锟届函锟斤拷锟斤拷锟斤拷锟皆讹拷锟斤拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷锟斤拷锟斤拷锟节癸拷锟斤拷锟节硷拷锟斤拷锟?I/O 锟斤拷锟斤拷锟斤拷锟斤拷锟缴碉拷锟斤拷 <see cref="LoadAll"/> 锟斤拷 <see cref="LoadAllAsync"/> 锟斤拷式锟斤拷锟截★拷
         /// </summary>
         public ConfigService()
         {
@@ -117,7 +117,7 @@ namespace TeamAAS_VP.Services
         {
             lock (_sync)
             {
-                // 锟斤拷取锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷募锟斤拷锟斤拷锟斤拷冢锟斤拷虮3锟DeviceConfig 默锟斤拷值
+                // 锟斤拷取锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷募锟斤拷锟斤拷锟斤拷冢锟斤拷虮3锟?DeviceConfig 默锟斤拷值
                 if (File.Exists(ConfigPaths.CamerasConfigurationPath))
                     Cameras = FileHelper.ReadJsonFile<ObservableCollection<CameraInfo>>(ConfigPaths.CamerasConfigurationPath);
                 else
@@ -211,7 +211,7 @@ namespace TeamAAS_VP.Services
                     FileHelper.WriteJsonFile(_screwDriverConfig, ConfigPaths.ScrewDriverConfigurationPath);
                 }
 
-                // load device info list (鏀�寔澶氳�澶�)
+                // load device info list (鏀�寔澶氳�澶?
                 if (File.Exists(ConfigPaths.DeviceInfoConfigurationPath))
                 {
                     try
@@ -263,7 +263,7 @@ namespace TeamAAS_VP.Services
 
         /// <summary>
         /// 锟斤拷锟节达拷锟叫碉拷锟斤拷锟斤拷锟斤拷锟斤拷写锟截碉拷锟斤拷应锟斤拷锟斤拷锟侥硷拷锟斤拷
-        /// 锟竭程帮拷全锟斤拷锟斤拷锟斤拷锟节诧拷锟斤拷写锟斤拷锟斤拷锟绞癸拷锟<see cref="_sync"/> 锟斤拷锟斤拷锟斤拷
+        /// 锟竭程帮拷全锟斤拷锟斤拷锟斤拷锟节诧拷锟斤拷写锟斤拷锟斤拷锟绞癸拷锟?<see cref="_sync"/> 锟斤拷锟斤拷锟斤拷
         /// </summary>
         public void SaveAll()
         {
@@ -285,7 +285,7 @@ namespace TeamAAS_VP.Services
                     FileHelper.WriteJsonFile(ScrewFeeders, ConfigPaths.ScrewFeedersConfigurationPath);
                 // save plc addresses
                 //FileHelper.WriteJsonFile(PlcAddressConfig, "..//Config//PlcAddressConfiguration.cfg");
-                // save device info list (鏀�寔澶氳�澶�)
+                // save device info list (鏀�寔澶氳�澶?
                 if (_deviceInfoList != null)
                     FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
                 // save card reader config
@@ -297,7 +297,7 @@ namespace TeamAAS_VP.Services
         /// <summary>
         /// 锟届步执锟斤拷 <see cref="SaveAll"/> 锟斤拷锟斤拷锟斤拷
         /// </summary>
-        /// <returns>锟斤拷示锟届步锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟�</returns>
+        /// <returns>锟斤拷示锟届步锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟?/returns>
         public Task SaveAllAsync()
         {
             return Task.Run(() => SaveAll());
@@ -305,19 +305,19 @@ namespace TeamAAS_VP.Services
 
         #region Cameras
         /// <summary>
-        /// 锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷玫锟街伙拷锟斤拷锟斤拷稀锟
+        /// 锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷玫锟街伙拷锟斤拷锟斤拷稀锟?
         /// 锟竭程帮拷全锟斤拷锟斤拷锟节诧拷锟斤拷锟斤拷锟皆憋拷证锟斤拷锟斤拷锟斤拷取锟斤拷一锟斤拷锟皆★拷
         /// </summary>
-        /// <returns>锟斤拷锟斤拷锟斤拷玫锟街伙拷锟斤拷锟斤拷稀锟�</returns>
+        /// <returns>锟斤拷锟斤拷锟斤拷玫锟街伙拷锟斤拷锟斤拷稀锟?/returns>
         public IReadOnlyCollection<CameraInfo> GetAllCameras()
         {
             lock (_sync) { return Cameras.ToList().AsReadOnly(); }
         }
 
         /// <summary>
-        /// 锟斤拷锟捷憋拷识锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟较�拷锟
+        /// 锟斤拷锟捷憋拷识锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟较�拷锟?
         /// </summary>
-        /// <param name="id">锟斤拷锟斤拷锟Guid 锟斤拷识锟斤拷</param>
+        /// <param name="id">锟斤拷锟斤拷锟?Guid 锟斤拷识锟斤拷</param>
         /// <returns>锟揭碉拷锟津返回讹拷应锟斤拷 <see cref="CameraInfo"/>锟斤拷锟斤拷锟津返伙拷 <c>null</c>锟斤拷</returns>
         public CameraInfo GetCamera(Guid id)
         {
@@ -327,11 +327,11 @@ namespace TeamAAS_VP.Services
         /// <summary>
         /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟矫★拷
         /// - 锟斤拷锟斤拷锟斤拷 <paramref name="camera"/> 为 <c>null</c> 锟斤拷锟斤拷 <c>null</c>锟斤拷
-        /// - 锟斤拷 Id 锟窖达拷锟斤拷锟斤拷锟芥换锟斤拷锟斤拷锟斤拷追锟接诧拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 CameraNo 锟斤拷拧锟
+        /// - 锟斤拷 Id 锟窖达拷锟斤拷锟斤拷锟芥换锟斤拷锟斤拷锟斤拷追锟接诧拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 CameraNo 锟斤拷拧锟?
         /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷峤�拷锟斤拷锟斤拷锟较持久伙拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷
         /// </summary>
         /// <param name="camera">要锟斤拷锟接伙拷锟斤拷碌锟斤拷锟斤拷锟斤拷锟矫★拷</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="CameraInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="CameraInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public CameraInfo AddOrUpdateCamera(CameraInfo camera)
         {
             if (camera == null) return null;
@@ -354,10 +354,10 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟捷憋拷识锟狡筹拷锟斤拷锟斤拷锟斤拷貌锟斤拷锟斤拷卤锟斤拷剩锟斤拷锟斤拷锟斤拷锟CameraNo锟斤拷
+        /// 锟斤拷锟捷憋拷识锟狡筹拷锟斤拷锟斤拷锟斤拷貌锟斤拷锟斤拷卤锟斤拷剩锟斤拷锟斤拷锟斤拷锟?CameraNo锟斤拷
         /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷峤�拷锟斤拷锟斤拷锟较持久伙拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷
         /// </summary>
-        /// <param name="id">要锟狡筹拷锟斤拷锟斤拷锟Guid锟斤拷</param>
+        /// <param name="id">要锟狡筹拷锟斤拷锟斤拷锟?Guid锟斤拷</param>
         /// <returns>锟斤拷锟揭碉拷锟斤拷锟缴癸拷锟狡筹拷锟斤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
         public bool RemoveCamera(Guid id)
         {
@@ -366,7 +366,7 @@ namespace TeamAAS_VP.Services
             {
                 var exist = Cameras.FirstOrDefault(c => c.Id == id);
                 if (exist != null) result = Cameras.Remove(exist);
-                //锟斤拷锟铰憋拷锟
+                //锟斤拷锟铰憋拷锟?
                 int no = 1;
                 //锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟紺ameraNo锟斤拷锟斤拷
                 var sortedCameras = Cameras.OrderBy(c => c.CameraNo).ToList();
@@ -386,18 +386,18 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟斤拷欠锟斤拷锟斤拷指锟斤拷 Id 锟斤拷锟斤拷锟斤拷锟斤拷谩锟
+        /// 锟斤拷锟斤拷欠锟斤拷锟斤拷指锟斤拷 Id 锟斤拷锟斤拷锟斤拷锟斤拷谩锟?
         /// </summary>
-        /// <param name="id">锟斤拷锟斤拷锟Guid锟斤拷</param>
+        /// <param name="id">锟斤拷锟斤拷锟?Guid锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
         public bool ContainsCamera(Guid id) { lock (_sync) { return Cameras.Any(c => c.Id == id); } }
         #endregion
 
         #region DeviceInfo
         /// <summary>
-        /// 鑾峰彇鎵€鏈夎�澶囦俊鎭�厤缃�垪琛
+        /// 鑾峰彇鎵€鏈夎�澶囦俊鎭�厤缃�垪琛?
         /// </summary>
-        /// <returns>璁惧�淇℃伅鍒楄〃鐨勫彧璇婚泦鍚�</returns>
+        /// <returns>璁惧�淇℃伅鍒楄〃鐨勫彧璇婚泦鍚?/returns>
         public IReadOnlyCollection<DeviceInfo> GetAllDeviceInfos()
         {
             lock (_sync)
@@ -460,7 +460,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 娣诲姞鎴栨洿鏂拌�澶囦俊鎭
+        /// 娣诲姞鎴栨洿鏂拌�澶囦俊鎭?
         /// </summary>
         /// <param name="deviceInfo">璁惧�淇℃伅瀵硅薄</param>
         public void SaveDeviceInfo(DeviceInfo deviceInfo)
@@ -484,17 +484,17 @@ namespace TeamAAS_VP.Services
                 }
                 else
                 {
-                    // 娣诲姞鏂拌�澶
+                    // 娣诲姞鏂拌�澶?
                     _deviceInfoList.Add(deviceInfo);
                 }
-                // 鎸夎�澶囩紪鍙锋帓搴
+                // 鎸夎�澶囩紪鍙锋帓搴?
                 _deviceInfoList = _deviceInfoList.OrderBy(d => d.DeviceNo).ToList();
                 FileHelper.WriteJsonFile(_deviceInfoList, ConfigPaths.DeviceInfoConfigurationPath);
             }
         }
 
         /// <summary>
-        /// 淇濆瓨鎵€鏈夎�澶囦俊鎭�垪琛
+        /// 淇濆瓨鎵€鏈夎�澶囦俊鎭�垪琛?
         /// </summary>
         /// <param name="deviceInfoList">璁惧�淇℃伅鍒楄〃</param>
         public void SaveAllDeviceInfos(IEnumerable<DeviceInfo> deviceInfoList)
@@ -508,7 +508,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 娣诲姞鏂拌�澶
+        /// 娣诲姞鏂拌�澶?
         /// </summary>
         /// <returns>鏂版坊鍔犵殑璁惧�</returns>
         public DeviceInfo AddDeviceInfo()
@@ -520,7 +520,7 @@ namespace TeamAAS_VP.Services
                     _deviceInfoList = new List<DeviceInfo>();
                 }
 
-                // 璁$畻鏂拌�澶囩紪鍙
+                // 璁$畻鏂拌�澶囩紪鍙?
                 int newDeviceNo = _deviceInfoList.Count > 0 ? _deviceInfoList.Max(d => d.DeviceNo) + 1 : 0;
                 var newDevice = new DeviceInfo { DeviceNo = newDeviceNo };
                 _deviceInfoList.Add(newDevice);
@@ -567,10 +567,10 @@ namespace TeamAAS_VP.Services
 
         /// <summary>
         /// 锟斤拷锟斤拷锟斤拷锟斤拷禄锟斤拷锟斤拷锟斤拷锟斤拷茫锟斤拷锟斤拷锟斤拷锟街久伙拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷
-        /// 锟斤拷锟斤拷时为锟斤拷锟斤拷锟剿凤拷锟斤拷锟斤拷锟斤拷锟斤拷 RobotNo 锟斤拷拧锟
+        /// 锟斤拷锟斤拷时为锟斤拷锟斤拷锟剿凤拷锟斤拷锟斤拷锟斤拷锟斤拷 RobotNo 锟斤拷拧锟?
         /// </summary>
-        /// <param name="robot">要锟斤拷锟接伙拷锟斤拷碌幕锟斤拷锟斤拷锟斤拷锟斤拷谩锟�</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="RobotInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <param name="robot">要锟斤拷锟接伙拷锟斤拷碌幕锟斤拷锟斤拷锟斤拷锟斤拷谩锟?/param>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="RobotInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public RobotInfo AddOrUpdateRobot(RobotInfo robot)
         {
             if (robot == null) return null;
@@ -595,7 +595,7 @@ namespace TeamAAS_VP.Services
 
         /// <summary>
         /// 锟斤拷锟捷憋拷识锟狡筹拷锟斤拷锟斤拷锟斤拷锟斤拷锟矫诧拷锟斤拷锟铰憋拷锟绞o拷锟斤拷锟斤拷锟剿★拷
-        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟
+        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟?
         /// </summary>
         /// <param name="id">要锟狡筹拷锟侥伙拷锟斤拷锟斤拷 Guid锟斤拷</param>
         /// <returns>锟狡筹拷锟缴癸拷锟斤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -607,7 +607,7 @@ namespace TeamAAS_VP.Services
                 var e = Robots.FirstOrDefault(r => r.Id == id);
                 if (e != null)
                     result = Robots.Remove(e);
-                //锟斤拷锟铰憋拷锟
+                //锟斤拷锟铰憋拷锟?
                 int no = 1;
                 //锟斤拷锟斤拷锟叫伙拷锟斤拷锟剿帮拷RobotNo锟斤拷锟斤拷
                 var sortedRobots = Robots.OrderBy(r => r.RobotNo).ToList();
@@ -627,7 +627,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟Id 锟侥伙拷锟斤拷锟斤拷锟斤拷锟矫★拷
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟?Id 锟侥伙拷锟斤拷锟斤拷锟斤拷锟矫★拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟剿碉拷 Guid锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -697,10 +697,10 @@ namespace TeamAAS_VP.Services
 
         /// <summary>
         /// 锟斤拷锟斤拷锟斤拷锟斤拷鹿锟斤拷锟斤拷锟斤拷锟斤拷茫锟斤拷锟斤拷锟斤拷锟街久伙拷锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷
-        /// 锟斤拷锟斤拷时为锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 FeederNo 锟斤拷拧锟
+        /// 锟斤拷锟斤拷时为锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷 FeederNo 锟斤拷拧锟?
         /// </summary>
-        /// <param name="feeder">要锟斤拷锟接伙拷锟斤拷碌墓锟斤拷锟斤拷锟斤拷锟斤拷谩锟�</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="FeederInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <param name="feeder">要锟斤拷锟接伙拷锟斤拷碌墓锟斤拷锟斤拷锟斤拷锟斤拷谩锟?/param>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="FeederInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public FeederInfo AddOrUpdateFeeder(FeederInfo feeder)
         {
             if (feeder == null) return null;
@@ -723,8 +723,8 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟捷憋拷识锟狡筹拷锟斤拷锟斤拷锟斤拷锟斤拷锟矫诧拷锟斤拷锟铰憋拷锟绞o拷喙╋拷锟斤拷锟斤拷锟
-        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟
+        /// 锟斤拷锟捷憋拷识锟狡筹拷锟斤拷锟斤拷锟斤拷锟斤拷锟矫诧拷锟斤拷锟铰憋拷锟绞o拷喙╋拷锟斤拷锟斤拷锟?
+        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟?
         /// </summary>
         /// <param name="id">要锟狡筹拷锟侥癸拷锟斤拷锟斤拷 Guid锟斤拷</param>
         /// <returns>锟狡筹拷锟缴癸拷锟斤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -735,7 +735,7 @@ namespace TeamAAS_VP.Services
             {
                 var e = Feeders.FirstOrDefault(f => f.Id == id);
                 if (e != null) result = Feeders.Remove(e);
-                //锟斤拷锟铰憋拷锟
+                //锟斤拷锟铰憋拷锟?
                 int no = 1;
                 //锟斤拷锟斤拷锟叫癸拷锟斤拷锟斤拷锟斤拷FeederNo锟斤拷锟斤拷
                 var sortedFeeders = Feeders.OrderBy(f => f.FeederNo).ToList();
@@ -756,7 +756,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟Id 锟侥癸拷锟斤拷锟斤拷锟斤拷锟矫★拷
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟?Id 锟侥癸拷锟斤拷锟斤拷锟斤拷锟矫★拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟斤拷 Guid锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -774,14 +774,14 @@ namespace TeamAAS_VP.Services
         /// 锟斤拷锟捷憋拷识锟斤拷取锟斤拷锟斤拷 PLC 锟斤拷锟矫★拷
         /// </summary>
         /// <param name="id">PLC 锟斤拷 Guid 锟斤拷识锟斤拷</param>
-        /// <returns>匹锟斤拷锟<see cref="PlcInfo"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <returns>匹锟斤拷锟?<see cref="PlcInfo"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public PlcInfo GetPlc(Guid id) { lock (_sync) { return Plcs.FirstOrDefault(p => p.Id == id); } }
 
         /// <summary>
-        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟PLC 锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷锟斤拷募锟斤拷锟斤拷锟斤拷锟绞憋拷锟斤拷锟斤拷锟斤拷锟� PlcNo 锟斤拷拧锟�
+        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟?PLC 锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷锟斤拷募锟斤拷锟斤拷锟斤拷锟绞憋拷锟斤拷锟斤拷锟斤拷锟?PlcNo 锟斤拷拧锟?
         /// </summary>
-        /// <param name="plc">要锟斤拷锟接伙拷锟斤拷碌锟PLC 锟斤拷锟矫★拷</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="PlcInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <param name="plc">要锟斤拷锟接伙拷锟斤拷碌锟?PLC 锟斤拷锟矫★拷</param>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="PlcInfo"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public PlcInfo AddOrUpdatePlc(PlcInfo plc)
         {
             if (plc == null) return null;
@@ -804,8 +804,8 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟捷憋拷识锟狡筹拷 PLC 锟斤拷锟矫诧拷锟斤拷锟铰憋拷锟绞o拷锟PLC锟斤拷
-        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟
+        /// 锟斤拷锟捷憋拷识锟狡筹拷 PLC 锟斤拷锟矫诧拷锟斤拷锟铰憋拷锟绞o拷锟?PLC锟斤拷
+        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟?
         /// </summary>
         /// <param name="id">要锟狡筹拷锟斤拷 PLC Guid锟斤拷</param>
         /// <returns>锟狡筹拷锟缴癸拷锟斤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -816,7 +816,7 @@ namespace TeamAAS_VP.Services
             {
                 var e = Plcs.FirstOrDefault(p => p.Id == id);
                 if (e != null) result = Plcs.Remove(e);
-                //锟斤拷锟铰憋拷锟
+                //锟斤拷锟铰憋拷锟?
                 int no = 1;
                 //锟斤拷锟斤拷锟斤拷PLC锟斤拷PlcNo锟斤拷锟斤拷
                 var sortedPlcs = Plcs.OrderBy(p => p.PlcNo).ToList();
@@ -837,7 +837,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟Id 锟斤拷 PLC 锟斤拷锟矫★拷
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟?Id 锟斤拷 PLC 锟斤拷锟矫★拷
         /// </summary>
         /// <param name="id">PLC 锟斤拷 Guid锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -846,13 +846,13 @@ namespace TeamAAS_VP.Services
 
         #region BgTcp
         /// <summary>
-        /// 锟斤拷取 BG TCP/IP 通锟斤拷锟斤拷锟矫o拷锟节达拷锟斤拷螅�锟斤拷锟轿null锟斤拷锟斤拷
+        /// 锟斤拷取 BG TCP/IP 通锟斤拷锟斤拷锟矫o拷锟节达拷锟斤拷螅�锟斤拷锟轿?null锟斤拷锟斤拷
         /// </summary>
         /// <returns>锟斤拷前锟斤拷 <see cref="BgTcpIP"/> 锟斤拷锟矫讹拷锟斤拷</returns>
         public BgTcpIP GetBgTcp() { lock (_sync) { return BgCommunicate; } }
 
         /// <summary>
-        /// 锟斤拷锟斤拷 BG TCP/IP 通锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷锟节达拷锟斤拷螅�锟斤拷锟斤拷远锟斤拷志没锟斤拷锟斤拷锟
+        /// 锟斤拷锟斤拷 BG TCP/IP 通锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷锟节达拷锟斤拷螅�锟斤拷锟斤拷远锟斤拷志没锟斤拷锟斤拷锟?
         /// 锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷 <see cref="SaveBgTcp"/>锟斤拷
         /// </summary>
         /// <param name="cfg">锟铰碉拷 <see cref="BgTcpIP"/> 锟斤拷锟矫讹拷锟斤拷</param>
@@ -866,13 +866,13 @@ namespace TeamAAS_VP.Services
 
         #region BgModbus
         /// <summary>
-        /// 锟斤拷取 BG Modbus TCP 通锟斤拷锟斤拷锟矫o拷锟节达拷锟斤拷螅�锟
+        /// 锟斤拷取 BG Modbus TCP 通锟斤拷锟斤拷锟矫o拷锟节达拷锟斤拷螅�锟?
         /// </summary>
         /// <returns>锟斤拷前锟斤拷 <see cref="BgModbusTcp"/> 锟斤拷锟矫讹拷锟斤拷</returns>
         public BgModbusTcp GetBgModbusTcp() { lock (_sync) { return BgModbusCommunicate; } }
 
         /// <summary>
-        /// 锟斤拷锟斤拷 BG Modbus TCP 通锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷锟节达拷锟斤拷螅�锟斤拷锟斤拷远锟斤拷志没锟斤拷锟斤拷锟
+        /// 锟斤拷锟斤拷 BG Modbus TCP 通锟斤拷锟斤拷锟矫o拷锟斤拷锟斤拷锟斤拷锟节达拷锟斤拷螅�锟斤拷锟斤拷远锟斤拷志没锟斤拷锟斤拷锟?
         /// </summary>
         /// <param name="cfg">锟铰碉拷 <see cref="BgModbusTcp"/> 锟斤拷锟矫讹拷锟斤拷</param>
         public void SetBgModbusTcp(BgModbusTcp cfg) { lock (_sync) { BgModbusCommunicate = cfg; } }
@@ -942,7 +942,7 @@ namespace TeamAAS_VP.Services
         /// <summary>
         /// 锟斤拷锟斤拷系统锟斤拷锟矫碉拷锟斤拷锟斤拷锟侥硷拷锟斤拷锟结覆锟斤拷锟斤拷锟斤拷锟侥硷拷锟斤拷锟斤拷
         /// </summary>
-        /// <param name="systemConfiguration">要锟斤拷锟斤拷锟较低筹拷锟斤拷枚锟斤拷锟�</param>
+        /// <param name="systemConfiguration">要锟斤拷锟斤拷锟较低筹拷锟斤拷枚锟斤拷锟?/param>
         public void SaveSystemConfiguration(SystemConfiguration systemConfiguration)
         {
             lock (_sync)
@@ -1026,16 +1026,16 @@ namespace TeamAAS_VP.Services
 
         #region Feeder锟斤拷锟斤拷锟斤拷锟斤拷
         /// <summary>
-        /// 锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟街伙拷锟斤拷锟斤拷稀锟
+        /// 锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟街伙拷锟斤拷锟斤拷稀锟?
         /// </summary>
-        /// <returns>锟斤拷锟斤拷锟斤拷锟斤拷锟街伙拷锟斤拷锟斤拷稀锟�</returns>
+        /// <returns>锟斤拷锟斤拷锟斤拷锟斤拷锟街伙拷锟斤拷锟斤拷稀锟?/returns>
         public IReadOnlyCollection<FeederClearWork> GetAllClearanceTasks() { lock (_sync) { return FeederClearanceTasks.ToList().AsReadOnly(); } }
 
         /// <summary>
-        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟绞蔽�拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟TaskCode锟斤拷锟斤拷珊锟街久伙拷锟斤拷锟斤拷锟侥硷拷锟斤拷
+        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟绞蔽�拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟?TaskCode锟斤拷锟斤拷珊锟街久伙拷锟斤拷锟斤拷锟侥硷拷锟斤拷
         /// </summary>
         /// <param name="task">要锟斤拷锟接伙拷锟斤拷碌锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="FeederClearWork"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="FeederClearWork"/>锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public FeederClearWork AddOrUpdateClearanceTask(FeederClearWork task)
         {
             if (task == null) return null;
@@ -1049,7 +1049,7 @@ namespace TeamAAS_VP.Services
                 }
                 else
                 {
-                    // 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷前锟斤拷锟斤拷偶锟�1
+                    // 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷前锟斤拷锟斤拷偶锟?
                     task.TaskCode = FeederClearanceTasks.Count > 0 ? FeederClearanceTasks.Max(t => t.TaskCode) + 1 : 1;
                     FeederClearanceTasks.Add(task);
                 }
@@ -1080,7 +1080,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷癫⒊志没锟斤拷占锟斤拷系锟斤拷锟斤拷锟斤拷募锟斤拷锟
+        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷癫⒊志没锟斤拷占锟斤拷系锟斤拷锟斤拷锟斤拷募锟斤拷锟?
         /// </summary>
         public void ClearAllClearanceTasks()
         {
@@ -1092,7 +1092,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟Id 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟?Id 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟斤拷锟斤拷 Guid锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -1106,14 +1106,14 @@ namespace TeamAAS_VP.Services
         /// 锟斤拷锟捷憋拷识锟斤拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷息锟斤拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟斤拷锟斤拷 Guid锟斤拷</param>
-        /// <returns>匹锟斤拷锟<see cref="FeederClearWork"/>锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <returns>匹锟斤拷锟?<see cref="FeederClearWork"/>锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public FeederClearWork GetClearanceTask(Guid id)
         {
             lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.Id == id); }
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟斤拷锟斤拷锟斤拷诺锟斤拷锟斤拷锟斤拷锟斤拷锟
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟斤拷锟斤拷锟斤拷诺锟斤拷锟斤拷锟斤拷锟斤拷锟?
         /// </summary>
         /// <param name="taskNumber">锟斤拷锟斤拷锟脚o拷TaskCode锟斤拷锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -1126,7 +1126,7 @@ namespace TeamAAS_VP.Services
         /// 锟斤拷锟斤拷锟斤拷锟斤拷锟脚伙拷取锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷息锟斤拷
         /// </summary>
         /// <param name="taskNumber">锟斤拷锟斤拷锟脚o拷TaskCode锟斤拷锟斤拷</param>
-        /// <returns>匹锟斤拷锟<see cref="FeederClearWork"/>锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <returns>匹锟斤拷锟?<see cref="FeederClearWork"/>锟斤拷锟揭诧拷锟斤拷锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         public FeederClearWork GetClearanceTaskByNumber(int taskNumber)
         {
             lock (_sync) { return FeederClearanceTasks.FirstOrDefault(t => t.TaskCode == taskNumber); }
@@ -1150,21 +1150,21 @@ namespace TeamAAS_VP.Services
         /// 锟竭程帮拷全锟斤拷锟矫凤拷锟斤拷锟斤拷锟节存集锟较斤拷锟斤拷只锟斤拷锟斤拷锟绞诧拷锟斤拷锟节诧拷锟斤拷锟斤拷锟斤拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷识锟斤拷Id锟斤拷锟斤拷</param>
-        /// <returns>匹锟斤拷锟<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟津返伙拷 <c>null</c>锟斤拷</returns>
+        /// <returns>匹锟斤拷锟?<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟津返伙拷 <c>null</c>锟斤拷</returns>
         public LightControllerConfig GetLightController(int id)
         {
             lock (_sync) { return LightControllers.FirstOrDefault(c => c.Id == id); }
         }
 
         /// <summary>
-        /// 锟斤拷锟斤拷锟斤拷锟斤拷鹿锟皆达拷锟斤拷锟斤拷锟斤拷锟斤拷谩锟
+        /// 锟斤拷锟斤拷锟斤拷锟斤拷鹿锟皆达拷锟斤拷锟斤拷锟斤拷锟斤拷谩锟?
         /// - 锟斤拷 <paramref name="controller"/> 为 <c>null</c> 锟斤拷锟斤拷 <c>null</c>锟斤拷
         /// - 锟斤拷锟斤拷时锟斤拷 Id 匹锟斤拷锟斤拷锟斤拷锟筋并锟芥换锟斤拷
         /// - 锟斤拷锟斤拷时锟斤拷锟斤拷锟斤拷锟斤拷锟侥匡拷锟斤拷锟斤拷 Id锟斤拷锟斤拷为锟斤拷锟斤拷锟斤拷锟节碉拷每锟斤拷通锟斤拷锟斤拷锟斤拷全锟斤拷通锟斤拷锟斤拷牛锟紾lobalIndex锟斤拷锟斤拷
         /// 锟竭程帮拷全锟斤拷锟斤拷锟节诧拷使锟斤拷 <see cref="_sync"/> 锟斤拷锟斤拷锟斤拷锟较★拷
         /// </summary>
-        /// <param name="controller">要锟斤拷锟接伙拷锟斤拷碌锟<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷</param>
-        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
+        /// <param name="controller">要锟斤拷锟接伙拷锟斤拷碌锟?<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷</param>
+        /// <returns>锟斤拷锟斤拷锟接伙拷锟斤拷碌锟?<see cref="LightControllerConfig"/> 实锟斤拷锟斤拷锟斤拷锟斤拷为 <c>null</c> 时锟斤拷锟斤拷 <c>null</c>锟斤拷</returns>
         /// <exception cref="ArgumentException">锟斤拷要锟斤拷锟斤拷/锟斤拷锟铰的匡拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟截革拷时锟阶筹拷锟斤拷</exception>
         public LightControllerConfig AddOrUpdateLightController(LightControllerConfig controller)
         {
@@ -1185,10 +1185,10 @@ namespace TeamAAS_VP.Services
                 else
                 {
                     // 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷
-                    // 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷前锟斤拷锟Id + 1锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷锟斤拷为 1锟斤拷
+                    // 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷前锟斤拷锟?Id + 1锟斤拷锟斤拷锟斤拷锟斤拷为锟斤拷锟斤拷为 1锟斤拷
                     controller.Id = LightControllers.Count > 0 ? LightControllers.Max(c => c.Id) + 1 : 1;
 
-                    // 锟斤拷锟斤拷锟斤拷一锟斤拷全锟斤拷通锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟窖达拷锟节匡拷锟斤拷锟斤拷锟斤拷通锟斤拷 GlobalIndex 锟斤拷取锟斤拷锟街碉拷锟斤拷锟�1
+                    // 锟斤拷锟斤拷锟斤拷一锟斤拷全锟斤拷通锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟窖达拷锟节匡拷锟斤拷锟斤拷锟斤拷通锟斤拷 GlobalIndex 锟斤拷取锟斤拷锟街碉拷锟斤拷锟?
                     int nextGlobal = 0;
                     if (LightControllers.SelectMany(c => c.ChannelConfigs).Any())
                     {
@@ -1209,17 +1209,17 @@ namespace TeamAAS_VP.Services
                     LightControllers.Add(controller);
                 }
             }
-            // 锟街久伙拷锟斤拷锟铰猴拷墓锟皆达拷锟斤拷锟斤拷锟斤拷锟斤拷锟
+            // 锟街久伙拷锟斤拷锟铰猴拷墓锟皆达拷锟斤拷锟斤拷锟斤拷锟斤拷锟?
             FileHelper.WriteJsonFile(LightControllers, ConfigPaths.LightControllersConfigurationPath);
             return controller;
         }
 
         /// <summary>
-        /// 锟斤拷锟斤拷 Id 锟狡筹拷锟斤拷源锟斤拷锟斤拷锟斤拷锟斤拷锟矫诧拷锟斤拷剩锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷卤锟脚o拷锟斤拷 1 锟斤拷始锟斤拷锟斤拷锟斤拷牛锟斤拷锟
-        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟
+        /// 锟斤拷锟斤拷 Id 锟狡筹拷锟斤拷源锟斤拷锟斤拷锟斤拷锟斤拷锟矫诧拷锟斤拷剩锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷卤锟脚o拷锟斤拷 1 锟斤拷始锟斤拷锟斤拷锟斤拷牛锟斤拷锟?
+        /// 锟斤拷锟斤拷锟斤拷志没锟斤拷锟斤拷锟斤拷募锟斤拷锟?
         /// </summary>
         /// <param name="id">要锟狡筹拷锟侥匡拷锟斤拷锟斤拷 Id锟斤拷</param>
-        /// <returns>锟斤拷锟斤拷晒锟斤拷瞥锟斤拷锟斤拷锟<c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷锟斤拷锟斤拷未锟揭碉拷锟斤拷 Id锟斤拷锟斤拷</returns>
+        /// <returns>锟斤拷锟斤拷晒锟斤拷瞥锟斤拷锟斤拷锟?<c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷锟斤拷锟斤拷未锟揭碉拷锟斤拷 Id锟斤拷锟斤拷</returns>
         public bool RemoveLightController(int id)
         {
             bool result = false;
@@ -1229,7 +1229,7 @@ namespace TeamAAS_VP.Services
                 if (e != null)
                     result = LightControllers.Remove(e);
 
-                // 锟斤拷锟铰帮拷 Id 锟斤拷锟津并达拷 1 锟斤拷始锟斤拷锟铰憋拷牛锟斤拷员锟斤拷锟斤拷锟斤拷锟斤拷锟
+                // 锟斤拷锟铰帮拷 Id 锟斤拷锟津并达拷 1 锟斤拷始锟斤拷锟铰憋拷牛锟斤拷员锟斤拷锟斤拷锟斤拷锟斤拷锟?
                 int no = 1;
                 var sorted = LightControllers.OrderBy(c => c.Id).ToList();
                 foreach (var c in sorted)
@@ -1248,7 +1248,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟Id 锟侥癸拷源锟斤拷锟斤拷锟斤拷锟斤拷
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟?Id 锟侥癸拷源锟斤拷锟斤拷锟斤拷锟斤拷
         /// </summary>
         /// <param name="id">锟斤拷锟斤拷锟斤拷 Id锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -1257,7 +1257,7 @@ namespace TeamAAS_VP.Services
         /// <summary>
         /// 锟斤拷取锟斤拷锟叫癸拷源通锟斤拷锟斤拷只锟斤拷锟斤拷锟较o拷锟斤拷 GlobalIndex 锟斤拷锟津返回★拷
         /// </summary>
-        /// <returns>锟斤拷 GlobalIndex 锟斤拷锟斤拷锟<see cref="ChannelConfig"/> 只锟斤拷锟斤拷锟较★拷</returns>
+        /// <returns>锟斤拷 GlobalIndex 锟斤拷锟斤拷锟?<see cref="ChannelConfig"/> 只锟斤拷锟斤拷锟较★拷</returns>
         public IReadOnlyCollection<ChannelConfig> GetAllLightChannels()
         {
             lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).OrderBy(ch => ch.GlobalIndex).ToList().AsReadOnly(); }
@@ -1267,14 +1267,14 @@ namespace TeamAAS_VP.Services
         /// 锟斤拷锟斤拷全锟斤拷通锟斤拷锟斤拷锟斤拷锟斤拷取锟斤拷锟斤拷通锟斤拷锟斤拷锟矫★拷
         /// </summary>
         /// <param name="globalIndex">通锟斤拷锟斤拷全锟斤拷锟斤拷锟斤拷锟斤拷GlobalIndex锟斤拷锟斤拷</param>
-        /// <returns>匹锟斤拷锟<see cref="ChannelConfig"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟津返伙拷 <c>null</c>锟斤拷</returns>
+        /// <returns>匹锟斤拷锟?<see cref="ChannelConfig"/> 实锟斤拷锟斤拷锟揭诧拷锟斤拷锟津返伙拷 <c>null</c>锟斤拷</returns>
         public ChannelConfig GetLightChannelByGlobalIndex(int globalIndex)
         {
             lock (_sync) { return LightControllers.SelectMany(c => c.ChannelConfigs).FirstOrDefault(ch => ch.GlobalIndex == globalIndex); }
         }
 
         /// <summary>
-        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟饺�拷锟酵�拷锟斤拷锟斤拷锟斤拷锟酵�拷锟斤拷锟斤拷谩锟
+        /// 锟叫讹拷锟角凤拷锟斤拷锟街革拷锟饺�拷锟酵�拷锟斤拷锟斤拷锟斤拷锟酵�拷锟斤拷锟斤拷谩锟?
         /// </summary>
         /// <param name="globalIndex">全锟斤拷通锟斤拷锟斤拷锟斤拷锟斤拷</param>
         /// <returns>锟斤拷锟节凤拷锟斤拷 <c>true</c>锟斤拷锟斤拷锟津返伙拷 <c>false</c>锟斤拷</returns>
@@ -1356,8 +1356,8 @@ namespace TeamAAS_VP.Services
         public ScrewFeederInfo GetScrewFeeder(Guid id) { lock (_sync) { return ScrewFeeders.FirstOrDefault(s => s.Id == id); } }
 
         /// <summary>
-        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟剿匡拷锟斤拷锟斤拷锟斤拷锟斤拷谩锟
-        /// 锟斤拷锟斤拷时锟斤拷未指锟斤拷 FeederNumber 锟斤拷锟斤拷锟轿�拷锟角帮拷锟斤拷锟�+1锟斤拷
+        /// 锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟剿匡拷锟斤拷锟斤拷锟斤拷锟斤拷谩锟?
+        /// 锟斤拷锟斤拷时锟斤拷未指锟斤拷 FeederNumber 锟斤拷锟斤拷锟轿�拷锟角帮拷锟斤拷锟?1锟斤拷
         /// </summary>
         public ScrewFeederInfo AddOrUpdateScrewFeeder(ScrewFeederInfo feeder)
         {
@@ -1401,7 +1401,7 @@ namespace TeamAAS_VP.Services
         public event Action<ScrewFeederInfo> ScrewFeederLowLevelAlarmTriggered;
 
         /// <summary>
-        /// 锟斤拷取指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺锟绞o拷锟斤拷锟剿匡拷锟斤拷锟斤拷锟斤拷也锟斤拷锟斤拷锟斤拷锟-1锟斤拷
+        /// 锟斤拷取指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺锟绞o拷锟斤拷锟剿匡拷锟斤拷锟斤拷锟斤拷也锟斤拷锟斤拷锟斤拷锟?-1锟斤拷
         /// </summary>
         public int GetRemainingCountByFeederNumber(int feederNumber)
         {
@@ -1414,7 +1414,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷取指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺牡锟斤拷锟斤拷锟斤拷锟阶刺�拷锟斤拷也锟斤拷锟斤拷锟斤拷锟false锟斤拷
+        /// 锟斤拷取指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺牡锟斤拷锟斤拷锟斤拷锟阶刺�拷锟斤拷也锟斤拷锟斤拷锟斤拷锟?false锟斤拷
         /// </summary>
         public bool GetLowLevelAlarmStatusByFeederNumber(int feederNumber)
         {
@@ -1452,7 +1452,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 为指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺菁锟街革拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷惴碉拷锟-1
+        /// 为指锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷诺菁锟街革拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷惴碉拷锟?-1
         /// </summary>
         public int DecrementScrewCountByFeederNumber(int feederNumber, int decrement = 1)
         {
@@ -1557,7 +1557,7 @@ namespace TeamAAS_VP.Services
                 }
                 catch
                 {
-                    // 锟斤拷锟斤拷锟斤拷锟捷匡拷写锟斤拷锟斤拷螅�锟铰硷拷锟斤拷锟斤拷锟斤拷锟街
+                    // 锟斤拷锟斤拷锟斤拷锟捷匡拷写锟斤拷锟斤拷螅�锟铰硷拷锟斤拷锟斤拷锟斤拷锟街?
                 }
             }
             catch
@@ -1567,7 +1567,7 @@ namespace TeamAAS_VP.Services
         }
 
         /// <summary>
-        /// 锟斤拷锟绞o拷锟斤拷锟剿匡拷欠癖ň锟
+        /// 锟斤拷锟绞o拷锟斤拷锟剿匡拷欠癖ň锟?
         /// </summary>
         public bool CheckAlarm(int feederNumber)
         {

+ 1 - 1
TeamAAS-VM/ViewModels/SettingViewModel.cs

@@ -1656,7 +1656,7 @@ namespace TeamAAS_VP.ViewModels
 
         private Int16 _WorkMode = 0;
         /// <summary>
-        /// 工作模式 =1 拍1打1 =2 拍1打所有
+        /// 工作模式 =1 拍1打1 =2 拍1打所有,=3:先拍1打1打3颗再拍2打所有  
         /// </summary>
         public Int16 WorkMode
         {

+ 50 - 16
TeamAAS-VM/Views/SettingView.xaml

@@ -540,30 +540,32 @@
                                     Grid.Column="1"
                                     Margin="6,2"
                                     Text="{Binding SelectDeviceInfo.ApiKey, Mode=TwoWay}" />
-
                                 <StackPanel
                                     Grid.Row="11"
                                     Grid.Column="1"
                                     Orientation="Horizontal">
                                     <CheckBox
-     Grid.Row="11"
-     Grid.Column="1"
-     Margin="6,2"
-     Command="{Binding CheckStatusCommand}"
-     Content="启用 MES"
-     IsChecked="{Binding SelectDeviceInfo.EnableMES, Mode=TwoWay}" />
+    Grid.Row="11"
+    Grid.Column="1"
+    Margin="6,2"
+    Command="{Binding CheckStatusCommand}"
+    Content="启用 MES"
+    IsChecked="{Binding SelectDeviceInfo.EnableMES, Mode=TwoWay}" />
                                     <!--<CheckBox Grid.Row="10"
-           Grid.Column="1"
-           Content="是否启用两次产品编号"
-           IsChecked="{Binding SelectDeviceInfo.EnableDoubleMes, Mode=TwoWay}"
-           Margin="6,2" />-->
+          Grid.Column="1"
+          Content="是否启用两次产品编号"
+          IsChecked="{Binding SelectDeviceInfo.EnableDoubleMes, Mode=TwoWay}"
+          Margin="6,2" />-->
                                     <CheckBox
-     Margin="6,2"
-     Command="{Binding CheckStatusCommand}"
-     Content="是否启用锁螺丝螺丝XY超限(目前只有组装线锁电池启用)"
-     IsChecked="{Binding SelectDeviceInfo.ScrewOverrun, Mode=TwoWay}" />
+                                        Grid.Row="11"
+                                        Grid.Column="1"
+                                        Margin="6,2"
+                                        Command="{Binding CheckStatusCommand}"
+Content="是否启用锁螺丝XY超限"
+IsChecked="{Binding SelectDeviceInfo.EnableXY, Mode=TwoWay}" />
                                 </StackPanel>
-                               
+
+                                
                                 <StackPanel
                                     Grid.Row="13"
                                     Grid.Column="1"
@@ -2978,6 +2980,38 @@ Text="{Binding SelectDeviceInfo.DataInfo.Screwsize2, Mode=TwoWay}" />
                                 Maximum="100"
                                 Minimum="0"
                                 Value="{Binding WorkMode, Mode=TwoWay}" />
+                        <!-- 固定相机检测锁附/组装次数 -->
+                        <TextBlock Grid.Row="6"
+                                   Grid.Column="0"
+                                   Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
+                                   VerticalAlignment="Center"
+                                   HorizontalAlignment="Right"
+                                   Margin="0,6,10,6"
+                                   Text="{lex:Loc 固定相机检测锁附组装次数}" />
+                        <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="{lex:Loc 工作模式}" />
+                        <mah:NumericUpDown Grid.Row="7"
+                                           Grid.Column="1"
+                                           Margin="0,10"
+                                           Value="{Binding WorkMode,Mode=TwoWay}"
+                                           Minimum="0"
+                                           Maximum="100"
+                                           FontSize="{DynamicResource Font.Size.Body3}"
+                                           materialDesign:HintAssist.HelperTextFontSize="10"
+                                           materialDesign:HintAssist.HelperText="1:拍1打1 - 2:拍2打所有 - 3:先拍1打1打3颗再拍2打所有" />
 
                             <!--  取料位置  -->
                             <TextBlock