Просмотр исходного кода

修复图片被提前释放与是否通过零件码判断螺丝型号

KWD 6 месяцев назад
Родитель
Сommit
12c24762db

+ 331 - 268
TeamAAS-VM/Core/Management.cs

@@ -1293,12 +1293,12 @@ namespace TeamAAS_VP.Core
                 }
 
                 //获取产品编码
-                //_productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
-                ////如果产品编码为空,则以当前的时间戳作为编码
-                //if (string.IsNullOrEmpty(_productService.CurrentProductCode))
-                //{
-                //    _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
-                //}
+                _productService.CurrentProductCode = plc.ReadNode<string>(string.Format(addressConfig.In_Code.Address, 0));
+                //如果产品编码为空,则以当前的时间戳作为编码
+                if (string.IsNullOrEmpty(_productService.CurrentProductCode))
+                {
+                    _productService.CurrentProductCode = DateTime.Now.ToString("yyyyMMddHHmmssfff");
+                }
 
                 // 触发下相机拍照
                 if (addressConfig.In_DowmCameraExe.Address.Contains(tuple.nodeId))
@@ -1861,7 +1861,7 @@ namespace TeamAAS_VP.Core
                             await plc.WriteNodeAsync(addressConfig.In_WorkDone.Address, (Int16)0);
                             // 停止采集压力并保存
                             await StopAndSavePressureCollectionAsync(currentProduct.Name, _productService.CurrentProductCode, positionIndex);
-                        }
+                                }
                         else
                         {
                             SendTaskMessage(Lang.停止锁付信号已关闭, MessageLevel.Alarm);
@@ -2040,6 +2040,7 @@ namespace TeamAAS_VP.Core
                                 {
                                     return;
                                 }
+                                var systemConfig = _configService.GetSystemConfiguration();
 
                                 string code = "";
                                 //plc启用的模式
@@ -2075,6 +2076,22 @@ namespace TeamAAS_VP.Core
                                         code = code.ToUpper();
                                         if (!string.IsNullOrEmpty(code))
                                         {
+                                            if (systemConfig.IsBasePartCodeChooseScrew)//是否基于零件码,判断是不是当站要打的螺丝
+                                            {
+                                                var val = CheckCode(code, systemConfig.ChooseScrewModel);
+                                                if (val)
+                                                {
+                                                    SendTaskMessage($"是当站螺丝:{code}", MessageLevel.Info);
+                                                    await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
+                                                }
+                                                else
+                                                {
+                                                    SendTaskMessage($"不是当站螺丝:{code}", MessageLevel.Info);
+                                                    await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)2);
+                                                    await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+                                                    return;
+                                                }
+                                            }
                                             SendTaskMessage($"二维码扫码成功:{code}", MessageLevel.Info);
                                             await plc.WriteNodeAsync(addressConfig.Out_QrCodePhotoResault.Address, (Int16)1);
                                         }
@@ -2104,338 +2121,338 @@ namespace TeamAAS_VP.Core
                                 //询问mes
                                 if (state == 1)
                                 {
-                                    //这里缺少从MES获取产品配方的内容,需要补充
-
-                                    _LastMesCheckTime[i] = (await _mesService.GetServerTimeAsync(i, code, 2)).Now;
-
-                                    //获取当前工位的配置
-                                    var stationConfig = _configService.GetDeviceInfo(i);
-                                    if (stationConfig.EnableDoubleMes)
+                                    if (_configService.GetDeviceInfo().EnableMES)
                                     {
-                                        SendTaskMessage($"收到{i}:{stationConfig.DeviceName}过站检查请求(当站是否生产)(当前需要双MES验证)...", MessageLevel.Debug);
+                                        //这里缺少从MES获取产品配方的内容,需要补充
+                                        if (i == 0)
+                                        {
+                                            SendTaskMessage($"收到当前过站检查请求(当站是否生产)...", MessageLevel.Debug);
+                                        }
+                                        else
+                                        {
+                                            SendTaskMessage($"收到{i}过站检查请求(当站是否生产)...", MessageLevel.Debug);
+                                        }
 
+                                        _LastMesCheckTime[i] = DateTime.UtcNow;
                                         LogHelper.WriteLogMes($"【mes开始QUERY】");
                                         SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
-                                        (bool isSuccess, string response) = await _mesService.StationGetExAsync(i, code, "", 2);//基于电池的SN获取产品SN,询问mes
-                                        if (isSuccess)
+                                        if (systemConfig.IsBasePartCodeGetSN)//是否基于零件码,判断是否过站
                                         {
-                                            LogHelper.WriteLogMes($"询问mes成功");
-                                            SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
-                                            string ProductMainSN_Temp = "";
-                                            if (response != "MES功能未启用!")
+                                            (bool isSuccess, string response) = await _mesService.StationGetExAsync(code, "", 2);//基于电池的SN获取产品SN,询问mes
+                                            if (isSuccess)
                                             {
+                                                string ProductMainSN_Temp = "";
+                                                LogHelper.WriteLogMes($"询问mes成功");
+                                                SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+
                                                 string[] item = response.Split('\n');
-                                                //获取过度件sn
-                                                string snItem = item.FirstOrDefault(f => f.Contains("sn="));
-                                                if (snItem != null)
+                                                if (item[2].Contains("sn="))
                                                 {
-                                                    ProductMainSN_Temp = snItem.Replace("sn=", "").Trim();
-                                                    SendTaskMessage($"过度件sn:{ProductMainSN_Temp}", MessageLevel.Info);
+                                                    ProductMainSN_Temp = item[2].Replace("sn=", "");
+                                                    SendTaskMessage($"流程sn:{ProductMainSN_Temp}", MessageLevel.Info);
                                                 }
-                                            }
 
-                                            (bool isSuccess2, string response2) = await _mesService.StationGetAsync(i, ProductMainSN_Temp, "", 2);//询问mes
-                                            if (isSuccess2)
-                                            {
-                                                LogHelper.WriteLogMes($"第二次询问mes成功");
-                                                SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
-                                                if (response2 != "MES功能未启用!")
+                                                LogHelper.WriteLogMes($"询问mes成功");
+                                                SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+
+                                                //20260214,螺丝机特别版
+                                                (bool isSuccess2, string response2) = await _mesService.StationGetAsync(ProductMainSN_Temp, "", 2);//询问mes
+                                                if (isSuccess2)
                                                 {
-                                                    string[] item = response2.Split('\n');
-                                                    //获取产品主sn和wo用于后续上传数据使用
-                                                    string snItem = item.FirstOrDefault(f => f.Contains("sn="));
-                                                    string woItem = item.FirstOrDefault(f => f.Contains("wo="));
-                                                    if (snItem != null)
+                                                    LogHelper.WriteLogMes($"询问mes成功");
+                                                    SendTaskMessage($"询问mes成功:{response2}", MessageLevel.Debug);
+
+                                                    item = response2.Split('\n');
+                                                    if (item[3].Contains("sn="))
                                                     {
-                                                        ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
-                                                        if (i == 0)
-                                                        {
-                                                            _productService.CurrentProductCode = ProductMainSN[i];
-                                                        }
+                                                        ProductMainSN[i] = item[3].Replace("sn=", "");
                                                         SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
                                                     }
-                                                    if (woItem != null)
+                                                    if (item[5].Contains("wo="))
                                                     {
-                                                        wo = woItem.Replace("wo=", "").Trim();
+                                                        wo = item[5].Replace("wo=", "");
                                                         SendTaskMessage($"产品主wo:{wo}", MessageLevel.Info);
                                                     }
+
+                                                    LogHelper.WriteLogMes($"第二次询问mes成功");
+                                                    SendTaskMessage($"第二次询问mes成功:{response2}", MessageLevel.Debug);
+
+                                                    //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
+                                                    await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                                    await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
                                                 }
+                                                else
+                                                {
+                                                    LogHelper.WriteLogMes($"第二次询问mes失败");
+                                                    SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
 
-                                                //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-                                                await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
-                                                await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
+                                                    //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
+                                                    await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                                    await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+                                                }
                                             }
                                             else
                                             {
-                                                LogHelper.WriteLogMes($"第二次询问mes失败");
-                                                SendTaskMessage($"第二次询问mes失败:{response2}", MessageLevel.Error);
+                                                LogHelper.WriteLogMes($"询问mes失败");
+                                                SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
 
                                                 //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
                                                 await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
                                                 await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
                                             }
                                         }
-                                        else
+                                        else //直接基于RFID询问是否过站
                                         {
-                                            //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-                                            await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
-                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
-
-                                            LogHelper.WriteLogMes($"询问mes失败");
-                                            SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
-
-                                            //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-                                            await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
-                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
-                                        }
-                                        LogHelper.WriteLogMes($"【mes结束QUERY】");
-                                        SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
-                                    }
-                                    else
-                                    {
-                                        SendTaskMessage($"收到{i}:{stationConfig.DeviceName}过站检查请求(当站是否生产)(当前不需要双MES验证)...", MessageLevel.Debug);
-
-                                        LogHelper.WriteLogMes($"【mes开始QUERY】");
-                                        SendTaskMessage($"mes开始QUERY", MessageLevel.Info);
-                                        (bool isSuccess, string response) = await _mesService.StationGetAsync(i, code, "", 2);//询问mes
-                                        if (isSuccess)
-                                        {
-                                            if (response != "MES功能未启用!")
+                                            (bool isSuccess, string response) = await _mesService.StationGetAsync(code, "", 2);//询问mes
+                                            if (isSuccess)
                                             {
-                                                string[] item = response.Split('\n');
-                                                //获取产品主sn和wo用于后续上传数据使用
-                                                string snItem = item.FirstOrDefault(f => f.Contains("sn="));
-                                                string woItem = item.FirstOrDefault(f => f.Contains("wo="));
-                                                if (snItem != null)
+                                                LogHelper.WriteLogMes($"询问mes成功");
+                                                SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
+
+                                                var item = response.Split('\n');
+                                                if (item[3].Contains("sn="))
                                                 {
-                                                    ProductMainSN[i] = snItem.Replace("sn=", "").Trim();
-                                                    if (i == 0)
-                                                    {
-                                                        _productService.CurrentProductCode = ProductMainSN[i];
-                                                    }
+                                                    ProductMainSN[i] = item[3].Replace("sn=", "");
                                                     SendTaskMessage($"产品主sn:{ProductMainSN[i]}", MessageLevel.Info);
                                                 }
-                                                if (woItem != null)
+                                                if (item[5].Contains("wo="))
                                                 {
-                                                    wo = woItem.Replace("wo=", "").Trim();
+                                                    wo = item[5].Replace("wo=", "");
                                                     SendTaskMessage($"产品主wo:{wo}", MessageLevel.Info);
                                                 }
+
+                                                //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
+                                                await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                                await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
                                             }
+                                            else
+                                            {
+                                                LogHelper.WriteLogMes($"询问mes失败");
+                                                SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
 
-                                            LogHelper.WriteLogMes($"询问mes成功");
-                                            SendTaskMessage($"询问mes成功:{response}", MessageLevel.Debug);
-                                            //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-                                            await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
-                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
-                                        }
-                                        else
-                                        {
-                                            LogHelper.WriteLogMes($"询问mes失败");
-                                            SendTaskMessage($"询问mes失败:{response}", MessageLevel.Error);
-                                            //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
-                                            await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
-                                            await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+                                                //产品发生改变并且供料器发生了变化时,需要通知PLC进行取料更改
+                                                await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                                await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)2);
+                                            }
                                         }
