quanzhou
2 天以前 86f899fa91e811415614dff1a699141144bfc802
src/Bro.M141.Process/M141Process_ImageCheck.cs
@@ -2,15 +2,23 @@
using Bro.Common.Helper;
using Bro.Common.Interface;
using Bro.Common.Model;
using Bro.DataBase.Model;
using Bro.M135.Common;
using Bro.M135.DBManager;
using Bro.UI.Model.Winform;
using HalconDotNet;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.Util;
using NPOI.XSSF.UserModel;
using Sunny.UI;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;
@@ -20,6 +28,7 @@
using static System.Net.Mime.MediaTypeNames;
using static System.Net.WebRequestMethods;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Tab;
using File = System.IO.File;
namespace Bro.M141.Process
{
@@ -28,6 +37,9 @@
        Dictionary<string, List<double>> dicdate = new Dictionary<string, List<double>>();
        ManualResetEvent set1 = new ManualResetEvent(false);
        ManualResetEvent set2 = new ManualResetEvent(false);
        [ProcessMethod("ImageCheck", "ImageCheckOperation", "通用图片检测操作", InvokeType.TestInvoke)]
        public ResponseMessage ImageCheckOperation(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
@@ -436,11 +448,14 @@
        }
        [ProcessMethod("", "ProductDataUpload", "产品数据汇总", InvokeType.TestInvoke)]
        public ResponseMessage ProductDataUpload(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
        {
            ResponseMessage msg = new ResponseMessage();
            string inputSequence = Plc1.Read(1536, 1, out _)[0].ToString();
            int numplca = Plc1.Read(1536, 1, out _)[0];
            string inputSequence = numplca.ToString();
            var productList = new List<int>() { 1 }.Select(u =>
            {
@@ -448,6 +463,10 @@
                return FindProductBySequence(sequence, true);
            }).ToList();
            if (PlcNumForAll == -1)
            {
                PlcNumForAll = numplca;
            }
            int waitInterval = 300;
            int repeatTime = M141Config.DetectTimeout / waitInterval;
@@ -472,30 +491,591 @@
            } while (true);
            var Defaultclass = M141Config.DefectClassCollection.FirstOrDefault(u => u.IsDefault);
            productList.ForEach(p =>
            var Defaultclass = M141Config.DefectClassCollection.FirstOrDefault(u => u.ClassName == productList[0].Result);
            if (M141Config.StationCode == "S4" && productList[0].Result == "OK")
            {
                if (Defaultclass == null)
                ////mysqlhelper.GetS2Result(productList[0].SEQUENCE);
                Plc1.WriteSingleAddress(1526, mysqlhelper.GetS2Result(productList[0].SEQUENCE) ? 1 : 2, out _);
                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{string.Join(",", productList.Select(u => u.PID))}检测反馈{mysqlhelper.GetS2Result(productList[0].SEQUENCE)}");
            }
            else
            {
                Plc1.WriteSingleAddress(1526, Defaultclass?.ClassValue ?? 2, out _);
            }
            Plc1.WriteSingleAddress(1516, 1, out _);
            //if (M141Config.ISupMES && (M141Config.MESchannel == -1 || M141Config.MESchannel == 1))
            //{
            //    if (M141Config.numpro >= 50)
            //    {
            //        M141Config.numpro = 0;
            //    }
            //    if (productList[0].Result == "OK")
            //    {
            //        M141Config.numpro++;
            //    }
            //    //mqtt.demes(productList[0], M141Config.zwoid);
            //    string Msgreceice = Task.Run(() => mqtt.MESForProduceAsync(productList[0], M141Config.zwoid, M141Config.numpro)).Result;
            //    if (Msgreceice == null)
            //    {
            //        LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{productList[0].PID}数据上传MES异常 返回数据为null");
            //    }
            //    else
            //    {
            //        try
            //        {
            //            var obj = JsonConvert.DeserializeObject<AutoLineMacBarcodeQueueBak>(Msgreceice);
            //            if (obj.zstatus == "200")
            //            {
            //                LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{productList[0].PID}数据上传MES成功  {Msgreceice}");
            //            }
            //            else
            //            {
            //                LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{productList[0].PID}数据上传MES失败  {Msgreceice}");
            //            }
            //        }
            //        catch
            //        {
            //            LogAsync(DateTime.Now, EnumHelper.LogLevel.Exception, $"产品{productList[0].PID}数据上传MES异常  {Msgreceice}");
            //        }
            //    }
            //    lock (plcnumlock)
            //    {
            //        int differ = numplca - PlcNumForAll;
            //        if (differ > 1)
            //        {
            //            for (int i = PlcNumForAll + 1; i < numplca; i++)
            //            {
            //                try
            //                {
            //                    var plist = mysqlhelper.GetProductList(i + "_1");
            //                    ProductModel newp = new ProductModel();
            //                    newp.SEQUENCE = plist[0].SEQUENCE;
            //                    newp.PID = plist[0].PID;
            //                    newp.BasketCode = plist[0].BasketCode;
            //                    newp.Result = "NG";
            //                    newp.SN = plist[0].SN;
            //                    var tems = Task.Run(() => mqtt.MESForProduceAsync(newp, M141Config.zwoid, M141Config.numpro)).Result;
            //                }
            //                catch
            //                {
            //                }
            //            }
            //        }
            //        else if (differ != -29998)
            //        {
            //            for (int i = PlcNumForAll + 1; i <= 29999; i++)
            //            {
            //                try
            //                {
            //                    var plist = mysqlhelper.GetProductList(i + "_1");
            //                    ProductModel newp = new ProductModel();
            //                    newp.SEQUENCE = plist[0].SEQUENCE;
            //                    newp.PID = plist[0].PID;
            //                    newp.BasketCode = plist[0].BasketCode;
            //                    newp.Result = "NG";
            //                    newp.SN = plist[0].SN;
            //                    var tems = Task.Run(() => mqtt.MESForProduceAsync(newp, M141Config.zwoid, M141Config.numpro)).Result;
            //                }
            //                catch
            //                {
            //                }
            //            }
            //            for (int i = 1; i < numplca; i++)
            //            {
            //                try
            //                {
            //                    var plist = mysqlhelper.GetProductList(i + "_1");
            //                    ProductModel newp = new ProductModel();
            //                    newp.SEQUENCE = plist[0].SEQUENCE;
            //                    newp.PID = plist[0].PID;
            //                    newp.BasketCode = plist[0].BasketCode;
            //                    newp.Result = "NG";
            //                    newp.SN = plist[0].SN;
            //                    var tems = Task.Run(() => mqtt.MESForProduceAsync(newp, M141Config.zwoid, M141Config.numpro)).Result;
            //                }
            //                catch
            //                {
            //                }
            //            }
            //        }
            //        PlcNumForAll = numplca;
            //    }
            //}
            return msg;
        }
        object plcnumlock = new object();
        int PlcNumForAll = -1;
        private bool _isDemoStarted = false;
        [ProcessMethod("OfflineDemo", "OfflineDemo", "离线测试", InvokeType.CalibInvoke)]
        public ResponseMessage OfflineDemo(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
        {
            if (config is OfflineDemoOperationConfig opConfig)
            {
                if (_isDemoStarted)
                {
                    if (string.IsNullOrEmpty(p.Result))
                    _isDemoStarted = false;
                }
                else
                {
                    _isDemoStarted = true;
                    OfflineDemoAsync(opConfig.ImageFolder, opConfig.IsOK, opConfig.SaveImageTime);
                }
            }
            return new ResponseMessage();
        }
        private async void OfflineDemoAsync(string imageFolder, bool isok, int saveimagetime)
        {
            await Task.Run(() =>
            {
                var imageFileNames = new DirectoryInfo(imageFolder).GetFiles().Select(u => u.FullName).ToList();
                for (int i = 0; i < imageFileNames.Count; i++)
                {
                    if (!_isDemoStarted)
                    {
                        p.Result = "NG";
                        return;
                    }
                    var imageFile = Path.GetFileNameWithoutExtension(imageFileNames[i]);
                    if (imageFile.EndsWith("Fit"))
                    {
                        continue;
                    }
                    if (imageFile.EndsWith("OK") & isok == false)
                    {
                        continue;
                    }
                    if (imageFile.EndsWith("NG") & isok == true)
                    {
                        continue;
                    }
                    var nameDatas = imageFile.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                    if (nameDatas.Count != 5)
                    {
                        LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"文件{imageFile}命名不符合规范,不执行离线测试");
                        continue;
                    }
                    var sn = nameDatas[0] + "_1";
                    var imageSeq = nameDatas[2][^1].ToString();
                    var measureBind = M141Config.MeasureBindCollection.FirstOrDefault(u => u.ImageSaveSeq == imageSeq);
                    if (measureBind == null || !measureBind.IsFixed)
                    {
                        LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"离线测试,工位{(measureBind == null ? "未匹配" : $"{measureBind.WorkPosition}未开启")}");
                        continue;
                    }
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"离线测试,产品{sn}开始工位{measureBind.WorkPosition}离线检测");
                    MLImageSet imgSet = new MLImageSet();
                    imgSet.HImage = new HalconDotNet.HImage(imageFileNames[i]);
                    imgSet.PID = sn;
                    var detectResults = ML.RunMLDetectionSync(imgSet, null, measureBind.DetectionId);
                    Thread.Sleep(saveimagetime);
                    imgSet.HImage?.Dispose();
                    imgSet.HImage = null;
                    Bitmap originImage = new Bitmap(imageFileNames[i]);
                    DetectResultSaveExcelAsync(detectResults, sn, originImage, DateTime.Now);
                }
            });
        }
        object _excelOpLock = new object();
        int _columnWidth = 0;
        int _columnWidth1 = 0;
        int _exportNum = 0;
        public async void DetectResultSaveExcelAsync(List<DetectResult> detectResults, string sn, Bitmap originImage, DateTime dt)
        {
            await Task.Run(() =>
            {
                if (detectResults.All(u => u.ResultState == EnumHelper.ResultState.OK))
                    return;
                try
                {
                    string excel_Path = Path.Combine(CSVHelper.BaseDirectory, $"{DateTime.Now.ToString("yyyyMMdd")}");
                    if (!Directory.Exists(excel_Path))//如果不存在就创建file文件夹
                    {
                        Directory.CreateDirectory(excel_Path);//创建该文件夹
                    }
                    excel_Path = Path.Combine(excel_Path, $"OfflineRecord_{DateTime.Now.ToString("yyyyMMdd")}.xlsx");
                    List<string> datas = new List<string>() { "检测时间", "SN", "缺陷名称", "位置", "缺陷面积", "实际面积", "缺陷截图1", "缺陷截图2" };
                    NPOI.SS.UserModel.IRow irow;
                    NPOI.SS.UserModel.ICell icell;
                    Interlocked.Increment(ref _exportNum);
                    lock (_excelOpLock)
                    {
                        if (!File.Exists(excel_Path))
                        {
                            XSSFWorkbook wb = new XSSFWorkbook();
                            ISheet sheet = wb.CreateSheet("DefectDetail");
                            irow = sheet.CreateRow(0);
                            for (int i = 0; i < datas.Count; i++)
                            {
                                icell = irow.CreateCell(i);
                                icell.SetCellValue(datas[i]);
                            }
                            FileStream fs = new FileStream(excel_Path, FileMode.OpenOrCreate, FileAccess.Write);
                            wb.Write(fs); fs.Close();
                            fs.Dispose();
                        }
                        using (FileStream newfs = new FileStream(excel_Path, FileMode.Open, FileAccess.ReadWrite))
                        {
                            //创建工作簿对象
                            XSSFWorkbook newwb = new XSSFWorkbook(newfs);
                            //根据工作表名获取工作簿对象,也可通过索引获取工作表wb.GetSheetAt(int index)
                            ISheet newsheet = newwb.GetSheet("DefectDetail");
                            int countrow = newsheet.LastRowNum + 1;
                            //ICellStyle hlink_style = newwb.CreateCellStyle();
                            //IFont hlink_font = newwb.CreateFont();
                            //hlink_font.Underline = FontUnderlineType.Single;
                            //hlink_font.Color = HSSFColor.Blue.Index;
                            //hlink_style.SetFont(hlink_font);
                            XSSFDrawing patriarchDefectImageFile = (XSSFDrawing)newsheet.CreateDrawingPatriarch();
                            var details = detectResults.SelectMany(u => u.NetResults).SelectMany(u => u.DetectDetails).Where(u => u.FinalResult != EnumHelper.ResultState.OK).ToList();
                            details.ForEach(d =>
                            {
                                //"检测时间", "SN", "缺陷名称", "位置", "缺陷面积", "实际面积", "缺陷截图1", "缺陷截图2"
                                List<string> data = new List<string>() { dt.ToString("HH:mm:ss.fff").ToString(), sn, d.ClassName, (d.Tag ?? "").ToString(), d.Area.ToString(), d.AreaInActual.ToString("f3") };
                                irow = newsheet.CreateRow(countrow);
                                for (int i = 0; i < datas.Count; i++)
                                {
                                    icell = irow.CreateCell(i);
                                    switch (i)
                                    {
                                        case 6:
                                            {
                                                byte[] bytesDefectImageFile = CaptureImage(originImage, (int)d.Rect.Width, (int)d.Rect.Height, (int)d.Rect.X, (int)d.Rect.Y, out int actWidth, out int actHeight);
                                                int pictureIdxDefectImageFile = newwb.AddPicture(bytesDefectImageFile, NPOI.SS.UserModel.PictureType.JPEG);
                                                // 插图片的位置  HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2) 后面再作解释
                                                XSSFClientAnchor anchorDefectImageFile = new XSSFClientAnchor(1, 1, 1, 1, i, countrow, i + 1, countrow + 1);
                                                //把图片插到相应的位置
                                                XSSFPicture pictDefectImageFile = (XSSFPicture)patriarchDefectImageFile.CreatePicture(anchorDefectImageFile, pictureIdxDefectImageFile);
                                                ////int colWidth = actWidth * 32;
                                                ////if (colWidth > _columnWidth)
                                                ////{
                                                ////    _columnWidth = colWidth;
                                                ////    newsheet.SetColumnWidth(i, _columnWidth);
                                                ////}
                                                irow.Height = (short)(actHeight * 16);
                                                //pictDefectImageFile.Resize();
                                            }
                                            break;
                                        case 7:
                                            {
                                                byte[] bytesDefectImageFile = CaptureImage(originImage, (int)d.Rect.Width, (int)d.Rect.Height, (int)d.Rect.X, (int)d.Rect.Y, out int actWidth, out int actHeight, d);
                                                int pictureIdxDefectImageFile = newwb.AddPicture(bytesDefectImageFile, NPOI.SS.UserModel.PictureType.JPEG);
                                                XSSFClientAnchor anchorDefectImageFile = new XSSFClientAnchor(1, 1, 1, 1, i, countrow, i + 5, countrow + 1);
                                                //把图片插到相应的位置
                                                XSSFPicture pictDefectImageFile = (XSSFPicture)patriarchDefectImageFile.CreatePicture(anchorDefectImageFile, pictureIdxDefectImageFile);
                                                //int colWidth = actWidth * 32;
                                                //if (colWidth > _columnWidth1)
                                                //{
                                                //    _columnWidth1 = colWidth;
                                                //    newsheet.SetColumnWidth(i, _columnWidth1);
                                                //}
                                                //pictDefectImageFile.Resize();
                                            }
                                            break;
                                        default:
                                            string strvalue = data[i];
                                            icell.SetCellValue(strvalue);
                                            break;
                                    }
                                }
                                countrow++;
                            });
                            using (var temp = File.OpenWrite(excel_Path))
                            {
                                newwb.Write(temp);//向打开的这个xls文件中写入数据
                            }
                            newfs.Close();
                            newfs.Dispose();
                        }
                    }
                    Interlocked.Decrement(ref _exportNum);
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Action, $"{detectResults[0].PID}Excel输出完成,还有{_exportNum}条记录");
                }
                catch (Exception ex)
                {
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Error, $"{detectResults[0].PID}缺陷插入Excel报错:{ex.Message.ToString()}");
                }
                finally
                {
                    originImage.Dispose();
                    originImage = null;
                }
            });
        }
        int _spaceRemain = 60;
        //public byte[] CaptureImage(Bitmap originImage, int width, int height, int spaceX, int spaceY, out int actWidth, out int actHeight, DefectDetail defect = null)
        //{
        //    spaceX -= _spaceRemain;
        //    spaceY -= _spaceRemain;
        //    width += _spaceRemain * 2;
        //    height += _spaceRemain * 2;
        //    if (spaceX < 0)
        //    {
        //        spaceX = 0;
        //    }
        //    if (spaceY < 0)
        //    {
        //        spaceY = 0;
        //    }
        //    if (spaceX + width > originImage.Width)
        //    {
        //        width = originImage.Width - spaceX;
        //    }
        //    if (spaceY + height > originImage.Height)
        //    {
        //        height = originImage.Height - spaceY;
        //    }
        //    actHeight = height;
        //    actWidth = width;
        //    Bitmap imageBack = originImage;
        //    if (defect != null)
        //    {
        //        PolygonResultDisplay display = new PolygonResultDisplay(defect, defect.ClassName, Color.Red, false, (int)(width * GlobalVar.WIDTH_RATIO));
        //        imageBack = new Bitmap(originImage.Width, originImage.Height, PixelFormat.Format24bppRgb);
        //        using (Graphics g = Graphics.FromImage(imageBack))
        //        {
        //            g.DrawImage(originImage, 0, 0);
        //            display.Draw(g);
        //        }
        //    }
        //    //创建新图位图
        //    Bitmap bitmap = new Bitmap(width, height, imageBack.PixelFormat);
        //    //创建作图区域
        //    using (Graphics graphic = Graphics.FromImage(bitmap))
        //    {
        //        //截取原图相应区域写入作图区
        //        graphic.DrawImage(imageBack, 0, 0, new Rectangle(spaceX, spaceY, width, height), GraphicsUnit.Pixel);
        //    }
        //    byte[] bt = null;
        //    using (MemoryStream mostream = new MemoryStream())
        //    {
        //        bitmap.Save(mostream, System.Drawing.Imaging.ImageFormat.Bmp);//将图像以指定的格式存入缓存内存流
        //        bt = new byte[mostream.Length];
        //        mostream.Position = 0;//设置留的初始位置
        //        mostream.Read(bt, 0, Convert.ToInt32(bt.Length));
        //    }
        //    bitmap.Dispose();
        //    return bt;
        //}
        public byte[] CaptureImage(Bitmap originImage, int width, int height, int spaceX, int spaceY,
    out int actWidth, out int actHeight, DefectDetail defect = null)
        {
            spaceX -= _spaceRemain;
            spaceY -= _spaceRemain;
            width += _spaceRemain * 2;
            height += _spaceRemain * 2;
            if (spaceX < 0)
            {
                spaceX = 0;
            }
            if (spaceY < 0)
            {
                spaceY = 0;
            }
            if (spaceX + width > originImage.Width)
            {
                width = originImage.Width - spaceX;
            }
            if (spaceY + height > originImage.Height)
            {
                height = originImage.Height - spaceY;
            }
            actHeight = height;
            actWidth = width;
            Bitmap imageBack = originImage;
            bool needDisposeImageBack = false; // 新增:标记是否需要释放imageBack
            if (defect != null)
            {
                PolygonResultDisplay display = new PolygonResultDisplay(defect, defect.ClassName, Color.Red, false, (int)(width * GlobalVar.WIDTH_RATIO));
                // 修改点1:确保创建的Bitmap支持Graphics
                // 使用Format24bppRgb或Format32bppArgb
                imageBack = new Bitmap(originImage.Width, originImage.Height, PixelFormat.Format24bppRgb);
                needDisposeImageBack = true; // 标记为需要释放
                // 修改点2:检查原始图像格式,如果是索引格式需要特殊处理
                if (IsIndexedPixelFormat(originImage.PixelFormat))
                {
                    // 创建支持Graphics的格式
                    using (Bitmap tempImage = new Bitmap(originImage.Width, originImage.Height, PixelFormat.Format24bppRgb))
                    using (Graphics tempG = Graphics.FromImage(tempImage))
                    {
                        tempG.DrawImage(originImage, 0, 0);
                        using (Graphics g = Graphics.FromImage(imageBack))
                        {
                            g.DrawImage(tempImage, 0, 0);
                            display.Draw(g);
                        }
                    }
                }
                else
                {
                    if (string.IsNullOrEmpty(p.Result))
                    // 原始代码逻辑
                    using (Graphics g = Graphics.FromImage(imageBack))
                    {
                        p.Result = Defaultclass.ClassName;
                        g.DrawImage(originImage, 0, 0);
                        display.Draw(g);
                    }
                }
            }
            else if (IsIndexedPixelFormat(originImage.PixelFormat))
            {
                // 修改点3:即使没有defect,如果是索引格式也需要转换
                imageBack = new Bitmap(originImage.Width, originImage.Height, PixelFormat.Format24bppRgb);
                needDisposeImageBack = true;
                Plc1.WriteSingleAddress(1526, p.Result.ToUpper().Contains("NG") ? 2 : 1, out _);
            });
            Plc1.WriteSingleAddress(1516, 1, out _);
                using (Graphics g = Graphics.FromImage(imageBack))
                {
                    g.DrawImage(originImage, 0, 0);
                }
            }
            // 修改点4:确保bitmap的像素格式支持Graphics
            PixelFormat bitmapFormat = imageBack.PixelFormat;
            if (IsIndexedPixelFormat(bitmapFormat))
            {
                // 如果imageBack仍然是索引格式(理论上不应该),转换为支持格式
                bitmapFormat = PixelFormat.Format24bppRgb;
            }
            //创建新图位图
            Bitmap bitmap = new Bitmap(width, height, bitmapFormat);
            //创建作图区域
            using (Graphics graphic = Graphics.FromImage(bitmap))
            {
                //截取原图相应区域写入作图区
                graphic.DrawImage(imageBack, 0, 0, new Rectangle(spaceX, spaceY, width, height), GraphicsUnit.Pixel);
            }
            byte[] bt = null;
            using (MemoryStream mostream = new MemoryStream())
            {
                bitmap.Save(mostream, System.Drawing.Imaging.ImageFormat.Bmp);//将图像以指定的格式存入缓存内存流
                bt = new byte[mostream.Length];
                mostream.Position = 0;//设置留的初始位置
                mostream.Read(bt, 0, Convert.ToInt32(bt.Length));
            }
            bitmap.Dispose();
            // 修改点5:释放临时创建的imageBack
            if (needDisposeImageBack && imageBack != originImage)
            {
                imageBack.Dispose();
            }
            return bt;
        }
        // 新增辅助方法:检查是否为索引像素格式
        private bool IsIndexedPixelFormat(PixelFormat format)
        {
            return format == PixelFormat.Format1bppIndexed ||
                   format == PixelFormat.Format4bppIndexed ||
                   format == PixelFormat.Format8bppIndexed ||
                   format == PixelFormat.Indexed;
        }
        [ProcessMethod("printer", "printer", "打印机打印", InvokeType.TestInvoke)]
        public ResponseMessage Printer(IOperationConfig config, IDevice invokeDevice, IDevice sourceDevice)
        {
            ResponseMessage msg = new ResponseMessage();
            Plc2 = invokeDevice as PLCBase;
            //string message = "nothing";
            if (M141Config.MES_codes.Count >= 1)
            {
                string message = M141Config.MES_codes[0].Printers_code;
                StartPrint(message, "Honeywell PX240S(300 dpi)1");
                M141Config.MES_codes.RemoveAt(0);
            }
            return msg;
        }
        public void PlcwritePrinter(int add, int value)
        {
            Plc2.WriteSingleAddress(add, value, out _);
        }
