From b403a5f4500fc0da7cd8f52deb591f25c02f0203 Mon Sep 17 00:00:00 2001 From: quowingwang Date: Tue, 27 Jan 2026 14:27:04 +0800 Subject: [PATCH] =?UTF-8?q?PLC=E6=95=B0=E9=87=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- RIZO.Admin.WebApi/PLC/Service/PlcService.cs | 955 ++++++++++++-------- 1 file changed, 572 insertions(+), 383 deletions(-) diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs index 22385f6..553575c 100644 --- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs +++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs @@ -1,12 +1,16 @@ // 统一引入所有必要命名空间 +using JinianNet.JNTemplate; +using MDM.Model.Process; using MDM.Services.Plant; using Microsoft.Extensions.Options; using NPOI.SS.Formula.Functions; using Quartz; using RIZO.Admin.WebApi.PLC.Model; using RIZO.Common; +using RIZO.Model.MES.product_trace; using S7.Net; using SqlSugar; +using SqlSugar.IOC; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -37,7 +41,11 @@ namespace RIZO.Admin.WebApi.PLC.Service // 先在类中添加2个核心优化字段(支撑高频访问) private readonly SemaphoreSlim _concurrencySemaphore = new SemaphoreSlim(15, 50); // 限制20并发(适配50台PLC) private readonly ConcurrentDictionary _plcConnPool = new(); // 连接池 - + private readonly SqlSugarClient Context; + public PlcService() + { + Context = DbScoped.SugarScope.CopyNew(); + } #region PLC地址块儿映射 //MES返回PLC请求映射 private readonly Dictionary _mesIntReturnMap = new() @@ -127,6 +135,95 @@ namespace RIZO.Admin.WebApi.PLC.Service }; + // OP050 专属地址映射(点白胶DC744工位,DB300) + private readonly Dictionary _op050StringMap = new() + { + { "报警信息", ("DB300.DBB680", 48) }, // Array[1..48] of Byte + { "产品型号", ("DB300.DBB728", 48) }, // String[48] + { "产品名称", ("DB300.DBB778", 48) }, // String[48] + { "产品1SN", ("DB300.DBB50", 40) }, // String[40] + { "产品2SN", ("DB300.DBB206", 40) }, // String[40] + { "产品3SN", ("DB300.DBB362", 40) }, // String[40] + { "产品4SN", ("DB300.DBB518", 40) } // String[40] + }; + + private readonly Dictionary _op050IntMap = new() + { + // 基础状态 + { "运行状态", "DB300.DBW670" }, // Int - 1=空闲,2=运行中,3=故障 + { "设备模式", "DB300.DBW672" }, // Int - 1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + { "设备在线状态", "DB300.DBW674" }, // Int - 1=离线,0=在线 + { "ByPass", "DB300.DBW676" }, // Int - 1=ByPass,0=正常模式 + { "生产模式", "DB300.DBW678" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式 + + // 上传与查询请求 + { "上传请求", "DB300.DBW42" }, // Int + { "查询请求", "DB300.DBW44" }, // Int - 非0是查询(%X1满足条码1查询……%X2满足条码2查询) + + // 产量数据 + { "实际产量", "DB300.DBD828" }, // DInt + { "合格数量", "DB300.DBD832" }, // DInt + { "失败数量", "DB300.DBD836" }, // DInt + + // 节拍时间 + { "节拍时间", "DB300.DBD840" }, // Real + + // 托盘号 + { "托盘号", "DB300.DBW844" }, // Int + }; + + // OP050-1 专属地址映射(自动下料工位,DB1001) + private readonly Dictionary _op050_1StringMap = new() + { + { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte + { "产品型号", ("DB1001.DBB1000", 48) }, // String[48] + { "产品名称", ("DB1001.DBB1054", 48) } // String[48] + }; + + private readonly Dictionary _op050_1IntMap = new() + { + // 基础状态 + { "运行状态", "DB1001.DBW0" }, // Int - 1=空闲,2=运行中,3=故障 + { "设备模式", "DB1001.DBW2" }, // Int - 1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + { "设备在线状态", "DB1001.DBW4" }, // Int - 1=离线,0=在线 + { "ByPass", "DB1001.DBW6" }, // Int - 1=ByPass,0=正常模式 + { "生产模式", "DB1001.DBW8" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式 + + // 产量数据 + { "实际产量", "DB1001.DBD1104" }, // DInt + { "合格数量", "DB1001.DBD1108" }, // DInt + { "失败数量", "DB1001.DBD1112" }, // DInt + + // 节拍时间 + { "节拍时间", "DB1001.DBD5086" }, // Real + }; + + // OP051扫码 专属地址映射(Coating扫码工位,假设使用 DB1002)//待PLC给出 + private readonly Dictionary _op051ScanStringMap = new() + { + { "产品型号", ("DB1002.DBB1000", 48) }, // String[48] + { "产品名称", ("DB1002.DBB1054", 48) }, // String[48] + { "SN_1", ("DB1002.DBB50", 40) }, // String[40] + { "SN_2", ("DB1002.DBB206", 40) }, // String[40] + { "SN_3", ("DB1002.DBB362", 40) } // String[40] + }; + + private readonly Dictionary _op051ScanIntMap = new() + { + // 基础状态 + { "运行状态", "DB1002.DBW0" }, // Int - 1=空闲,2=运行中,3=故障 + { "设备模式", "DB1002.DBW2" }, // Int - 1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + { "设备在线状态", "DB1002.DBW4" }, // Int - 1=离线,0=在线 + { "生产模式", "DB1002.DBW8" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式 + + // 操作请求 + { "查询请求", "DB1002.DBW44" }, // Int - 非0为查询 + { "上传结果请求", "DB1002.DBW46" }, // Int - 非0为上传 + + // 托盘号 + { "托盘号", "DB1002.DBW844" } // Int + }; + // OP070-1 专属地址映射 (点散热胶GF1500工位) OP070-2 点散热胶TC4060 OP070-3 点散热胶GF3500 private readonly Dictionary _op070_1StringMap = new() { @@ -482,6 +579,15 @@ namespace RIZO.Admin.WebApi.PLC.Service await Task.WhenAll(task4_1, task4_2, task4_3, task4_4).ConfigureAwait(false); iSaveRequest = (task4_1.Result == 1 || task4_2.Result == 1 || task4_3.Result == 1 || task4_4.Result == 1) ? 1 : 0; break; + case "OP050": + iSaveRequest = await ReadPlcIntAsync(plc, _op050IntMap["上传请求"]).ConfigureAwait(false); + break; + case "OP050_1": + iSaveRequest = 1; + break; + case " ": + iSaveRequest = await ReadPlcIntAsync(plc, _op051ScanIntMap["上传结果请求"]).ConfigureAwait(false); + break; case "OP070-1": case "OP070-2": case "OP070-3": @@ -512,6 +618,9 @@ namespace RIZO.Admin.WebApi.PLC.Service { "OP020-2" => await ReadOP020_2DataAsync(plc, ip, plcName).ConfigureAwait(false), "OP020-3" => await ReadOP020_3DataAsync(plc, ip, plcName).ConfigureAwait(false), + "OP020-4" => await ReadOP020_4DataAsync(plc, ip, plcName).ConfigureAwait(false), + "OP050" => await ReadOP050DataAsync(plc, ip, plcName).ConfigureAwait(false), + "OP050_1" => await ReadOP050_1DataAsync(plc, ip, plcName).ConfigureAwait(false), "OP070-1" or "OP070-2" or "OP070-3" => await ReadOP070_1DataAsync(plc, ip, plcName).ConfigureAwait(false), "OP075" => await ReadOP075DataAsync(plc, ip, plcName).ConfigureAwait(false), "OP080-1" => await ReadOP080_1DataAsync(plc, ip, plcName, strSaveRequest).ConfigureAwait(false), @@ -578,7 +687,7 @@ namespace RIZO.Admin.WebApi.PLC.Service /// /// 读取OP020-2数据(合盖工位 /// - private async Task ReadOP020_2DataAsync(Plc plc, string ip, string workstationCode) + private async Task ReadOP020_2DataAsync(Plc plc, string ip, string workstationCode) { // 前置校验:PLC连接无效直接返回,避免无效操作 if (plc == null || !plc.IsConnected) @@ -757,10 +866,385 @@ namespace RIZO.Admin.WebApi.PLC.Service return null; } } + + /// + /// 读取OP020-4数据(pin压合&视觉检查工位) + /// + private async Task ReadOP020_4DataAsync(Plc plc, string ip, string workstationCode) + { + // 前置校验:PLC连接无效直接返回,避免无效操作 + if (plc == null || !plc.IsConnected) + { + return null; + } + + try + { + // 1. 批量创建并行读取任务(最大化并行效率,减少临时变量开销) + var stringReadTasks = new Dictionary> + { + { "报警信息", ReadPlcStringAsync(plc, _op020_4StringMap["报警信息"].Addr, _op020_4StringMap["报警信息"].Len) }, + { "产品型号", ReadPlcStringAsync(plc, _op020_4StringMap["产品型号"].Addr, _op020_4StringMap["产品型号"].Len) }, + { "产品名称", ReadPlcStringAsync(plc, _op020_4StringMap["产品名称"].Addr, _op020_4StringMap["产品名称"].Len) }, + { "产品1SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品1SN"].Addr, _op020_4StringMap["产品1SN"].Len) }, + { "产品2SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品2SN"].Addr, _op020_4StringMap["产品2SN"].Len) }, + { "产品3SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品3SN"].Addr, _op020_4StringMap["产品3SN"].Len) }, + { "产品4SN", ReadPlcStringAsync(plc, _op020_4StringMap["产品4SN"].Addr, _op020_4StringMap["产品4SN"].Len) } + }; + + var intReadTasks = new Dictionary> + { + { "运行状态", ReadPlcIntAsync(plc, _op020_4IntMap["运行状态"]) }, + { "设备模式", ReadPlcIntAsync(plc, _op020_4IntMap["设备模式"]) }, + { "设备在线状态", ReadPlcIntAsync(plc, _op020_4IntMap["设备在线状态"]) }, + { "ByPass", ReadPlcIntAsync(plc, _op020_4IntMap["ByPass"]) }, + { "生产模式", ReadPlcIntAsync(plc, _op020_4IntMap["生产模式"]) }, + { "托盘号", ReadPlcIntAsync(plc, _op020_4IntMap["托盘号"]) }, + { "产品1结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品1结果"]) }, + { "产品2结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品2结果"]) }, + { "产品3结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品3结果"]) }, + { "产品4结果", ReadPlcIntAsync(plc, _op020_4IntMap["产品4结果"]) } + }; + + // 2. 并行等待所有读取任务完成(合并任务列表,单次WaitAll提升效率) + var allTasks = new List(); + allTasks.AddRange(stringReadTasks.Values); + allTasks.AddRange(intReadTasks.Values); + await Task.WhenAll(allTasks).ConfigureAwait(false); + + // 3. 提取读取结果(直接取值+空值兜底,减少await重复调用) + // 字符串字段 + string productModel = stringReadTasks["产品型号"].Result ?? string.Empty; + string productName = stringReadTasks["产品名称"].Result ?? string.Empty; + string product1SN = stringReadTasks["产品1SN"].Result ?? string.Empty; + string product2SN = stringReadTasks["产品2SN"].Result ?? string.Empty; + string product3SN = stringReadTasks["产品3SN"].Result ?? string.Empty; + string product4SN = stringReadTasks["产品4SN"].Result ?? string.Empty; + + // 整数字段 + int runStatus = intReadTasks["运行状态"].Result; + int machineModel = intReadTasks["设备模式"].Result; + int onlineStatus = intReadTasks["设备在线状态"].Result; + int produceModel = intReadTasks["生产模式"].Result; + int trayNo = intReadTasks["托盘号"].Result; + int product1Result = intReadTasks["产品1结果"].Result; + int product2Result = intReadTasks["产品2结果"].Result; + int product3Result = intReadTasks["产品3结果"].Result; + int product4Result = intReadTasks["产品4结果"].Result; + + + // 4. 业务逻辑转换(极简逻辑,仅保留必要转换) + string reworkFlag = produceModel == 4 ? "1" : "0"; + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => produceModel.ToString() + }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + bool allProductsOk = product1Result == 1 && product2Result == 1 && product3Result == 1 && product4Result == 1; + string qualificationFlag = allProductsOk ? "1" : "2"; + // 6. 构建实体(精准匹配PlcProductionData字段,无冗余) + return new PlcProductionData + { + PlcIp = ip, + OccurTime = DateTime.Now, + LineCode = "line2", + WorkstationCode = workstationCode, + ProductModel = productModel, + ProductName = productName, + ProductCode = product1SN, // 主产品编码取产品1SN(可根据业务调整) + ReworkFlag = reworkFlag, + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + TrayNo = trayNo.ToString(), + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + Product1SN = product1SN, + Product2SN = product2SN, + Product3SN = product3SN, + Product4SN = product4SN, + Product1Result = product1Result.ToString(), + Product2Result = product2Result.ToString(), + Product3Result = product1Result.ToString(), + Product4Result = product1Result.ToString(), + SN1 = product1SN, + SN2 = product2SN, + QualificationFlag = qualificationFlag + }; + } + catch + { + return null; + } + } + + /// + /// 读取OP050数据(点白胶DC744工位) + /// + /// PLC连接实例 + /// PLC的IP地址 + /// 工位编码 + /// PLC生产数据实体 + private async Task ReadOP050DataAsync(Plc plc, string ip, string workstationCode) + { + // 前置校验:PLC连接无效直接返回,避免无效操作 + if (plc == null || !plc.IsConnected) + { + return null; + } + + try + { + // 1. 批量创建并行读取任务(最大化并行效率,按字段类型分类) + var stringReadTasks = new Dictionary> + { + { "报警信息", ReadPlcStringAsync(plc, _op050StringMap["报警信息"].Addr, _op050StringMap["报警信息"].Len) }, + { "产品型号", ReadPlcStringAsync(plc, _op050StringMap["产品型号"].Addr, _op050StringMap["产品型号"].Len) }, + { "产品名称", ReadPlcStringAsync(plc, _op050StringMap["产品名称"].Addr, _op050StringMap["产品名称"].Len) }, + { "产品1SN", ReadPlcStringAsync(plc, _op050StringMap["产品1SN"].Addr, _op050StringMap["产品1SN"].Len) }, + { "产品2SN", ReadPlcStringAsync(plc, _op050StringMap["产品2SN"].Addr, _op050StringMap["产品2SN"].Len) }, + { "产品3SN", ReadPlcStringAsync(plc, _op050StringMap["产品3SN"].Addr, _op050StringMap["产品3SN"].Len) }, + { "产品4SN", ReadPlcStringAsync(plc, _op050StringMap["产品4SN"].Addr, _op050StringMap["产品4SN"].Len) } + }; + + // 注意:OP050包含DInt/Real类型,需适配读取方法(假设已有对应异步方法) + var intReadTasks = new Dictionary> + { + { "运行状态", ReadPlcIntAsync(plc, _op050IntMap["运行状态"]) }, + { "设备模式", ReadPlcIntAsync(plc, _op050IntMap["设备模式"]) }, + { "设备在线状态", ReadPlcIntAsync(plc, _op050IntMap["设备在线状态"]) }, + { "ByPass", ReadPlcIntAsync(plc, _op050IntMap["ByPass"]) }, + { "生产模式", ReadPlcIntAsync(plc, _op050IntMap["生产模式"]) }, + { "托盘号", ReadPlcIntAsync(plc, _op050IntMap["托盘号"]) } + }; + + // DInt(双整数)读取任务(复用ReadPlcIntAsync,PLC底层兼容DInt转int) + var dIntReadTasks = new Dictionary> + { + { "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) }, + { "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) }, + { "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) } + }; + + // Real(浮点型)读取任务(新增ReadPlcRealAsync方法,返回float) + var realReadTasks = new Dictionary> + { + { "节拍时间", ReadPlcRealAsync(plc, _op050IntMap["节拍时间"]) } + }; + + // 2. 并行等待所有读取任务完成(合并所有任务列表,单次WaitAll提升效率) + var allTasks = new List(); + allTasks.AddRange(stringReadTasks.Values); + allTasks.AddRange(intReadTasks.Values); + allTasks.AddRange(dIntReadTasks.Values); + allTasks.AddRange(realReadTasks.Values); + await Task.WhenAll(allTasks).ConfigureAwait(false); + + // 3. 提取读取结果(直接取值+空值兜底,任务已完成无阻塞风险) + // 字符串字段 + string productModel = stringReadTasks["产品型号"].Result ?? string.Empty; + string productName = stringReadTasks["产品名称"].Result ?? string.Empty; + string product1SN = stringReadTasks["产品1SN"].Result ?? string.Empty; + string product2SN = stringReadTasks["产品2SN"].Result ?? string.Empty; + string product3SN = stringReadTasks["产品3SN"].Result ?? string.Empty; + string product4SN = stringReadTasks["产品4SN"].Result ?? string.Empty; + + // 整数/双整数字段 + int runStatus = intReadTasks["运行状态"].Result; + int machineModel = intReadTasks["设备模式"].Result; + int onlineStatus = intReadTasks["设备在线状态"].Result; + int byPass = intReadTasks["ByPass"].Result; + int produceModel = intReadTasks["生产模式"].Result; + int trayNo = intReadTasks["托盘号"].Result; + int actualOutput = dIntReadTasks["实际产量"].Result; + int qualifiedQty = dIntReadTasks["合格数量"].Result; + int failedQty = dIntReadTasks["失败数量"].Result; + + // 浮点数字段 + float cycleTime = realReadTasks["节拍时间"].Result; + + // 5. 业务逻辑转换(极简+严谨) + string reworkFlag = produceModel == 4 ? "1" : "0"; + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => produceModel.ToString() + }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + // OP050无单个产品结果,合格标识按总产量逻辑:有失败则NG(2),否则OK(1) + bool allQualified = failedQty == 0 && actualOutput >= 0; + string qualificationFlag = allQualified ? "1" : "2"; + + // 6. 构建实体(精准匹配PlcProductionData字段,适配OP050特性) + return new PlcProductionData + { + PlcIp = ip, + OccurTime = DateTime.Now, + LineCode = "line2", // 按实际产线调整,建议后续改为参数 + WorkstationCode = workstationCode, + ProductModel = productModel, + ProductName = productName, + ProductCode = product1SN, // 主产品编码取产品1SN + ReworkFlag = reworkFlag, + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + TrayNo = trayNo.ToString(), + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + // 4个产品SN(匹配实体字段) + Product1SN = product1SN, + Product2SN = product2SN, + Product3SN = product3SN, + Product4SN = product4SN, + // 兼容原有SN字段 + SN1 = product1SN, + SN2 = product2SN, + // OP050核心产量/节拍字段 + ProductionCycle = (int)Math.Round(cycleTime), // 节拍时间转整数秒 + QualificationFlag = qualificationFlag, + }; + } + catch + { + return null; + } + } + + /// + /// 读取OP050-1数据(自动下料工位,DB1001) + /// + private async Task ReadOP050_1DataAsync(Plc plc, string ip, string workstationCode) + { + // 前置校验:PLC连接无效直接返回,避免无效操作 + if (plc == null || !plc.IsConnected) + { + return null; + } + + try + { + // 1. 批量创建并行读取任务(按字段类型分类,最大化并行效率) + var stringReadTasks = new Dictionary> + { + { "报警信息", ReadPlcStringAsync(plc, _op050_1StringMap["报警信息"].Addr, _op050_1StringMap["报警信息"].Len) }, + { "产品型号", ReadPlcStringAsync(plc, _op050_1StringMap["产品型号"].Addr, _op050_1StringMap["产品型号"].Len) }, + { "产品名称", ReadPlcStringAsync(plc, _op050_1StringMap["产品名称"].Addr, _op050_1StringMap["产品名称"].Len) } + }; + + var intReadTasks = new Dictionary> + { + { "运行状态", ReadPlcIntAsync(plc, _op050_1IntMap["运行状态"]) }, + { "设备模式", ReadPlcIntAsync(plc, _op050_1IntMap["设备模式"]) }, + { "设备在线状态", ReadPlcIntAsync(plc, _op050_1IntMap["设备在线状态"]) }, + { "ByPass", ReadPlcIntAsync(plc, _op050_1IntMap["ByPass"]) }, + { "生产模式", ReadPlcIntAsync(plc, _op050_1IntMap["生产模式"]) } + }; + + // DInt(双整数)读取任务(产量相关) + var dIntReadTasks = new Dictionary> + { + { "实际产量", ReadPlcIntAsync(plc, _op050_1IntMap["实际产量"]) }, + { "合格数量", ReadPlcIntAsync(plc, _op050_1IntMap["合格数量"]) }, + { "失败数量", ReadPlcIntAsync(plc, _op050_1IntMap["失败数量"]) } + }; + + // Real(浮点型)读取任务(节拍时间) + var realReadTasks = new Dictionary> + { + { "节拍时间", ReadPlcRealAsync(plc, _op050_1IntMap["节拍时间"]) } + }; + + // 2. 并行等待所有读取任务完成(单次WaitAll,最小化等待时间) + var allTasks = new List(); + allTasks.AddRange(stringReadTasks.Values); + allTasks.AddRange(intReadTasks.Values); + allTasks.AddRange(dIntReadTasks.Values); + allTasks.AddRange(realReadTasks.Values); + await Task.WhenAll(allTasks).ConfigureAwait(false); + + // 3. 提取读取结果(直接取值+空值兜底,无阻塞风险) + // 字符串字段 + string productModel = stringReadTasks["产品型号"].Result ?? string.Empty; + string productName = stringReadTasks["产品名称"].Result ?? string.Empty; + + // 整数基础状态字段 + int runStatus = intReadTasks["运行状态"].Result; + int machineModel = intReadTasks["设备模式"].Result; + int onlineStatus = intReadTasks["设备在线状态"].Result; + int produceModel = intReadTasks["生产模式"].Result; + + // 产量相关字段(DInt) + int actualOutput = dIntReadTasks["实际产量"].Result; + int qualifiedQty = dIntReadTasks["合格数量"].Result; + int failedQty = dIntReadTasks["失败数量"].Result; + + // 节拍时间(Real) + float cycleTime = realReadTasks["节拍时间"].Result; + + // 4. 业务逻辑转换(极简+严谨) + string reworkFlag = produceModel == 4 ? "1" : "0"; // 返工模式标识 + string produceModelDesc = produceModel switch + { + 1 => "正常模式", + 2 => "清线模式", + 4 => "返工模式", + 8 => "换型模式", + 16 => "预热模式", + _ => produceModel.ToString() + }; + string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; + // 合格标识:失败数量为0且实际产量≥0则OK(1),否则NG(2) + bool allQualified = failedQty == 0 && actualOutput >= 0; + string qualificationFlag = allQualified ? "1" : "2"; + + // 5. 构建实体(精准匹配PlcProductionData字段,无冗余) + return new PlcProductionData + { + PlcIp = ip, + OccurTime = DateTime.Now, + LineCode = "line2", // 按实际产线调整,建议改为参数 + WorkstationCode = workstationCode, + ProductModel = productModel, + ProductName = productName, + ProductCode = string.Empty, + ReworkFlag = reworkFlag, + Automanual = machineModel, + Runstatus = runStatus, + OnlineStatus = onlineStatusDesc, + ProduceModel = produceModelDesc, + TrayNo = string.Empty, + CreatedBy = "PLC", + CreatedTime = DateTime.Now, + // 产量/节拍核心字段 + ProductionCycle = (int)Math.Round(cycleTime), // 节拍时间转整数秒 + QualificationFlag = qualificationFlag, + // 备注记录产量信息(便于排查) + Remark = $"实际产量:{actualOutput},合格数量:{qualifiedQty},失败数量:{failedQty},节拍时间:{cycleTime:F2}秒" + }; + } + catch + { + // 异常静默处理,返回null避免上层崩溃 + return null; + } + } + /// /// OP070-1数据读取 - 效率优化版 /// - private async Task ReadOP070_1DataAsync(Plc plc, string ip, string workstationCode) + private async Task ReadOP070_1DataAsync(Plc plc, string ip, string workstationCode) { // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) if (plc == null || !plc.IsConnected) @@ -884,7 +1368,7 @@ namespace RIZO.Admin.WebApi.PLC.Service /// /// OP075数据读取 /// - private async Task ReadOP075DataAsync(Plc plc, string ip, string workstationCode) + private async Task ReadOP075DataAsync(Plc plc, string ip, string workstationCode) { // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) if (plc == null || !plc.IsConnected) @@ -1010,308 +1494,6 @@ namespace RIZO.Admin.WebApi.PLC.Service } } - ///// - ///// 读取OP080-1数据 - 效率优化版 - ///// - //private async Task ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest) - //{ - // // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) - // if (plc == null || !plc.IsConnected) - // { - // Console.WriteLine($"OP080-1({ip})PLC连接无效,跳过数据读取"); - // // 返回基础实体避免业务空引用 - // return new PlcProductionData { PlcIp = ip, WorkstationCode = workstationCode }; - // } - - // try - // { - // // 1. 真正的并行读取所有字段(核心效率优化:44个字段并行读取) - // // ========== 字符串字段并行任务 ========== - // var taskOrderName = ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len); - // var taskProductName = ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len); - // var taskHzMachineSN = ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len); - // var taskHzPcbsn = ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len); - // var taskNjMachineSN = ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len); - // var taskNjPcbsn = ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len); - - // // ========== Int字段并行任务 ========== - // // 基础状态字段 - // var taskRunStatus = ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]); - // var taskMachineModel = ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]); - // var taskOnlineStatus = ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]); - // var taskByPass = ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]); - // var taskProduceModel = ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]); - // // 请求/托盘字段 - // var taskHzQueryReq = ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]); - // var taskHzSaveReq = ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]); - // var taskNjSaveReq = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]); - // var taskHzTrayNo = ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]); - // var taskNjTrayNo = ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]); - // // 螺钉结果字段 - // var taskScrew1Result = ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]); - // var taskScrew2Result = ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]); - // var taskScrew3Result = ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]); - // var taskScrew4Result = ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]); - // var taskScrew5Result = ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]); - // var taskScrew6Result = ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]); - // var taskScrew7Result = ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"]); - - // // ========== Real字段并行任务(7个螺钉×4个维度) ========== - // // 1号螺钉 - // var taskScrew1Torque = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_扭矩"]); - // var taskScrew1Depth = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_深度"]); - // var taskScrew1Angle = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_角度"]); - // var taskScrew1Time = ReadPlcRealAsync(plc, _op080_1IntMap["1号螺钉_拧紧时间"]); - // // 2号螺钉 - // var taskScrew2Torque = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_扭矩"]); - // var taskScrew2Depth = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_深度"]); - // var taskScrew2Angle = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_角度"]); - // var taskScrew2Time = ReadPlcRealAsync(plc, _op080_1IntMap["2号螺钉_拧紧时间"]); - // // 3号螺钉 - // var taskScrew3Torque = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_扭矩"]); - // var taskScrew3Depth = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_深度"]); - // var taskScrew3Angle = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_角度"]); - // var taskScrew3Time = ReadPlcRealAsync(plc, _op080_1IntMap["3号螺钉_拧紧时间"]); - // // 4号螺钉 - // var taskScrew4Torque = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_扭矩"]); - // var taskScrew4Depth = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_深度"]); - // var taskScrew4Angle = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_角度"]); - // var taskScrew4Time = ReadPlcRealAsync(plc, _op080_1IntMap["4号螺钉_拧紧时间"]); - // // 5号螺钉 - // var taskScrew5Torque = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_扭矩"]); - // var taskScrew5Depth = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_深度"]); - // var taskScrew5Angle = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_角度"]); - // var taskScrew5Time = ReadPlcRealAsync(plc, _op080_1IntMap["5号螺钉_拧紧时间"]); - // // 6号螺钉 - // var taskScrew6Torque = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_扭矩"]); - // var taskScrew6Depth = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_深度"]); - // var taskScrew6Angle = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_角度"]); - // var taskScrew6Time = ReadPlcRealAsync(plc, _op080_1IntMap["6号螺钉_拧紧时间"]); - // // 7号螺钉 - // var taskScrew7Torque = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_扭矩"]); - // var taskScrew7Depth = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_深度"]); - // var taskScrew7Angle = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_角度"]); - // var taskScrew7Time = ReadPlcRealAsync(plc, _op080_1IntMap["7号螺钉_拧紧时间"]); - - // // 2. 等待所有并行任务完成(核心:耗时=最慢的单个读取任务,而非44个字段总和) - // await Task.WhenAll( - // // 字符串任务 - // taskOrderName, taskProductName, taskHzMachineSN, taskHzPcbsn, taskNjMachineSN, taskNjPcbsn, - // // Int任务 - // taskRunStatus, taskMachineModel, taskOnlineStatus, taskByPass, taskProduceModel, - // taskHzQueryReq, taskHzSaveReq, taskNjSaveReq, taskHzTrayNo, taskNjTrayNo, - // taskScrew1Result, taskScrew2Result, taskScrew3Result, taskScrew4Result, taskScrew5Result, taskScrew6Result, taskScrew7Result, - // // Real任务(7×4) - // taskScrew1Torque, taskScrew1Depth, taskScrew1Angle, taskScrew1Time, - // taskScrew2Torque, taskScrew2Depth, taskScrew2Angle, taskScrew2Time, - // taskScrew3Torque, taskScrew3Depth, taskScrew3Angle, taskScrew3Time, - // taskScrew4Torque, taskScrew4Depth, taskScrew4Angle, taskScrew4Time, - // taskScrew5Torque, taskScrew5Depth, taskScrew5Angle, taskScrew5Time, - // taskScrew6Torque, taskScrew6Depth, taskScrew6Angle, taskScrew6Time, - // taskScrew7Torque, taskScrew7Depth, taskScrew7Angle, taskScrew7Time); - - // // 3. 获取并行读取结果(带空值兜底,避免后续空引用) - // // 字符串字段 - // string orderName = await taskOrderName ?? string.Empty; - // string productName = await taskProductName ?? string.Empty; - // string hzMachineSN = await taskHzMachineSN ?? string.Empty; - // string hzPcbsn = await taskHzPcbsn ?? string.Empty; - // string njMachineSN = await taskNjMachineSN ?? string.Empty; - // string njPcbsn = await taskNjPcbsn ?? string.Empty; - - // // Int字段 - // int runStatus = await taskRunStatus; - // int machineModel = await taskMachineModel; - // int onlineStatus = await taskOnlineStatus; - // int byPass = await taskByPass; - // int produceModel = await taskProduceModel; - // int hzQueryReq = await taskHzQueryReq; - // int hzSaveReq = await taskHzSaveReq; - // int njSaveReq = await taskNjSaveReq; - // int hzTrayNo = await taskHzTrayNo; - // int njTrayNo = await taskNjTrayNo; - // int screw1Result = await taskScrew1Result; - // int screw2Result = await taskScrew2Result; - // int screw3Result = await taskScrew3Result; - // int screw4Result = await taskScrew4Result; - // int screw5Result = await taskScrew5Result; - // int screw6Result = await taskScrew6Result; - // int screw7Result = await taskScrew7Result; - - // // Real字段 - // float screw1Torque = await taskScrew1Torque; - // float screw1Depth = await taskScrew1Depth; - // float screw1Angle = await taskScrew1Angle; - // float screw1Time = await taskScrew1Time; - // float screw2Torque = await taskScrew2Torque; - // float screw2Depth = await taskScrew2Depth; - // float screw2Angle = await taskScrew2Angle; - // float screw2Time = await taskScrew2Time; - // float screw3Torque = await taskScrew3Torque; - // float screw3Depth = await taskScrew3Depth; - // float screw3Angle = await taskScrew3Angle; - // float screw3Time = await taskScrew3Time; - // float screw4Torque = await taskScrew4Torque; - // float screw4Depth = await taskScrew4Depth; - // float screw4Angle = await taskScrew4Angle; - // float screw4Time = await taskScrew4Time; - // float screw5Torque = await taskScrew5Torque; - // float screw5Depth = await taskScrew5Depth; - // float screw5Angle = await taskScrew5Angle; - // float screw5Time = await taskScrew5Time; - // float screw6Torque = await taskScrew6Torque; - // float screw6Depth = await taskScrew6Depth; - // float screw6Angle = await taskScrew6Angle; - // float screw6Time = await taskScrew6Time; - // float screw7Torque = await taskScrew7Torque; - // float screw7Depth = await taskScrew7Depth; - // float screw7Angle = await taskScrew7Angle; - // float screw7Time = await taskScrew7Time; - - // // 4. 异步复位保存请求(非阻塞,不影响读取效率) - // // 异步执行写操作,不阻塞主线程 - // //await Task.Run(() => - // //{ - // // if (strSaveRequest.Contains("合装结果保存请求")) - // // { - // // WritePlcValue(plc, _op080_1IntMap["合装结果保存请求"], "0"); - // // } - // // if (strSaveRequest.Contains("拧紧结果保存请求")) - // // { - // // WritePlcValue(plc, _op080_1IntMap["拧紧结果保存请求"], "0"); - // // } - // //}); - - // // 5. 业务逻辑计算(优化:减少冗余计算) - // var reworkFlag = produceModel == 4 ? "1" : "0"; - // string produceModelDesc = produceModel switch - // { - // 1 => "正常模式", - // 2 => "清线模式", - // 4 => "返工模式", - // 8 => "换型模式", - // 16 => "预热模式", - // _ => $"未知({produceModel})" - // }; - // string runStatusDesc = runStatus switch { 1 => "空闲", 2 => "运行中", 3 => "故障", _ => $"未知({runStatus})" }; - // string onlineStatusDesc = onlineStatus == 1 ? "离线" : "在线"; - - // // 计算整体工位合格标识(优化:数组提前创建,减少GC) - // var screwResults = new[] { screw1Result, screw2Result, screw3Result, screw4Result, screw5Result, screw6Result, screw7Result }; - // bool allScrewQualified = screwResults.All(s => s == 1); - // string qualificationFlag = allScrewQualified ? "1" : "0"; - - // // 调试日志:优化字符串拼接,保留核心信息 - // Console.WriteLine($"OP080-1({ip})读取结果:产品名称={productName},运行状态={runStatusDesc},订单名称={orderName},螺钉整体合格={allScrewQualified}"); - - // // 6. 构建数据实体(优化:减少冗余字符串操作,提前兜底) - // var plcData = new PlcProductionData - // { - // // 基础字段(移除ip.Trim,外层已校验非空) - // PlcIp = ip, - // OccurTime = DateTime.Now, - // LineCode = "line2", - // WorkstationCode = workstationCode, - // ProductName = productName, - // ProductCode = njPcbsn, - - // // 合格/返工标志 - // QualificationFlag = qualificationFlag, - // ReworkFlag = reworkFlag, - - // // 设备状态相关 - // Automanual = machineModel, - // Runstatus = runStatus, - // OnlineStatus = onlineStatusDesc, - // ProduceModel = produceModelDesc, - - // // 托盘号相关 - // TrayNo = $"{hzTrayNo}!{njTrayNo}", - // AssemblyTrayNo = hzTrayNo.ToString(), - // TightenTrayNo = njTrayNo.ToString(), - - // // SN相关字段(提前兜底,无需重复判空) - // SN1 = hzMachineSN, - // SN2 = njMachineSN, - // AssemblyHousingSN = hzMachineSN, - // AssemblyPCBSN = hzPcbsn, - // TightenHousingSN = njMachineSN, - // TightenPCBSN = njPcbsn, - - // // 螺钉相关字段(优化:ToString("0.00")直接赋值,减少临时变量) - // Screw1Result = screw1Result.ToString(), - // Screw1Torque = screw1Torque.ToString("0.00"), - // Screw1Depth = screw1Depth.ToString("0.00"), - // Screw1Angle = screw1Angle.ToString("0.00"), - // Screw1TightenTime = screw1Time.ToString("0.00"), - - // Screw2Result = screw2Result.ToString(), - // Screw2Torque = screw2Torque.ToString("0.00"), - // Screw2Depth = screw2Depth.ToString("0.00"), - // Screw2Angle = screw2Angle.ToString("0.00"), - // Screw2TightenTime = screw2Time.ToString("0.00"), - - // Screw3Result = screw3Result.ToString(), - // Screw3Torque = screw3Torque.ToString("0.00"), - // Screw3Depth = screw3Depth.ToString("0.00"), - // Screw3Angle = screw3Angle.ToString("0.00"), - // Screw3TightenTime = screw3Time.ToString("0.00"), - - // Screw4Result = screw4Result.ToString(), - // Screw4Torque = screw4Torque.ToString("0.00"), - // Screw4Depth = screw4Depth.ToString("0.00"), - // Screw4Angle = screw4Angle.ToString("0.00"), - // Screw4TightenTime = screw4Time.ToString("0.00"), - - // Screw5Result = screw5Result.ToString(), - // Screw5Torque = screw5Torque.ToString("0.00"), - // Screw5Depth = screw5Depth.ToString("0.00"), - // Screw5Angle = screw5Angle.ToString("0.00"), - // Screw5TightenTime = screw5Time.ToString("0.00"), - - // Screw6Result = screw6Result.ToString(), - // Screw6Torque = screw6Torque.ToString("0.00"), - // Screw6Depth = screw6Depth.ToString("0.00"), - // Screw6Angle = screw6Angle.ToString("0.00"), - // Screw6TightenTime = screw6Time.ToString("0.00"), - - // Screw7Result = screw7Result.ToString(), - // Screw7Torque = screw7Torque.ToString("0.00"), - // Screw7Depth = screw7Depth.ToString("0.00"), - // Screw7Angle = screw7Angle.ToString("0.00"), - // Screw7TightenTime = screw7Time.ToString("0.00"), - - // // 系统字段(固定值直接赋值) - // CreatedBy = "PLC", - // CreatedTime = DateTime.Now, - // ParamName = string.Empty, - // ParamValue = string.Empty, - // ProductionCycle = null, - // Remark = string.Empty, - // UpdatedBy = string.Empty, - // UpdatedTime = null, - // ProductModel = string.Empty, - // WorkstationName = string.Empty, - // CameraResult = string.Empty - // }; - // return plcData; - // } - // catch (Exception ex) - // { - // // 增强异常日志:包含堆栈,便于定位问题 - // Console.WriteLine($"OP080-1({ip})数据读取异常:{ex.Message}\n{ex.StackTrace}"); - // // 异常时返回基础实体,避免业务空引用 - // return new PlcProductionData - // { - // PlcIp = ip, - // WorkstationCode = workstationCode, - // CreatedBy = "PLC", - // CreatedTime = DateTime.Now, - // OnlineStatus = "读取异常" - // }; - // } - //} - /// /// 读取OP080-1数据 - 极致优化版(批量并行+内存复用+异步优化) /// @@ -1320,7 +1502,7 @@ namespace RIZO.Admin.WebApi.PLC.Service /// 工位编码 /// 保存请求类型 /// PLC生产数据 - private async Task ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest) + private async Task ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest) { // 前置核心校验:避免无效PLC操作(节省10+ms无效耗时) if (plc == null || !plc.IsConnected) @@ -1333,39 +1515,39 @@ namespace RIZO.Admin.WebApi.PLC.Service // ========== 阶段1:批量创建并行任务(按类型分组,减少分散管理) ========== // 1.1 字符串字段任务(6个)- 批量存储 var stringTasks = new List> - { - ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len), - ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len), - ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len), - ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len), - ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len), - ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len) - }; + { + ReadPlcStringAsync(plc, _op080_1StringMap["订单名称"].Addr, _op080_1StringMap["订单名称"].Len), + ReadPlcStringAsync(plc, _op080_1StringMap["产品名称"].Addr, _op080_1StringMap["产品名称"].Len), + ReadPlcStringAsync(plc, _op080_1StringMap["合装位机壳_SN"].Addr, _op080_1StringMap["合装位机壳_SN"].Len), + ReadPlcStringAsync(plc, _op080_1StringMap["合装位PCB_SN"].Addr, _op080_1StringMap["合装位PCB_SN"].Len), + ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位机壳_SN"].Addr, _op080_1StringMap["拧紧位机壳_SN"].Len), + ReadPlcStringAsync(plc, _op080_1StringMap["拧紧位PCB_SN"].Addr, _op080_1StringMap["拧紧位PCB_SN"].Len) + }; // 1.2 Int字段任务(17个)- 批量存储 var intTasks = new List> - { - // 基础状态字段 - ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]), - ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]), - ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]), - ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]), - ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]), - // 请求/托盘字段 - ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]), - ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]), - ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]), - ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]), - ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]), - // 螺钉结果字段(7个) - ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]), - ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"]) - }; + { + // 基础状态字段 + ReadPlcIntAsync(plc, _op080_1IntMap["运行状态"]), + ReadPlcIntAsync(plc, _op080_1IntMap["设备模式"]), + ReadPlcIntAsync(plc, _op080_1IntMap["设备在线状态"]), + ReadPlcIntAsync(plc, _op080_1IntMap["ByPass"]), + ReadPlcIntAsync(plc, _op080_1IntMap["生产模式"]), + // 请求/托盘字段 + ReadPlcIntAsync(plc, _op080_1IntMap["合装工位查询请求"]), + ReadPlcIntAsync(plc, _op080_1IntMap["合装结果保存请求"]), + ReadPlcIntAsync(plc, _op080_1IntMap["拧紧结果保存请求"]), + ReadPlcIntAsync(plc, _op080_1IntMap["合装位托盘号"]), + ReadPlcIntAsync(plc, _op080_1IntMap["拧紧位托盘号"]), + // 螺钉结果字段(7个) + ReadPlcIntAsync(plc, _op080_1IntMap["1号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["2号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["3号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["4号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["5号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["6号螺钉_结果"]), + ReadPlcIntAsync(plc, _op080_1IntMap["7号螺钉_结果"]) + }; // 1.3 Real字段任务(28个)- 按螺钉分组,批量存储(减少硬编码) var realTasks = new List>(); @@ -1410,9 +1592,9 @@ namespace RIZO.Admin.WebApi.PLC.Service // 螺钉结果(索引10-16) int[] screwResults = new[] { - intTasks[10].Result, intTasks[11].Result, intTasks[12].Result, - intTasks[13].Result, intTasks[14].Result, intTasks[15].Result, intTasks[16].Result - }; + intTasks[10].Result, intTasks[11].Result, intTasks[12].Result, + intTasks[13].Result, intTasks[14].Result, intTasks[15].Result, intTasks[16].Result + }; // 3.3 Real结果(按螺钉维度批量读取,索引0-27:7螺钉×4维度) float[] realResults = realTasks.Select(t => t.Result).ToArray(); @@ -1551,7 +1733,7 @@ namespace RIZO.Admin.WebApi.PLC.Service /// /// /// - private async Task ReadOP080_2DataAsync(Plc plc, string ip, string plcName) + private async Task ReadOP080_2DataAsync(Plc plc, string ip, string plcName) { try { @@ -2143,9 +2325,6 @@ namespace RIZO.Admin.WebApi.PLC.Service } } - /// - /// 修复版:异步读取PLC整数(DBW地址,16位短整型) - /// 增强类型兼容、异常日志、地址校验 /// /// PLC客户端实例 /// 读取地址(如DB1010.DBW226) @@ -2403,62 +2582,72 @@ namespace RIZO.Admin.WebApi.PLC.Service } } - //记录PLC过站状态 - private void RecordPlcOperationResult(string plcName, PlcProductionData prodData) + /// + /// 记录PLC过站状态 + /// + private async Task RecordPlcOperationResult(string plcName, PlcProductionData prodData) { + // 1. 入参校验(极致精简,减少分支和字符串操作) if (string.IsNullOrWhiteSpace(plcName)) - { throw new ArgumentNullException(nameof(plcName), "PLC/工位名称不能为空"); - } - if (prodData == null) - { + if (prodData is null) throw new ArgumentNullException(nameof(prodData), "PLC生产数据实体不能为空"); - } - string strSN = prodData.SN2?.Trim(); - if (string.IsNullOrWhiteSpace(strSN)) - { + + // 2. SN校验(直接判断,减少临时变量赋值) + if (string.IsNullOrWhiteSpace(prodData.SN2?.Trim())) return; - } - int result = string.Equals(prodData.QualificationFlag, "1", StringComparison.OrdinalIgnoreCase) ? 1 : 0; + var strSN = prodData.SN2.Trim(); // 仅在非空时赋值,减少内存分配 + + // 3. 合格状态转换(提前计算,减少后续引用开销) + var result = string.Equals(prodData.QualificationFlag, "1", StringComparison.OrdinalIgnoreCase) ? 1 : 0; + var now = DateTime.Now; try { - var existingRecord = _plcOperationResultService.Queryable() - .Where(it => it.Sn == strSN && it.Workstationcode == plcName).ToList().FirstOrDefault(); + var routingCode = await Context.Queryable() + .LeftJoin((r, o) => r.RoutingCode == o.FkRoutingCode) + .Where((r, o) => r.FkProductMaterialCode == strSN && r.Status == 1) + .Select((r, o) => o.FkRoutingCode) + .FirstAsync(); // 直接取第一条,避免ToList+First的双重开销 - if (existingRecord != null) + // 4.1 工艺路线校验(合并判断,减少分支) + if (string.IsNullOrWhiteSpace(routingCode)) { - // 情况1:记录存在 - if (existingRecord.Result == result) - { - return; - } - else - { - // 情况2:记录存在但结果不一致,执行修改操作 - existingRecord.Result = result; - existingRecord.UpdatedBy = "PLC"; - existingRecord.UpdatedTime = DateTime.Now; - _plcOperationResultService.Update(existingRecord); - } + Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - {strSN} 工艺路线无效,跳过记录"); + return; } - else + + // 5. 返工状态判断(无分配判断,直接赋值) + var productionLifeStage = string.Equals(prodData.ReworkFlag, "1", StringComparison.OrdinalIgnoreCase) ? 2 : 1; + + // 6. 构建记录(结构体思维,减少冗余字段) + var askOutStation = new ProductPassStationRecord { - // 情况3:记录不存在,执行新增操作 - PlcOperationResult porNew = new PlcOperationResult(); - porNew.Sn = strSN; - porNew.Workstationcode = plcName; - porNew.Result = result; - porNew.CreatedBy = "PLC"; - porNew.CreatedTime = DateTime.Now; - _plcOperationResultService.Insert(porNew); - } + ProductSN = strSN, + WorkstationCode = plcName, + Routingcode = routingCode, + OperationCode = plcName, + ProductionLifeStage = productionLifeStage, + PasstationType = 1, + ResultCode = result, + EffectTime = now, + CreatedTime = now + }; + + // 7. 插入数据库(批量插入优化,减少IO交互) + var insertCount = await Context.Insertable(askOutStation).ExecuteCommandAsync(); + + } + catch (ArgumentNullException ex) + { + Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - 入参异常:{ex.Message}"); + throw; } catch (Exception ex) { + Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - {strSN} 记录异常:{ex.Message}"); } } - /// /// 异步复位上传请求(独立方法,非阻塞) ///