+
                                         LogHelper.WriteLogMes($"【mes结束QUERY】");
                                         SendTaskMessage($"mes结束QUERY", MessageLevel.Info);
                                     }
+                                    else
+                                    {
+                                        LogHelper.WriteLogMes($"【未启用mes】");
+                                        SendTaskMessage($"未启用mes", MessageLevel.Info);
+                                        await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                        await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)1);
+                                    }
                                 }
                                 // 上传本站数据
                                 else if (state == 2)
                                 {
-                                    DFC.Clear();
+                                    if (_configService.GetDeviceInfo().EnableMES == true)
+                                    {
+                                        DFC.Clear();
 
-                                    //获取当前工位的配置
-                                    var stationConfig = _configService.GetDeviceInfo(i);
-                                    SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
-                                    //从服务器中获取当前时间
-                                    var serverTimeResult = await _mesService.GetServerTimeAsync(i, code, 2);
+                                        //获取当前工位的配置
+                                        var stationConfig = _configService.GetDeviceInfo(0);
+                                        SendTaskMessage($"收到{i}:{stationConfig.DeviceName}上传本站数据请求...", MessageLevel.Debug);
+                                        //从服务器中获取当前时间
+                                        var serverTimeResult = await _mesService.GetServerTimeAsync(i, code, 2);
 
-                                    //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
+                                        //这里缺少上传MES的本站数据结果及开始和结束时间,需要补充
 
-                                    if (i == 0)
-                                    {
-                                        CTtime = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
-                                    }
+                                        if (i == 0)
+                                        {
+                                            CTtime = serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds;
+                                        }
 
-                                    //读取产品结果
-                                    Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
+                                        //读取产品结果
+                                        Int16 resultIndex = plc.ReadNode<Int16>(string.Format(addressConfig.In_Result.Address, i));
 
-                                    //目前只记录当前站
-                                    if (i == 0)
-                                        await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
+                                        //目前只记录当前站
+                                        if (i == 0)
+                                            await _systemDatabaseService.RecordProductionAsync(new ProductionRecord()
+                                            {
+                                                ProductName = currentProduct.Name,
+                                                ProductCode = ProductMainSN[i],
+                                                DeviceId = i,
+                                                DeviceName = "",
+                                                Category = resultIndex == 1 ? "OK" : "NG",
+                                                Quantity = 1,
+                                                Remark = $"TotalSeconds:{serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
+                                            });
+
+                                        LogHelper.WriteLogMes($"【mes开始ADD】");
+                                        SendTaskMessage($"mes开始ADD", MessageLevel.Info);
+                                        //上传mes
+                                        string torque = string.Join(",", torqueList);
+                                        string pressure = string.Join(",", pressureList);
+                                        string turn = string.Join(",", turnList);
+                                        //这里现在上传的结果都是锁付站的,如果存在其他附属站的数据需要上传时,将不适用,要根据实际情况进行调整
+                                        (bool isSuccess, string response) = await _mesService.SubmitGetAsync(ProductMainSN[i], "", torque, pressure, turn, resultIndex == 1 ? true : false, _LastMesCheckTime[i], DateTime.UtcNow);
+                                        if (isSuccess)
                                         {
-                                            ProductName = currentProduct.Name,
-                                            ProductCode = ProductMainSN[i],
-                                            DeviceId = i,
-                                            DeviceName = "",
-                                            Category = resultIndex == 1 ? "OK" : "NG",
-                                            Quantity = 1,
-                                            Remark = $"TotalSeconds:{serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds.ToString("F2")}",
-                                        });
-
-                                    LogHelper.WriteLogMes($"【mes开始ADD】");
-                                    SendTaskMessage($"mes开始ADD", MessageLevel.Info);
-                                    //上传mes
-                                    string torque = string.Join(",", torqueList);
-                                    string pressure = string.Join(",", pressureList);
-                                    string turn = string.Join(",", turnList);
-                                    //这里现在上传的结果都是锁付站的,如果存在其他附属站的数据需要上传时,将不适用,要根据实际情况进行调整
-                                    (bool isSuccess, string response) = await _mesService.SubmitGetAsync(i, ProductMainSN[i], "", torque, pressure, turn, resultIndex == 1 ? true : false, _LastMesCheckTime[i], serverTimeResult.Now);
-                                    if (isSuccess)
-                                    {
-                                        LogHelper.WriteLogMes($"上传mes成功");
-                                        SendTaskMessage($"上传mes成功", MessageLevel.Debug);
-                                    }
-                                    else
-                                    {
-                                        LogHelper.WriteLogMes($"上传mes失败");
-                                        SendTaskMessage($"上传mes失败", MessageLevel.Error);
-                                    }
-                                    await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
+                                            LogHelper.WriteLogMes($"上传mes成功");
+                                            SendTaskMessage($"上传mes成功", MessageLevel.Debug);
+                                        }
+                                        else
+                                        {
+                                            LogHelper.WriteLogMes($"上传mes失败");
+                                            SendTaskMessage($"上传mes失败", MessageLevel.Error);
+                                        }
+                                        await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
 