@@ -508,9 +1088,10 @@
                var spec = M141Config.SpecCollection.FirstOrDefault(s => s.Code == u.SpecCode);
                if (spec != null)
                {
                    var temp = spec.Copy<Spec>();
                    var temp = spec.Copy();
                    temp.ActualValue = null;
                    temp.MeasureResult = null;
                    temp.Source = "";
                    specList.Add(temp);
                }
            });
@@ -532,6 +1113,9 @@
            });
            return specList;
        }
        protected void FillSpecResults(string pid, List<ISpec> detectSpec, List<double> results, string SEQUENCE)
        {
@@ -556,8 +1140,6 @@
                        }
                    }
                    LogAsync(DateTime.Now, EnumHelper.LogLevel.Assist, $"产品{pid}检测项{s.Code}赋值{s.GetMeasureValueStr()},结果{s.GetMeasureResultStr()}");
                }
                else
@@ -580,12 +1162,21 @@
        {
            isOK = false;
            int num = 0;
            while (p.Details.Any(u => !u.IsDone) && num < 10)
            {
                num++;
                Thread.Sleep(500);
            }
            p.InitialDetailSpecs();
            var resultList = p.Details.SelectMany(u => u.ResultList).ToList();
            resultList.ForEach(u => u.SetResult());
            var defects = resultList.GetDefectDescList();
            var ngSpecCodes = p.Details.SelectMany(u => u.SpecList ?? new List<Spec>()).Where(u => u.MeasureResult != true).Select(u => u.Code);
            var ngSpecCodes = p.Details.SelectMany(u => u.SpecList ?? new List<ISpec>()).Where(u => u.MeasureResult != true).Select(u => u.Code);
            var ngDefectDescList = p.Details.SelectMany(u => u.DefectList ?? new List<string>()).ToList();
            defects.AddRange(ngSpecCodes);
@@ -595,16 +1186,18 @@
            {
                defects.Add("TBD");
            }
            defects = defects.Distinct().ToList();
            isOK = defects.Count <= 0;
            UpdateDefectAsync(defects);
            var defectClass = GetDefectClassFromDefectList(defects);
            UpdateResult(DateTime.Now, p.SN, defectClass.ClassName, "");
            UpdateResult(DateTime.Now, p.SN, defectClass.ClassName, "", p.ImagePaths);
            //产品序号+1
            Interlocked.Increment(ref _productIndex);
            //Interlocked.Increment(ref _productIndex);
            List<ISpec> specList = new List<ISpec>();
            specList.AddRange(p.Details.SelectMany(u => u.SpecList).ToList().ConvertAll(u => (ISpec)u));
@@ -625,17 +1218,20 @@
        private void UpdateProductResultAsync(ProductModel p)
        private void UpdateProductResultAsync(ProductModel p, string name)
        {
            UpdateProductResult(p, out bool isOK);
            _taskFactory.StartNew(() =>
            {
                _csvHead = p.GetCSVHead(ref _specHeadList, ref _positionList);
                CSVRecordAsync($"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}.csv", p.GetCSVData(_specHeadList, _positionList), _csvHead);
                //CSVRecordAsync($"ProductRecord_{DateTime.Now.ToString("yyyyMMdd")}.csv", p.GetCSVData(_specHeadList, _positionList), _csvHead);
                CSVRecordAsync(name, p.GetCSVData(_specHeadList, _positionList), _csvHead);
                //_manager_P_Product.UpdateProductResult(p.ID, p.PID, p.SN, p.Result);
            });
            //连续NG数据记录
            CheckContinuousNGAlarmAsync(p);
        }
@@ -747,6 +1343,10 @@
    }
}