-                                    //是否保存当前的产品记录至CSV?
-                                    if (stationConfig.SaveCsv)
-                                    {
-                                        //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
-                                        if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
+                                        //是否保存当前的产品记录至CSV?
+                                        if (stationConfig.SaveCsv)
                                         {
-                                            bool recordResult = false;
-                                            if (i == 0)
+                                            //判断锁付路径字符串是否为空,如果不为空则保存,否则不保存
+                                            if (!string.IsNullOrEmpty(stationConfig.SaveCsvPath))
                                             {
-                                                foreach (var lockResult in lockResultsAll)
+                                                bool recordResult = false;
+                                                if (i == 0)
                                                 {
-                                                    bool torqueRes, turnRes, pressureRes;
-                                                    if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
-                                                    {
-                                                        torqueRes = true;
-                                                    }
-                                                    else torqueRes = false;
-                                                    if (lockResult.Pressure >= stationConfig.DataInfo.CTQ_LSL_Pressure && lockResult.Pressure <= stationConfig.DataInfo.CTQ_USL_Pressure)
-                                                    {
-                                                        pressureRes = true;
-                                                    }
-                                                    else pressureRes = false;
-                                                    if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
+                                                    foreach (var lockResult in lockResultsAll)
                                                     {
-                                                        turnRes = true;
+                                                        bool torqueRes, turnRes, pressureRes;
+                                                        if (lockResult.LockTorque >= lockResult.TargetTorqueLowerLimit && lockResult.LockTorque <= lockResult.TargetTorqueUpperLimit)
+                                                        {
+                                                            torqueRes = true;
+                                                        }
+                                                        else torqueRes = false;
+                                                        if (lockResult.Pressure >= stationConfig.DataInfo.CTQ_LSL_Pressure && lockResult.Pressure <= stationConfig.DataInfo.CTQ_USL_Pressure)
+                                                        {
+                                                            pressureRes = true;
+                                                        }
+                                                        else pressureRes = false;
+                                                        if (lockResult.LockTurns >= lockResult.TargetTurnsLowerLimit && lockResult.LockTurns <= lockResult.TargetTurnsUpperLimit)
+                                                        {
+                                                            turnRes = true;
+                                                        }
+                                                        else turnRes = false;
+                                                        DFC.Add(new DataFormCtq
+                                                        {
+                                                            PPID = ProductMainSN[i],
+                                                            PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                            PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                            CTQ_NAME = "Torque",
+                                                            CTQ_VALUE = lockResult.LockTorque,
+                                                            CTQ_LSL = lockResult.TargetTorqueLowerLimit,
+                                                            CTQ_USL = lockResult.TargetTorqueUpperLimit,
+                                                            PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                            SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                            COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                            REVISION = stationConfig.DataInfo.REVISION,
+                                                            WO = wo,
+                                                            MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                            MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                            PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
+                                                            PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                            CTQ_UNIT_OF_MEASURE = "kgf.cm",
+                                                            ERROR_MESSAGE = torqueRes ? "" : "Torque_Spec OOS"
+                                                        });
+                                                        DFC.Add(new DataFormCtq
+                                                        {
+                                                            PPID = ProductMainSN[i],
+                                                            PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                            PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                            CTQ_NAME = "Turn",
+                                                            CTQ_VALUE = lockResult.LockTurns,
+                                                            CTQ_LSL = lockResult.TargetTurnsLowerLimit,
+                                                            CTQ_USL = lockResult.TargetTurnsUpperLimit,
+                                                            PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                            SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                            COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                            REVISION = stationConfig.DataInfo.REVISION,
+                                                            WO = wo,
+                                                            MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                            MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                            PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
+                                                            PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                            CTQ_UNIT_OF_MEASURE = "圈",
+                                                            ERROR_MESSAGE = turnRes ? "" : "Turn_Spec OOS"
+                                                        });
+                                                        DFC.Add(new DataFormCtq
+                                                        {
+                                                            PPID = ProductMainSN[i],
+                                                            PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                            PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                            CTQ_NAME = "Pressure",
+                                                            CTQ_VALUE = lockResult.Pressure,
+                                                            CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
+                                                            CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
+                                                            PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                            SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                            COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                            REVISION = stationConfig.DataInfo.REVISION,
+                                                            WO = wo,
+                                                            MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                            MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                            PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
+                                                            PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                            CTQ_UNIT_OF_MEASURE = "N",
+                                                            ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
+                                                        });
                                                     }
-                                                    else turnRes = false;
-                                                    DFC.Add(new DataFormCtq
-                                                    {
-                                                        PPID = ProductMainSN[i],
-                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
-                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
-                                                        CTQ_NAME = "Torque",
-                                                        CTQ_VALUE = lockResult.LockTorque,
-                                                        CTQ_LSL = lockResult.TargetTorqueLowerLimit,
-                                                        CTQ_USL = lockResult.TargetTorqueUpperLimit,
-                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
-                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
-                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
-                                                        REVISION = stationConfig.DataInfo.REVISION,
-                                                        WO = wo,
-                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
-                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
-                                                        PROCESS_OUTCOME = torqueRes ? "PASS" : "FAIL",
-                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
-                                                        CTQ_UNIT_OF_MEASURE = "kgf.cm",
-                                                        ERROR_MESSAGE = torqueRes ? "" : "Torque_Spec OOS"
-                                                    });
-                                                    DFC.Add(new DataFormCtq
-                                                    {
-                                                        PPID = ProductMainSN[i],
-                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
-                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
-                                                        CTQ_NAME = "Turn",
-                                                        CTQ_VALUE = lockResult.LockTurns,
-                                                        CTQ_LSL = lockResult.TargetTurnsLowerLimit,
-                                                        CTQ_USL = lockResult.TargetTurnsUpperLimit,
-                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
-                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
-                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
-                                                        REVISION = stationConfig.DataInfo.REVISION,
-                                                        WO = wo,
-                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
-                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
-                                                        PROCESS_OUTCOME = turnRes ? "PASS" : "FAIL",
-                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
-                                                        CTQ_UNIT_OF_MEASURE = "圈",
-                                                        ERROR_MESSAGE = turnRes ? "" : "Turn_Spec OOS"
-                                                    });
-                                                    DFC.Add(new DataFormCtq
-                                                    {
-                                                        PPID = ProductMainSN[i],
-                                                        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
-                                                        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
-                                                        CTQ_NAME = "Pressure",
-                                                        CTQ_VALUE = lockResult.Pressure,
-                                                        CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
-                                                        CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
-                                                        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
-                                                        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
-                                                        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
-                                                        REVISION = stationConfig.DataInfo.REVISION,
-                                                        WO = wo,
-                                                        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
-                                                        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
-                                                        PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
-                                                        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
-                                                        CTQ_UNIT_OF_MEASURE = "N",
-                                                        ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
-                                                    });
                                                 }
-                                            }
-                                            //else
-                                            //{
-                                            //    DFC.Add(new DataFormCtq
-                                            //    {
-                                            //        PPID = ProductMainSN[i],
-                                            //        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
-                                            //        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
-                                            //        CTQ_NAME = "Pressure",
-                                            //        CTQ_VALUE = lockResult.Pressure,
-                                            //        CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
-                                            //        CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
-                                            //        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
-                                            //        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
-                                            //        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
-                                            //        REVISION = stationConfig.DataInfo.REVISION,
-                                            //        WO = wo,
-                                            //        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
-                                            //        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
-                                            //        PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
-                                            //        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
-                                            //        CTQ_UNIT_OF_MEASURE = "N",
-                                            //        ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
-                                            //    });
-                                            //    //压力值
-                                            //    //dataItems.Add("Pressure", pressure);
-                                            //    recordResult = RecordOtherStationResult(i, dataItems, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
-                                            //}
-                                            recordResult = RecordStationResult(i, DFC, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
-                                            if (recordResult)
-                                            {
-                                                SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
+                                                //else
+                                                //{
+                                                //    DFC.Add(new DataFormCtq
+                                                //    {
+                                                //        PPID = ProductMainSN[i],
+                                                //        PROCESS_NAME = stationConfig.DataInfo.PROCESS_NAME,
+                                                //        PROCESS_START_TIME = _LastMesCheckTime[i].ToString(),
+                                                //        CTQ_NAME = "Pressure",
+                                                //        CTQ_VALUE = lockResult.Pressure,
+                                                //        CTQ_LSL = stationConfig.DataInfo.CTQ_LSL_Pressure,
+                                                //        CTQ_USL = stationConfig.DataInfo.CTQ_USL_Pressure,
+                                                //        PROCESS_END_TIME = serverTimeResult.Now.ToString(),
+                                                //        SUPPLIER_NAME = stationConfig.DataInfo.SUPPLIER_NAME,
+                                                //        COMMODITY_TYPE = stationConfig.DataInfo.COMMODITY_TYPE,
+                                                //        REVISION = stationConfig.DataInfo.REVISION,
+                                                //        WO = wo,
+                                                //        MFG_LOT = stationConfig.DataInfo.MFG_LOT,
+                                                //        MFG_ASSY_LINE = stationConfig.DataInfo.MFG_ASSY_LINE,
+                                                //        PROCESS_OUTCOME = pressureRes ? "PASS" : "FAIL",
+                                                //        PROCESS_MACHINE_ID = stationConfig.DataInfo.PROCESS_MACHINE_ID,
+                                                //        CTQ_UNIT_OF_MEASURE = "N",
+                                                //        ERROR_MESSAGE = pressureRes ? "" : "Pressure_Spec OOS"
+                                                //    });
+                                                //    //压力值
+                                                //    //dataItems.Add("Pressure", pressure);
+                                                //    recordResult = RecordOtherStationResult(i, dataItems, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
+                                                //}
+                                                recordResult = RecordStationResult(i, DFC, ProductMainSN[i], serverTimeResult.Now.Subtract(_LastMesCheckTime[i]).TotalSeconds, _LastMesCheckTime[i], stationConfig.SaveCsvPath);
+                                                if (recordResult)
+                                                {
+                                                    SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存成功", MessageLevel.Debug);
+                                                }
+                                                else
+                                                {
+                                                    SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
+                                                }
                                             }
                                             else
                                             {
-                                                SendTaskMessage($"{i}:{stationConfig.DeviceName}产品记录保存失败", MessageLevel.Error);
+                                                SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
                                             }
                                         }
                                         else
                                         {
-                                            SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存路径,无法保存产品记录", MessageLevel.Error);
+                                            SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
                                         }
+
+                                        WriteProductLog(lockResultsAll, ProductMainSN[i], CTtime);
+
+                                        LogHelper.WriteLogMes($"【mes结束ADD】");
+                                        SendTaskMessage($"mes结束ADD", MessageLevel.Info);
                                     }
                                     else
                                     {
-                                        SendTaskMessage($"{i}:{stationConfig.DeviceName}工位未配置保存产品记录", MessageLevel.Debug);
+                                        await plc.WriteNodeAsync(addressConfig.Out_ScrewFeederIsChanged.Address, (Int16)1); //不发生改变
+                                        await plc.WriteNodeAsync(string.Format(addressConfig.Out_MesStatus.Address, i), (Int16)3);
                                     }
-
-                                    LogHelper.WriteLogMes($"【mes结束ADD】");
-                                    SendTaskMessage($"mes结束ADD", MessageLevel.Info);
-                                }
+                                }                     
                                 else
                                 {
                                     SendTaskMessage($"{i}过站检查信号:state={state},处理为默认状态", MessageLevel.Alarm);
@@ -2623,6 +2640,52 @@ namespace TeamAAS_VP.Core
             }
         }
 
+
+        /// <summary>
+        /// 判断是否符合当站
+        /// </summary>
+        /// <param name="data"></param>
+        /// <param name="checkData"></param>
+        /// <returns></returns>
+        private bool CheckCode(string data, string checkData)
+        {
+            try
+            {
+                if (data.Length != checkData.Length)
+                {
+                    var len = checkData.Length - data.Length;
+                    LogHelper.WriteLogMes($"判断是否符合当站失败,字符长度差{len}");
+                    SendTaskMessage($"判断是否符合当站失败,字符长度差{len}", MessageLevel.Error);
+                    return false;
+                }
+
+                int count = checkData.Length;
+                for (int i = 0; i < count; i++)
+                {
+                    if (checkData[i] == '*')//不需要检测的部分
+                    {
+                        continue;
+                    }
+
+                    if (data[i] != checkData[i])//有值不一致
+                    {
+                        LogHelper.WriteLogMes($"判断是否符合当站失败,第{i}个字符,不一致");
+                        SendTaskMessage($"判断是否符合当站失败,第{i}个字符,不一致", MessageLevel.Error);
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                LogHelper.WriteLogMes($"判断是否符合当站失败,{ex}");
+                SendTaskMessage($"判断是否符合当站失败,{ex}", MessageLevel.Error);
+                return false;
+            }
+
+        }
+
         #region vm启动检测
 
         /// <summary>

+ 3 - 0
TeamAAS-VM/Interfaces/IConfigService.cs

@@ -538,5 +538,8 @@ namespace TeamAAS_VP.Interfaces
         void SaveTorqueReaderConfig(TorqueSerialPortConfig config);
 
         TorqueSerialPortConfig GetTorqueReaderConfig();
+
+        CTQ_Data GetCTQDataInfo();
+        void SaveCTQDataInfo(CTQ_Data cd);
     }
 }

+ 39 - 0
TeamAAS-VM/Interfaces/IMesService.cs

@@ -29,6 +29,8 @@ namespace TeamAAS_VP.Interfaces
         /// </remarks>
         Task<(bool IsSuccess, string Response)> StationGetAsync(int deviceNo, string sn, string comp, CancellationToken cancellationToken = default);
 
+        Task<(bool IsSuccess, string Response)> StationGetExAsync(string sn, string comp, double timeoutInSeconds);
+
         /// <summary>
         /// 使用配置的过站(Station)URL 发起 GET 请求,携带序列号(sn)作为查询参数进行过站,并使用指定的超时时间(秒)。
         /// </summary>
@@ -54,6 +56,22 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<(bool IsSuccess, string Response)> StationGetExAsync(int deviceNo, string sn, string comp, double timeoutInSeconds);
 
+        /// <summary>
+        /// 使用配置的过站(Station)URL 发起 GET 请求,携带序列号(sn)作为查询参数进行过站,并使用指定的超时时间(秒)。
+        /// </summary>
+        /// <param name="sn">要过站的产品序列号,不能为空或空白。</param>
+        /// <param name="timeoutInSeconds">请求超时时间,单位为秒。应为正数;实现可以将其应用到 HTTP 客户端或请求级别超时。</param>
+        /// <returns>
+        /// 一个包含请求结果的元组:
+        /// IsSuccess 表示请求并解析 MES 响应是否被认为成功。
+        /// Response 为 MES 返回的原始响应字符串或描述错误的信息。
+        /// </returns>
+        /// <remarks>
+        /// - 此重载方便在不使用 <see cref="CancellationToken"/> 的场景中指定超时时间。
+        /// - 实现应验证 <paramref name="timeoutInSeconds"/> 为合理值(例如 > 0),否则可抛出 <see cref="ArgumentOutOfRangeException"/>。
+        /// </remarks>
+        Task<(bool IsSuccess, string Response)> StationGetAsync(string sn, string comp, double timeoutInSeconds);
+
         /// <summary>
         /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息。
         /// </summary>
@@ -74,6 +92,27 @@ namespace TeamAAS_VP.Interfaces
         /// </remarks>
         Task<(bool IsSuccess, string Response)> SubmitGetAsync(int deviceNo, string sn, string comp, string torque, string pressure, string turn, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
 
+        /// <summary>
+        /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息。
+        /// </summary>
+        /// <param name="sn">待提交的产品序列号,不能为空或空白。</param>
+        /// <param name="isSuccess">表示该序列号对应的过站是否成功(业务层面的成功标志)。</param>
+        /// <param name="start_time">过程开始时间(本地时间或 UTC,取决于与 MES 的约定)。实现方应按与 MES 约定的时区/格式发送。</param>
+        /// <param name="stop_time">过程结束时间,语义同 <paramref name="start_time"/>。</param>
+        /// <param name="cancellationToken">用于在外部请求取消时中止异步请求的 <see cref="CancellationToken"/>。默认值为 <see cref="CancellationToken.None"/>。</param>
+        /// <returns>
+        /// 一个包含请求结果的元组:
+        /// IsSuccess 表示提交请求及解析 MES 响应是否被认为成功。
+        /// Response 为 MES 返回的原始响应字符串或描述错误的信息。
+        /// </returns>
+        /// <remarks>
+        /// - 实现应将时间参数按 MES 要求格式化为查询字符串或适当的请求参数。
+        /// - 若 <paramref name="start_time"/> 晚于 <paramref name="stop_time"/>,实现应记录并视情况返回失败或抛出异常。
+        /// - 实现应尊重 <paramref name="cancellationToken"/>,并在取消时尽早中止请求。
+        /// </remarks>
+        Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string torque, string pressure, string turn, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default);
+
+
         /// <summary>
         /// 使用配置的提交(Submit)URL 发起 GET 请求,提交过站结果及时间信息,并使用指定的超时时间(秒)。
         /// </summary>

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

@@ -216,6 +216,36 @@ namespace TeamAAS_VP.Models
             set => SetProperty(ref _ScrewCurvePath, value);
         }
 
+        private bool _IsBasePartCodeGetSN = false;
+        /// <summary>
+        /// 是否基于零件码获取流程码
+        /// </summary>
+        public bool IsBasePartCodeGetSN
+        {
+            get { return _IsBasePartCodeGetSN; }
+            set { SetProperty(ref _IsBasePartCodeGetSN, value); }
+        }
+
+        private bool _IsBasePartCodeChooseScrew = false;
+        /// <summary>
+        /// 是否通过零件码判断螺丝型号
+        /// </summary>
+        public bool IsBasePartCodeChooseScrew
+        {
+            get { return _IsBasePartCodeChooseScrew; }
+            set { SetProperty(ref _IsBasePartCodeChooseScrew, value); }
+        }
+
+        private string _ChooseScrewModel = "***********abc123****";
+        /// <summary>
+        /// 螺丝型号判断,如******123**,*为忽略字符
+        /// </summary>
+        public string ChooseScrewModel
+        {
+            get { return _ChooseScrewModel; }
+            set { SetProperty(ref _ChooseScrewModel, value); }
+        }
+
         /// <summary>
         /// 字体大小子设置
         /// </summary>

+ 37 - 0
TeamAAS-VM/Services/ConfigService.cs

@@ -55,6 +55,7 @@ namespace TeamAAS_VP.Services
             public static readonly string CardReaderConfigurationPath = "..//Config//CardReaderConfiguration.cfg";
             // ��������·��
             public static readonly string TorqueReaderConfigurationPath = "..//Config//TorqueReaderConfiguration.cfg";
+            public static readonly string DataConfigurationPath = "..//Config//DataConfiguration.cfg";
         }
 
         private readonly object _sync = new object();
@@ -882,6 +883,42 @@ namespace TeamAAS_VP.Services
         public void SaveBgModbusTcp() { lock (_sync) { FileHelper.WriteJsonFile(BgModbusCommunicate, ConfigPaths.BgModbusTcpConfigurationPath); } }
         #endregion
 
+        #region CTQData
+        /// <summary>
+        /// 获取CTQ信息配置
+        /// </summary>
+        public CTQ_Data GetCTQDataInfo()
+        {
+            lock (_sync)
+            {
+                if (CtqData == null)
+                {
+                    if (File.Exists(ConfigPaths.DataConfigurationPath))
+                        CtqData = FileHelper.ReadJsonFile<CTQ_Data>(ConfigPaths.DataConfigurationPath);
+                    else
+                    {
+                        CtqData = new CTQ_Data();
+                        FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
+                    }
+                }
+                return CtqData;
+            }
+        }
+
+        /// <summary>
+        /// 保存CTQ信息
+        /// </summary>
+        public void SaveCTQDataInfo(CTQ_Data cd)
+        {
+            if (cd == null) return;
+            lock (_sync)
+            {
+                CtqData = cd;
+                FileHelper.WriteJsonFile(CtqData, ConfigPaths.DataConfigurationPath);
+            }
+        }
+        #endregion
+
         #region ϵͳ����
         /// <summary>
         /// ��ȡϵͳ���ã��������ļ���ȡ����

+ 288 - 0
TeamAAS-VM/Services/MesService.cs

@@ -149,6 +149,201 @@ namespace TeamAAS_VP.Services
             return result;
         }
 
+        public async Task<(bool IsSuccess, string Response)> StationGetExAsync(string sn, string comp, double timeoutInSeconds)
+        {
+            using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
+            {
+                return await StationGetExAsync(sn, comp, cts.Token);
+            }
+        }
+
+
+        /// <summary>
+        /// 向 MES 发起站点查询请求,使用超时(秒)作为便捷重载。
+        /// </summary>
+        /// <param name="sn">序列号(SN)。</param>
+        /// <param name="timeoutInSeconds">请求超时,单位为秒。</param>
+        /// <returns>与 <see cref="StationGetAsync(string, CancellationToken)"/> 相同的返回语义。</returns>
+        public async Task<(bool IsSuccess, string Response)> StationGetAsync(string sn, string comp, double timeoutInSeconds)
+        {
+            using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
+            {
+                return await StationGetAsync(sn, comp, cts.Token);
+            }
+        }
+
+        /// <summary>
+        /// 向配置中指定的 MES 站点 URL 发起 GET 请求(用于过站查询)。
+        /// </summary>
+        /// <param name="sn">要查询的序列号(SN)。</param>
+        /// <param name="cancellationToken">可选的取消令牌,用于请求超时或取消。</param>
+        /// <returns>
+        /// 返回元组 (IsSuccess, Response):
+        /// - IsSuccess: 请求是否视为成功(即 MES 返回了预期的 "SFC_OK" 且包含 "unit_process_check=OK")。
+        /// - Response: 原始响应文本或错误信息说明(如 "MES功能未启用!"、"Missing MES station URL"、"Canceled" 等)。
+        /// </returns>
+        /// <remarks>
+        /// 行为说明:
+        /// - 从配置获取设备信息,若 MES 未启用则直接返回 IsSuccess=true 且 Response 为提示文本(不视为错误)。
+        /// - 若未配置 MES URL 则返回 IsSuccess=false 与错误文本。
+        /// - 使用配置的 URL(通过 <see cref="string.Format"/> 填充 sn)发起 GET 请求,最多重试 10 次。
+        /// - 只有当响应包含 "SFC_OK" 且包含 "unit_process_check=OK" 时视为成功并立即返回。
+        /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
+        /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
+        /// </remarks>
+        public async Task<(bool IsSuccess, string Response)> StationGetExAsync(string sn, string comp, CancellationToken cancellationToken = default)
+        {
+            // 如果已经释放,则抛出异常,防止在已释放资源上继续操作。
+            if (_disposed) throw new ObjectDisposedException(nameof(MesService));
+
+            var device = _configService.GetDeviceInfo();
+            if (device == null || !device.EnableMES)
+            {
+                LogHelper.WriteLogMes($"MES功能未启用!");
+                SendTaskMessage($"MES功能未启用!", MessageLevel.Info);
+                return (false, "MES功能未启用!");
+            }
+            if (string.IsNullOrWhiteSpace(device.MesUrl))
+            {
+                LogHelper.WriteLogMes($"Missing MES station URL");
+                SendTaskMessage($"Missing MES station URL", MessageLevel.Info);
+                return (false, "Missing MES station URL");
+            }
+
+            string url = "";
+            url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&p=sn,message";
+
+            LogHelper.WriteLogMes($"【询问URL】{url}");
+            SendTaskMessage($"【询问URL】{url}", MessageLevel.Info);
+            (bool IsSuccess, string Response) result = (false, string.Empty);
+
+            for (int i = 0; i < 3; i++)
+            {
+                try
+                {
+                    using (var rsp = await _httpClient.GetAsync(url))
+                    {
+                        var text = await rsp.Content.ReadAsStringAsync();
+                        LogHelper.WriteLogMes($"【HTTP接收】{text}");
+                        SendTaskMessage($"【HTTP接收】{text}", MessageLevel.Info);
+
+                        // "SFC_OK" 代表和 MES 连接成功
+                        if (text.Contains("SFC_OK"))
+                        {
+                            if (text.Contains("message=OK"))
+                            {
+                                return (true, text);
+                            }
+                        }
+                        result = (false, text);
+                    }
+                }
+                catch (OperationCanceledException)
+                {
+                    result = (false, "Canceled");
+                }
+                catch (Exception ex)
+                {
+                    result = (false, ex.Message);
+                }
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 向配置中指定的 MES 站点 URL 发起 GET 请求(用于过站查询)。
+        /// </summary>
+        /// <param name="sn">要查询的序列号(SN)。</param>
+        /// <param name="cancellationToken">可选的取消令牌,用于请求超时或取消。</param>
+        /// <returns>
+        /// 返回元组 (IsSuccess, Response):
+        /// - IsSuccess: 请求是否视为成功(即 MES 返回了预期的 "SFC_OK" 且包含 "unit_process_check=OK")。
+        /// - Response: 原始响应文本或错误信息说明(如 "MES功能未启用!"、"Missing MES station URL"、"Canceled" 等)。
+        /// </returns>
+        /// <remarks>
+        /// 行为说明:
+        /// - 从配置获取设备信息,若 MES 未启用则直接返回 IsSuccess=true 且 Response 为提示文本(不视为错误)。
+        /// - 若未配置 MES URL 则返回 IsSuccess=false 与错误文本。
+        /// - 使用配置的 URL(通过 <see cref="string.Format"/> 填充 sn)发起 GET 请求,最多重试 10 次。
+        /// - 只有当响应包含 "SFC_OK" 且包含 "unit_process_check=OK" 时视为成功并立即返回。
+        /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
+        /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
+        /// </remarks>
+        public async Task<(bool IsSuccess, string Response)> StationGetAsync(string sn, string comp, CancellationToken cancellationToken = default)
+        {
+            // 如果已经释放,则抛出异常,防止在已释放资源上继续操作。
+            if (_disposed) throw new ObjectDisposedException(nameof(MesService));
+
+            var device = _configService.GetDeviceInfo();
+            if (device == null || !device.EnableMES)
+            {
+                LogHelper.WriteLogMes($"MES功能未启用!");
+                SendTaskMessage($"MES功能未启用!", MessageLevel.Info);
+                return (false, "MES功能未启用!");
+            }
+            if (string.IsNullOrWhiteSpace(device.MesUrl))
+            {
+                LogHelper.WriteLogMes($"Missing MES station URL");
+                SendTaskMessage($"Missing MES station URL", MessageLevel.Info);
+                return (false, "Missing MES station URL");
+            }
+            if (device.F == "PTL")
+            {
+                if (string.IsNullOrEmpty(device.comp))
+                {
+                    LogHelper.WriteLogMes($"PTL模式下comp不能为空");
+                    SendTaskMessage($"PTL模式下comp不能为空", MessageLevel.Info);
+                    return (false, "PTL模式下comp不能为空");
+                }
+            }
+
+            string url = "";
+            if (device.F == "PTL")
+            {
+                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&comp={device.comp}:{comp}&p=unit_process_check,message,model,sn,wo";
+            }
+            else
+            {
+                url = $"{device.MesUrl}?c=QUERY_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&p=unit_process_check,message,model,sn,wo";
+            }
+
+            LogHelper.WriteLogMes($"【询问URL】{url}");
+            SendTaskMessage($"【询问URL】{url}", MessageLevel.Info);
+            (bool IsSuccess, string Response) result = (false, string.Empty);
+
+            for (int i = 0; i < 3; i++)
+            {
+                try
+                {
+                    using (var rsp = await _httpClient.GetAsync(url))
+                    {
+                        var text = await rsp.Content.ReadAsStringAsync();
+                        LogHelper.WriteLogMes($"【HTTP接收】{text}");
+                        SendTaskMessage($"【HTTP接收】{text}", MessageLevel.Info);
+
+                        // "SFC_OK" 代表和 MES 连接成功
+                        if (text.Contains("SFC_OK"))
+                        {
+                            if (text.Contains("message=OK"))
+                            {
+                                return (true, text);
+                            }
+                        }
+                        result = (false, text);
+                    }
+                }
+                catch (OperationCanceledException)
+                {
+                    result = (false, "Canceled");
+                }
+                catch (Exception ex)
+                {
+                    result = (false, ex.Message);
+                }
+            }
+            return result;
+        }
+
         /// <summary>
         /// 向配置中指定的 MES 站点 URL 发起 GET 请求(用于过站查询)。
         /// </summary>
@@ -341,6 +536,99 @@ namespace TeamAAS_VP.Services
             return result;
         }
 
+        /// <summary>
+        /// 向配置中指定的 MES 提交 URL 发起 GET 请求(用于提交测试结果/记录)。
+        /// </summary>
+        /// <param name="sn">要提交的序列号(SN)。</param>
+        /// <param name="isSuccess">表示此次记录是否通过(true => PASS,false => FAIL)。</param>
+        /// <param name="start_time">开始时间,提交时使用 "yyyy-MM-dd HH:mm:ss" 格式。</param>
+        /// <param name="stop_time">结束时间,提交时使用 "yyyy-MM-dd HH:mm:ss" 格式。</param>
+        /// <param name="cancellationToken">可选的取消令牌,用于请求超时或取消。</param>
+        /// <returns>
+        /// 返回元组 (IsSuccess, Response):
+        /// - IsSuccess: 提交是否被 MES 视为成功(收到 "SFC_OK" 且响应中无额外多行信息)。
+        /// - Response: MES 返回文本或错误说明;当 MES 返回 "SFC_OK" 但包含额外多行信息(代表 SN 数据问题)时,IsSuccess 为 false 且 Response 为该文本。
+        /// </returns>
+        /// <remarks>
+        /// 行为说明:
+        /// - 从配置获取设备信息,若 MES 未启用则直接返回 IsSuccess=true 且 Response 为提示文本(不视为错误)。
+        /// - 若未配置 MES 提交 URL 则返回 IsSuccess=false 与错误文本。
+        /// - 使用配置的 URL(通过 <see cref="string.Format"/> 按顺序填充 sn、PASS/FAIL、start_time、stop_time)发起 GET 请求,最多重试 10 次。
+        /// - 在收到包含 "SFC_OK" 的响应时,如果返回文本包含多行(有附加信息)则视为提交失败并返回该文本,否则视为提交成功。
+        /// - 捕获 <see cref="OperationCanceledException"/> 返回 "Canceled",捕获其它异常则返回异常消息。
+        /// - 若实例已被释放则抛出 <see cref="ObjectDisposedException"/>。
+        /// </remarks>
+        public async Task<(bool IsSuccess, string Response)> SubmitGetAsync(string sn, string comp, string torque, string pressure, string turn, bool isSuccess, DateTime start_time, DateTime stop_time, CancellationToken cancellationToken = default)
+        {
+            // 如果已经释放,则抛出异常,防止在已释放资源上继续操作。
+            if (_disposed) throw new ObjectDisposedException(nameof(MesService));
+
+            var device = _configService.GetDeviceInfo();
+            if (device == null || !device.EnableMES)
+            {
+                return (true, "MES功能未启用!");
+            }
+            if (string.IsNullOrWhiteSpace(device.MesUrl))
+                return (false, "Missing MES submit URL");
+            if (device.F == "PTL")
+            {
+                if (string.IsNullOrEmpty(device.comp))
+                {
+                    return (false, "PTL模式下comp不能为空");
+                }
+            }
+
+            //string res = isSuccess ? "PASS" : "FAIL";
+            string res = "PASS";
+            string url = "";
+            if (device.F == "PTL")
+            {
+                url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PTL&comp={device.comp}:{comp}" +
+                    $"&torque={torque}&pressure={pressure}&turn={turn}&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
+            }
+            else
+            {
+                url = $"{device.MesUrl}?c=ADD_RECORD&line={device.Line}&station={device.Station}&fixtureid={device.FixtureId}&sn={sn}&f=PQC" +
+                    $"&torque={torque}&pressure={pressure}&turn={turn}&result={res}&start_time={start_time.ToString("yyyy-MM-dd HH:mm:ss")}&stop_time={stop_time.ToString("yyyy-MM-dd HH:mm:ss")}";
+            }
+            LogHelper.WriteLogMes($"【上传URL】{url}");
+            SendTaskMessage($"【上传URL】{url}", MessageLevel.Info);
+            (bool IsSuccess, string Response) result = (false, string.Empty);
+
+            for (int i = 0; i < 3; i++)
+            {
+                try
+                {
+                    using (var rsp = await _httpClient.GetAsync(url, cancellationToken))
+                    {
+                        var text = await rsp.Content.ReadAsStringAsync();
+                        LogHelper.WriteLogMes($"【HTTP接收】{text}");
+                        SendTaskMessage($"【HTTP接收】{text}", MessageLevel.Info);
+                        // "SFC_OK" 代表和 MES 连接成功
+                        if (text.Contains("SFC_OK"))
+                        {
+                            // 如果有附加信息(多行),代表此 SN 数据有问题,视为失败并返回该文本
+                            if (text.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Length > 1)
+                            {
+                                return (false, text);
+                            }
+                            return (true, text);
+                        }
+                        result = (false, text);
+                    }
+                }
+                catch (OperationCanceledException)
+                {
+                    result = (false, "Canceled");
+                }
+                catch (Exception ex)
+                {
+                    result = (false, ex.Message);
+                }
+            }
+            return result;
+        }
+
         /// <summary>
         /// 向 MES 提交请求的超时重载,使用超时(秒)作为便捷参数。
         /// </summary>

+ 7 - 3
TeamAAS-VM/Services/RemoteCommandService.cs

@@ -1956,11 +1956,15 @@ namespace TeamAAS_VP.Services
                 }
                 //获取当前的产品SN
                 string productSN = _productService.CurrentProductCode;
-                //如果产品SN存在非法字符,则替换为下划线
-                foreach (char c in System.IO.Path.GetInvalidFileNameChars())
+                if (!string.IsNullOrEmpty(productSN))
                 {
-                    productSN = productSN.Replace(c, '_');
+                    //如果产品SN存在非法字符,则替换为下划线
+                    foreach (char c in System.IO.Path.GetInvalidFileNameChars())
+                    {
+                        productSN = productSN.Replace(c, '_');
+                    }
                 }
+
                 //当前用户
                 string currentUser = _systemDatabaseService.GetCurrentUser()?.UserName;
 

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

@@ -1467,6 +1467,9 @@ namespace TeamAAS_VP.ViewModels
                 ScrewTeachNum = sys.ScrewTeachNum;
                 IsSaveScrewCurve = sys.IsSaveScrewCurve;
                 ScrewCurvePath = sys.ScrewCurvePath;
+                IsBasePartCodeGetSN = sys.IsBasePartCodeGetSN;
+                IsBasePartCodeChooseScrew = sys.IsBasePartCodeChooseScrew;
+                ChooseScrewModel = sys.ChooseScrewModel;
             }
 
             if (isFirstLoad)
@@ -1529,6 +1532,36 @@ namespace TeamAAS_VP.ViewModels
         }
 
         #region 系统参数
+        private bool _IsBasePartCodeGetSN;
+        /// <summary>
+        /// 是否基于零件码获取流程码
+        /// </summary>
+        public bool IsBasePartCodeGetSN
+        {
+            get { return _IsBasePartCodeGetSN; }
+            set { SetProperty(ref _IsBasePartCodeGetSN, value); }
+        }
+
+        private bool _IsBasePartCodeChooseScrew;
+        /// <summary>
+        /// 是否通过零件码判断螺丝型号
+        /// </summary>
+        public bool IsBasePartCodeChooseScrew
+        {
+            get { return _IsBasePartCodeChooseScrew; }
+            set { SetProperty(ref _IsBasePartCodeChooseScrew, value); }
+        }
+
+        private string _ChooseScrewModel;
+        /// <summary>
+        /// 螺丝型号判断,如******123**,*为忽略字符
+        /// </summary>
+        public string ChooseScrewModel
+        {
+            get { return _ChooseScrewModel; }
+            set { SetProperty(ref _ChooseScrewModel, value); }
+        }
+
         private Int16 _WorkMode = 0;
         /// <summary>
         /// 工作模式 =1 拍1打1 =2 拍1打所有
@@ -1698,6 +1731,9 @@ namespace TeamAAS_VP.ViewModels
                     sysConfig.ScrewTeachNum = ScrewTeachNum;
                     sysConfig.IsSaveScrewCurve = IsSaveScrewCurve;
                     sysConfig.ScrewCurvePath = ScrewCurvePath;
+                    sysConfig.IsBasePartCodeGetSN = IsBasePartCodeGetSN;
+                    sysConfig.IsBasePartCodeChooseScrew = IsBasePartCodeChooseScrew;
+                    sysConfig.ChooseScrewModel = ChooseScrewModel;
 
                     _configService.SaveSystemConfiguration(sysConfig);
                     await management.WriteSystemParameterToPlcAsync(sysConfig);

+ 23 - 69
TeamAAS-VM/Views/Home/ShowVisionRender.xaml.cs

@@ -82,64 +82,26 @@ namespace TeamAAS_VP.Views.Home
                 {
                     if (item.Value?.Child is CogRecordDisplay disp)
                     {
-                        ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Record = null;
-                        ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Image = render.Image;
-                        ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).StaticGraphics.Clear();
-                        if (render.Graphic != null)
-                            ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).StaticGraphics.AddList(render.Graphic, "");
-
-                        if (render.Record != null)
-                            ((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).Record = render.Record;
-                        if (render.IsSaveImage)
+                        // 通过 Tag(产品名) 匹配当前需要更新的窗口
+                        if (disp.Tag != null && disp.Tag.ToString() == render.ProceductName)
                         {
-                            SaveImage(render.SaveImageModel, render.SaveImagePathModel, render.SavePath, render.Image, (Bitmap)((Cognex.VisionPro.CogRecordDisplay)item.Value.Child).CreateContentBitmap(Cognex.VisionPro.Display.CogDisplayContentBitmapConstants.Custom), render.Result, render.IsCompress, render.ImgPara, render.ImageFileName);
-                        }
-                        break;
-                    }
-                }
-                /*
-                foreach (var item in gridRender.Children)
-                {
-                    if (item is WindowsFormsHost && ((WindowsFormsHost)item).Child is Cognex.VisionPro.CogRecordDisplay)
-                    {
-                        if (((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).Tag != null && ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).Tag.ToString() == render.CameraName)
-                        {
-                            ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).Image = render.Image;
-                            ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).StaticGraphics.Clear();
-                            ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).StaticGraphics.AddList(render.Graphic, "");
+                            disp.Record = null;
+                            disp.Image = render.Image;
+
+                            disp.StaticGraphics.Clear();
+                            if (render.Graphic != null)
+                                disp.StaticGraphics.AddList(render.Graphic, "");
+
                             if (render.Record != null)
-                                ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).Record = render.Record;
-                            if (render.IsSaveImage)
-                            {
-                                SaveImage(render.SaveImageModel, render.SaveImagePathModel, render.SavePath, render.Image, (Bitmap)((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).CreateContentBitmap(Cognex.VisionPro.Display.CogDisplayContentBitmapConstants.Custom), render.Result, render.IsCompress);
-                            }
+                                disp.Record = render.Record;
+
+                            // ======================= 【关键优化】保存图像走安全入口 =======================
+                            RequestSaveImage(render, disp);
+
                             break;
                         }
                     }
-                    else if (item is Grid)
-                    {
-                        foreach (var item1 in ((Grid)item).Children)
-                        {
-                            if (item1 is WindowsFormsHost && ((WindowsFormsHost)item1).Child is Cognex.VisionPro.CogRecordDisplay)
-                            {
-                                if (((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item1).Child).Tag != null && ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item1).Child).Tag.ToString() == render.CameraName)
-                                {
-                                    ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item1).Child).Image = render.Image;
-                                    ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item1).Child).StaticGraphics.Clear();
-                                    ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item1).Child).StaticGraphics.AddList(render.Graphic, "");
-                                    if (render.Record != null)
-                                        ((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).Record = render.Record;
-                                    if (render.IsSaveImage)
-                                    {
-                                        SaveImage(render.SaveImageModel, render.SaveImagePathModel, render.SavePath, render.Image, (Bitmap)((Cognex.VisionPro.CogRecordDisplay)((WindowsFormsHost)item).Child).CreateContentBitmap(Cognex.VisionPro.Display.CogDisplayContentBitmapConstants.Custom), render.Result, render.IsCompress);
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-                        break;
-                    }
-                }*/
+                }
             }));
         }
 
@@ -354,7 +316,6 @@ namespace TeamAAS_VP.Views.Home
                                 clonedBitmap,
                                 render.Result,
                                 render.IsCompress,
-                                render.ImgPara,
                                 render.ImageFileName
                             );
                         }
@@ -369,18 +330,18 @@ namespace TeamAAS_VP.Views.Home
                         finally
                         {
                             // 确保释放 Clone 的 Bitmap,避免 GDI 泄漏导致闪退
-                            try { clonedBitmap?.Dispose(); } catch { }
+                            //try { clonedBitmap?.Dispose(); } catch { }
                             _saveSemaphore.Release();
                         }
                     }, token);
                 }
                 catch (OperationCanceledException)
                 {
-                    try { clonedBitmap?.Dispose(); } catch { }
+                    //try { clonedBitmap?.Dispose(); } catch { }
                 }
                 catch (Exception ex)
                 {
-                    try { clonedBitmap?.Dispose(); } catch { }
+                    //try { clonedBitmap?.Dispose(); } catch { }
                     LogHelper.WriteLogError("RequestSaveImage(UI截图阶段) 出错!", ex);
                 }
             }));
@@ -389,14 +350,7 @@ namespace TeamAAS_VP.Views.Home
         /// <summary>
         /// 保存图像(保持你原有逻辑不变,补充 Dispose 兜底,防止压缩分支不释放导致闪退)
         /// </summary>
-        /// <param name="saveImageModel">要保存图像的模式</param>
-        /// <param name="saveImagePathModel">图像保存路径类型</param>
-        /// <param name="path">保存图像的文件夹路径</param>
-        /// <param name="image">原图像</param>
-        /// <param name="reimage">渲染图像</param>
-        /// <param name="result">拍照结果</param>
-        /// <param name="isCompress">是否压缩</param>
-        private void SaveImage(ProcedureSaveImageModel saveImageModel, ProcedureSaveImagePathModel saveImagePathModel, string path, ICogImage image, Bitmap reimage, bool result, bool isCompress, ImageParameters imgPara, string imageFileName)
+        private void SaveImage(ProcedureSaveImageModel saveImageModel, ProcedureSaveImagePathModel saveImagePathModel, string path, ICogImage image, Bitmap reimage, bool result, bool isCompress, string imageFileName)
         {
             if (string.IsNullOrEmpty(path) || string.IsNullOrWhiteSpace(path) || !Path.IsPathRooted(path))
             {
@@ -454,7 +408,7 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
+                            Originalpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{productSN}\\{resultStr}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))
@@ -502,7 +456,7 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
+                            Recordedpath = $"{path}\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{productSN}\\{resultStr}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Recordedpath)))
@@ -570,8 +524,8 @@ namespace TeamAAS_VP.Views.Home
                                 productSN = productSN.Replace(c, '_');
 
                             string resultStr = result ? "OK" : "NG";
-                            Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
-                            Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{resultStr}\\{productSN}\\{imgName}.bmp";
+                            Originalpath = $"{path}\\Original\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{productSN}\\{resultStr}\\{imgName}.bmp";
+                            Recordedpath = $"{path}\\Recored\\{now:yyyy-MM}\\{now:MM-dd}\\{formulaName}\\{productSN}\\{resultStr}\\{imgName}.bmp";
                         }
 
                         if (!Directory.Exists(Path.GetDirectoryName(Originalpath)))

+ 25 - 1
TeamAAS-VM/Views/SettingView.xaml

@@ -2468,6 +2468,8 @@
                             <RowDefinition Height="Auto" />
                             <RowDefinition Height="Auto" />
                             <RowDefinition Height="Auto" />
+                            <RowDefinition Height="Auto" />
+                            <RowDefinition Height="Auto" />
                         </Grid.RowDefinitions>
 
                         <!-- 相机拍照次数 -->
@@ -2667,7 +2669,29 @@
 
 
                         </StackPanel>
-                        <Button Grid.Row="11"
+                        <!-- 扫码模式选择 -->
+                        <StackPanel Grid.Row="11"
+                                Grid.ColumnSpan="2"
+                                Orientation="Horizontal"
+                                HorizontalAlignment="Left"
+                                VerticalAlignment="Center"
+                                Margin="5">
+                            <CheckBox IsChecked="{Binding IsBasePartCodeGetSN,Mode=TwoWay}"
+                                VerticalAlignment="Center"
+                                HorizontalAlignment="Right"
+                                FontSize="{DynamicResource Font.Size.Body3}"
+                                Margin="0,0,6,0">是否基于零件码获取流程码</CheckBox>
+                            <CheckBox IsChecked="{Binding IsBasePartCodeChooseScrew,Mode=TwoWay}"
+                                VerticalAlignment="Center"
+                                HorizontalAlignment="Right"
+                                FontSize="{DynamicResource Font.Size.Body3}"
+                                Margin="0,0,6,0">是否通过零件码判断螺丝型号</CheckBox>
+                            <TextBox MinWidth="300"
+                                Text="{Binding ChooseScrewModel,Mode=TwoWay}"
+                                ToolTip="螺丝型号判断,如******123**,*为忽略字符"/>
+
+                        </StackPanel>
+                        <Button Grid.Row="12"
                                 Grid.Column="1"
                                 Margin="0,6"
                                 Style="{StaticResource MaterialDesignRaisedButton}"