From a696db26d4f06080314450480aeee553d286a6c6 Mon Sep 17 00:00:00 2001 From: quowingwang Date: Tue, 3 Feb 2026 17:28:39 +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 --- Infrastructure/Model/OptionsSetting.cs | 3 + RIZO.Admin.WebApi/PLC/Service/PlcService.cs | 227 ++++++++++-------- RIZO.Admin.WebApi/Program.cs | 8 + RIZO.Admin.WebApi/appsettings.json | 47 ++-- .../Into/PlcIntoStationService_Common.cs | 202 ++++++++++------ .../Into/PlcIntoStationService_OP020-2.cs | 194 +++++++-------- .../Into/PlcIntoStationService_OP020-3.cs | 2 +- .../Into/PlcIntoStationService_OP020-4.cs | 2 +- .../Into/PlcIntoStationService_OP050-1.cs | 37 +++ .../Into/PlcIntoStationService_OP051Scan.cs | 37 +++ 10 files changed, 461 insertions(+), 298 deletions(-) create mode 100644 RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP050-1.cs create mode 100644 RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP051Scan.cs diff --git a/Infrastructure/Model/OptionsSetting.cs b/Infrastructure/Model/OptionsSetting.cs index 51627d7..9e700ae 100644 --- a/Infrastructure/Model/OptionsSetting.cs +++ b/Infrastructure/Model/OptionsSetting.cs @@ -209,6 +209,9 @@ namespace Infrastructure.Model public string ProductModel { get; set; } public string ProductSN { get; set; } public string IntoStationResp { get; set; } + public string IntoStationResp2 { get; set; } + public string IntoStationResp3 { get; set; } + public string IntoStationResp4 { get; set; } } } diff --git a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs index d62a3b2..16a3d38 100644 --- a/RIZO.Admin.WebApi/PLC/Service/PlcService.cs +++ b/RIZO.Admin.WebApi/PLC/Service/PlcService.cs @@ -60,18 +60,24 @@ namespace RIZO.Admin.WebApi.PLC.Service { { "设备使能", "DB1000.DBW0" }, // Int { "工位开始查询结果", "DB1000.DBW2000" }, // Int - { "1#产品结束保存结果", "DB1000.DBW2002" }, // Int - { "2#产品结束保存结果", "DB1000.DBW2004" }, // Int - { "3#产品结束保存结果", "DB1000.DBW2006" }, // Int - { "4#产品结束保存结果", "DB1000.DBW2008" }, // Int + { "保存结果1", "DB1000.DBW2002" }, // Int + { "保存结果2", "DB1000.DBW2004" }, // Int + { "保存结果3", "DB1000.DBW2006" }, // Int + { "保存结果4", "DB1000.DBW2008" }, // Int }; - private readonly Dictionary _mesop50IntReturnMap = new() + private readonly Dictionary _mesop050IntReturnMap = new() { { "设备使能", "DB300.DBW0" }, // Int - { "1#产品结束保存结果", "DB300.DBW48" }, // Int - { "2#产品结束保存结果", "DB300.DBW204" }, // Int - { "3#产品结束保存结果", "DB300.DBW360" }, // Int - { "4#产品结束保存结果", "DB300.DBW516" }, // Int + { "保存结果1", "DB300.DBW48" }, // Int + { "保存结果2", "DB300.DBW204" }, // Int + { "保存结果3", "DB300.DBW360" }, // Int + { "保存结果4", "DB300.DBW516" }, // Int + }; + private readonly Dictionary _mesop51ScanIntReturnMap = new() + { + { "设备使能", "DB1000.DBW0" }, // Int + { "工位开始查询结果", "DB1000.DBW2" }, // Int + { "保存结果", "DB1000.DBW4" }, // Int }; private readonly Dictionary _mesop058IntReturnMap = new() { @@ -112,13 +118,14 @@ namespace RIZO.Admin.WebApi.PLC.Service { "运行状态", "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=正常模式 + { "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.DBD1104" }, // DInt + { "合格数量", "DB1001.DBD1108" }, // DInt + { "失败数量", "DB1001.DBD1112" }, // DInt + { "查询请求", "DB1001.DBW2000" }, // Int - 1=请求开始,0=无请求 { "上传请求", "DB1001.DBW2002" }, // Int - 1=请求开始,0=无请求 { "托盘号", "DB1001.DBW2054" }, // Int { "总结果", "DB1001.DBW2158" }, // Int - 一个托盘上传四次结果 @@ -150,7 +157,7 @@ namespace RIZO.Admin.WebApi.PLC.Service { "上传请求", "DB1001.DBW2002" }, // Int - 1:请求开始,0:无请求 // 节拍时间 - { "节拍时间", "DB1001.DBD2988" }, // Real + { "节拍时间", "DB1001.DBD3030" }, // Real // 产品结果与产量 { "合格数量", "DB1001.DBD4110" }, // DInt @@ -158,12 +165,10 @@ namespace RIZO.Admin.WebApi.PLC.Service { "实际数量", "DB1001.DBD4118" } // DInt }; - // OP020-4 专属地址映射(pin压合&视觉检查工位,DB1001) private readonly Dictionary _op020_4StringMap = new() { { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte { "产品型号", ("DB1001.DBB1000", 48) }, // String[48] - { "产品名称", ("DB1001.DBB1054", 48) }, // String[48] { "产品1SN", ("DB1001.DBB2230", 40) }, // String[40] { "产品2SN", ("DB1001.DBB2360", 40) }, // String[40] { "产品3SN", ("DB1001.DBB2490", 40) }, // String[40] @@ -178,29 +183,34 @@ namespace RIZO.Admin.WebApi.PLC.Service { "设备在线状态", "DB1001.DBW4" }, // Int - 1=离线,0=在线 { "ByPass", "DB1001.DBW6" }, // Int - 1=ByPass,0=正常模式 { "生产模式", "DB1001.DBW8" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式 - + // 上传请求 + { "查询请求", "DB1001.DBW2000" }, // Int - 1:请求开始,0:无请求 { "产品1上传请求", "DB1001.DBW2002" }, // Int { "产品2上传请求", "DB1001.DBW2004" }, // Int { "产品3上传请求", "DB1001.DBW2006" }, // Int { "产品4上传请求", "DB1001.DBW2008" }, // Int - + // 托盘号 { "托盘号", "DB1001.DBW2070" }, // Int - + // 产品结果 { "产品1结果", "DB1001.DBW2274" }, // Int - 1:OK 2:NG { "产品2结果", "DB1001.DBW2404" }, // Int - 1:OK 2:NG { "产品3结果", "DB1001.DBW2534" }, // Int - 1:OK 2:NG { "产品4结果", "DB1001.DBW2664" }, // Int - 1:OK 2:NG - + + // 产量统计 + { "实际产量", "DB1001.DBD1104" }, // DInt + { "合格数量", "DB1001.DBD1108" }, // DInt + { "失败数量", "DB1001.DBD1112" } // DInt }; // OP050 专属地址映射(点白胶DC744工位,DB300) private readonly Dictionary _op050StringMap = new() { - { "报警信息", ("DB300.DBB680", 48) }, // Array[1..48] of Byte - { "产品型号", ("DB300.DBB728", 48) }, // String[48] + { "报警信息", ("DB300.DBB730", 48) }, // Array[1..48] of Byte + { "产品型号", ("DB300.DBB680", 48) }, // String[48] { "产品名称", ("DB300.DBB778", 48) }, // String[48] { "产品1SN", ("DB300.DBB50", 40) }, // String[40] { "产品2SN", ("DB300.DBB206", 40) }, // String[40] @@ -268,30 +278,31 @@ namespace RIZO.Admin.WebApi.PLC.Service { "节拍时间", "DB1001.DBD5086" }, // Real }; - // OP051扫码 专属地址映射(Coating扫码工位,假设使用 DB1002)//待PLC给出 + // OP051扫码 专属地址映射(Coating扫码工位,DB1001) 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] + { "报警信息", ("DB1001.DBB60", 48) }, // Array[0..48] of Byte + { "SN", ("DB1001.DBB110", 40) }, // String[40] - 查询条码 + { "SN_1", ("DB1001.DBB152", 40) }, // String[40] - 保存条码1 + { "SN_2", ("DB1001.DBB194", 40) }, // String[40] - 保存条码2 + { "SN_3", ("DB1001.DBB236", 40) }, // String[40] - 保存条码3 + { "托盘号", ("DB1001.DBB278", 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=预热模式 - + { "运行状态", "DB1001.DBW0" }, // Int - 1=空闲,2=运行中,3=故障 + { "设备模式", "DB1001.DBW2" }, // Int - 1=空模式;2=手动;4=初始化;8=自动;16=CycleStop + { "设备在线状态", "DB1001.DBW4" }, // Int - 1=离线,0=在线 + { "生产模式", "DB1001.DBW6" }, // Int - 1=正常模式;2=清线模式;4=返工模式;8=换型模式;16=预热模式 + // 操作请求 - { "查询请求", "DB1002.DBW44" }, // Int - 非0为查询 - { "上传结果请求", "DB1002.DBW46" }, // Int - 非0为上传 - - // 托盘号 - { "托盘号", "DB1002.DBW844" } // Int + { "查询请求", "DB1001.DBW320" }, // Int - 1:请求开始,0:无请求 + { "上传结果请求", "DB1001.DBW322" }, // Int - 1:请求开始,0:无请求 + + // 节拍时间 + { "节拍时间", "DB1001.DBD324" } // Real }; // OP057 专属地址映射(压装定位销&激光打标工位,DB1001) @@ -1076,7 +1087,9 @@ namespace RIZO.Admin.WebApi.PLC.Service { { "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte { "产品型号", ("DB1001.DBB1000", 48) }, // String[48] - { "产品名称", ("DB1001.DBB1054", 48) } // String[48] + { "产品名称", ("DB1001.DBB1054", 48) }, // String[48] + { "查询SN", ("DB1001.DBB2100", 40) }, // String[40] + { "保存SN", ("DB1001.DBB2230", 40) } // String[40] }; private readonly Dictionary _op115IntMap = new() @@ -1086,7 +1099,10 @@ namespace RIZO.Admin.WebApi.PLC.Service { "设备模式", "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=样件,5=正常 + { "生产模式", "DB1001.DBW8" }, // Int - 1=点检,2=返工,4=样件,5=正常 + // 操作请求 + { "工位查询请求", "DB1001.DBW2000" }, // Int - 1=请求开始,0=无请求 + { "结果保存请求", "DB1001.DBW2002" }, // Int - 1=请求开始,0=无请求 }; // OP140 专属地址映射(气密性测试工位,DB1001) @@ -1313,6 +1329,7 @@ namespace RIZO.Admin.WebApi.PLC.Service break; case "OP050": iSaveRequest = await ReadPlcIntAsync(plc, _op050IntMap["上传请求"]).ConfigureAwait(false); + if (iSaveRequest > 0) iSaveRequest = 1; break; case "OP050-1": var task5_1 = ReadPlcIntAsync(plc, _op050_1IntMap["产品1保存请求"]); @@ -1387,8 +1404,7 @@ namespace RIZO.Admin.WebApi.PLC.Service iSaveRequest = await ReadPlcIntAsync(plc, _op110_3IntMap["产品保存请求"]).ConfigureAwait(false); break; case "OP115": - //iSaveRequest = await ReadPlcIntAsync(plc, _op115IntMap["结果保存请求"]).ConfigureAwait(false); - iSaveRequest = 0; + iSaveRequest = await ReadPlcIntAsync(plc, _op115IntMap["结果保存请求"]).ConfigureAwait(false); break; case "OP140": iSaveRequest = await ReadPlcIntAsync(plc, _op140IntMap["结果保存请求"]).ConfigureAwait(false); @@ -1630,8 +1646,7 @@ namespace RIZO.Admin.WebApi.PLC.Service { "ByPass", ReadPlcIntAsync(plc, _op020_3IntMap["ByPass"]) }, { "生产模式", ReadPlcIntAsync(plc, _op020_3IntMap["生产模式"]) }, { "查询请求", ReadPlcIntAsync(plc, _op020_3IntMap["查询请求"]) }, - { "上传请求", ReadPlcIntAsync(plc, _op020_3IntMap["上传请求"]) }, - { "托盘号", ReadPlcIntAsync(plc, _op020_3IntMap["托盘号"]) } + { "上传请求", ReadPlcIntAsync(plc, _op020_3IntMap["上传请求"]) } }; // DInt/Real读取任务(产量+节拍时间,复用ReadPlcIntAsync兼容转换,与OP020-4风格一致) @@ -1664,7 +1679,6 @@ namespace RIZO.Admin.WebApi.PLC.Service int onlineStatus = intReadTasks["设备在线状态"].Result; int byPass = intReadTasks["ByPass"].Result; int produceModel = intReadTasks["生产模式"].Result; - int trayNo = intReadTasks["托盘号"].Result; // DInt/Real转换结果 int cycleTime = dIntRealReadTasks["节拍时间"].Result; @@ -1703,7 +1717,6 @@ namespace RIZO.Admin.WebApi.PLC.Service Runstatus = runStatus, OnlineStatus = onlineStatusDesc, ProduceModel = produceModelDesc, - TrayNo = trayNo.ToString(), CreatedBy = "PLC", CreatedTime = DateTime.Now, Product1SN = product1SN, @@ -1748,7 +1761,7 @@ namespace RIZO.Admin.WebApi.PLC.Service { { "报警信息", 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) }, @@ -1787,7 +1800,6 @@ namespace RIZO.Admin.WebApi.PLC.Service // 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; @@ -1831,7 +1843,6 @@ namespace RIZO.Admin.WebApi.PLC.Service WorkstationCode = workstationCode, WorkstationName = "pin压合&视觉检查", // 补充工站名称 ProductModel = productModel, - ProductName = productName, ProductCode = product1SN, // 主产品编码取产品1SN(可根据业务调整) ReworkFlag = reworkFlag, Automanual = machineModel, @@ -2140,20 +2151,26 @@ namespace RIZO.Admin.WebApi.PLC.Service /// PLC生产数据实体 public async Task ReadOP051ScanDataAsync(Plc plc, string ip, string workstationCode) { - if (plc == null || !plc.IsConnected) return null; + // 1. 入参校验(强化兜底,更严谨) + if (plc == null || !plc.IsConnected) + { + Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] PLC未连接或实例为空,无法读取OP051扫码工位数据"); + return null; + } if (string.IsNullOrWhiteSpace(ip)) throw new ArgumentNullException(nameof(ip), "PLC IP地址不能为空"); if (string.IsNullOrWhiteSpace(workstationCode)) throw new ArgumentNullException(nameof(workstationCode), "工位编码不能为空"); try { - // 1. 批量创建并行读取任务(按类型分类,最大化并行效率) + // 2. 批量创建并行读取任务(完全匹配点位表,无多余读取,添加空值兜底) var stringTasks = new Dictionary> { - { "产品型号", ReadPlcStringAsync(plc, _op051ScanStringMap["产品型号"].Addr, _op051ScanStringMap["产品型号"].Len) }, - { "产品名称", ReadPlcStringAsync(plc, _op051ScanStringMap["产品名称"].Addr, _op051ScanStringMap["产品名称"].Len) }, + { "报警信息", ReadPlcStringAsync(plc, _op051ScanStringMap["报警信息"].Addr, _op051ScanStringMap["报警信息"].Len) }, + { "查询条码", ReadPlcStringAsync(plc, _op051ScanStringMap["SN"].Addr, _op051ScanStringMap["SN"].Len) }, { "SN_1", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_1"].Addr, _op051ScanStringMap["SN_1"].Len) }, { "SN_2", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_2"].Addr, _op051ScanStringMap["SN_2"].Len) }, - { "SN_3", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_3"].Addr, _op051ScanStringMap["SN_3"].Len) } + { "SN_3", ReadPlcStringAsync(plc, _op051ScanStringMap["SN_3"].Addr, _op051ScanStringMap["SN_3"].Len) }, + { "托盘号", ReadPlcStringAsync(plc, _op051ScanStringMap["托盘号"].Addr, _op051ScanStringMap["托盘号"].Len) } }; var intTasks = new Dictionary> @@ -2163,32 +2180,24 @@ namespace RIZO.Admin.WebApi.PLC.Service { "设备在线状态", ReadPlcIntAsync(plc, _op051ScanIntMap["设备在线状态"]) }, { "生产模式", ReadPlcIntAsync(plc, _op051ScanIntMap["生产模式"]) }, { "查询请求", ReadPlcIntAsync(plc, _op051ScanIntMap["查询请求"]) }, - { "上传结果请求", ReadPlcIntAsync(plc, _op051ScanIntMap["上传结果请求"]) }, - { "托盘号", ReadPlcIntAsync(plc, _op051ScanIntMap["托盘号"]) } + { "上传结果请求", ReadPlcIntAsync(plc, _op051ScanIntMap["上传结果请求"]) } }; - // DInt(双整数)读取任务(复用ReadPlcIntAsync,PLC底层兼容DInt转int) - var dIntReadTasks = new Dictionary> - { - { "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) }, - { "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) }, - { "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) } - }; - - // 2. 并行等待所有任务完成(单次WaitAll,最小化等待时间) - var allTasks = new List(); - allTasks.AddRange(stringTasks.Values); - allTasks.AddRange(dIntReadTasks.Values); - allTasks.AddRange(intTasks.Values); + // 3. 并行等待所有任务完成(最小化等待时间,ConfigureAwait(false)提升异步效率) + var allTasks = new List() + .Concat(stringTasks.Values) + .Concat(intTasks.Values) + .ToList(); await Task.WhenAll(allTasks).ConfigureAwait(false); - // 3. 提取结果(直接取值,空值兜底,减少内存分配) - var now = DateTime.Now; // 单次获取时间,减少系统调用 - var productModel = stringTasks["产品型号"].Result; - var productName = stringTasks["产品名称"].Result; - var sn1 = stringTasks["SN_1"].Result; - var sn2 = stringTasks["SN_2"].Result; - var sn3 = stringTasks["SN_3"].Result; + // 4. 提取结果(空值兜底,避免NullReferenceException,简化取值逻辑) + var now = DateTime.Now; + var alarmInfo = stringTasks["报警信息"].Result ?? string.Empty; + var querySn = stringTasks["查询条码"].Result ?? string.Empty; + var sn1 = stringTasks["SN_1"].Result ?? string.Empty; + var sn2 = stringTasks["SN_2"].Result ?? string.Empty; + var sn3 = stringTasks["SN_3"].Result ?? string.Empty; + var trayNo = stringTasks["托盘号"].Result ?? string.Empty; var runStatus = intTasks["运行状态"].Result; var machineModel = intTasks["设备模式"].Result; @@ -2196,13 +2205,8 @@ namespace RIZO.Admin.WebApi.PLC.Service var produceModel = intTasks["生产模式"].Result; var queryRequest = intTasks["查询请求"].Result; var uploadRequest = intTasks["上传结果请求"].Result; - var trayNo = intTasks["托盘号"].Result.ToString(); // 转换为字符串,适配实体字段 - int actualOutput = dIntReadTasks["实际产量"].Result; - int qualifiedQty = dIntReadTasks["合格数量"].Result; - int failedQty = dIntReadTasks["失败数量"].Result; - - // 4. 核心逻辑转换(极简表达式,适配扫码工位业务) + // 5. 核心逻辑转换(极简表达式,适配扫码工位业务,注释清晰) var reworkFlag = produceModel == 4 ? "1" : "0"; // 4=返工模式→1,其他→0 var produceModelDesc = produceModel switch { @@ -2218,18 +2222,15 @@ namespace RIZO.Admin.WebApi.PLC.Service var uploadRequestDesc = uploadRequest != 0 ? "有上传请求" : "无上传请求"; var qualificationFlag = "1"; // 扫码工位默认合格(无检测结果,可根据业务调整) - - // 6. 构建并返回实体(适配扫码工位特性,精简字段) + // 6. 构建并返回实体(完全匹配点位表数据,精简无冗余字段,修正注释错误) return new PlcProductionData { PlcIp = ip, OccurTime = now, - LineCode = "line2", // 可改为参数传入 + LineCode = "line2", // 建议后续改为参数传入,提升方法通用性 WorkstationCode = workstationCode, - WorkstationName = "Coating扫码", // 补充工站名称 - ProductModel = productModel, - ProductName = productName, - ProductCode = sn2, // 主SN用SN_1 + WorkstationName = "Coating扫码", + ProductCode = sn1, // 修正注释与代码不一致:主SN使用SN_1 ReworkFlag = reworkFlag, Automanual = machineModel, Runstatus = runStatus, @@ -2242,16 +2243,20 @@ namespace RIZO.Admin.WebApi.PLC.Service Product2SN = sn2, Product3SN = sn3, QualificationFlag = qualificationFlag, - ActualOutQty = actualOutput.ToString(), - QualifiedQty = qualifiedQty.ToString(), - FailedQty = failedQty.ToString(), CreatedBy = "PLC", - CreatedTime = now, + CreatedTime = now }; } + catch (KeyNotFoundException ex) + { + // 精准捕获键不存在异常(点位表与读取逻辑不匹配时快速定位) + Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP051扫码工位读取异常:点位表中不存在指定键 -> {ex.Message}"); + return null; + } catch (Exception ex) { - Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP051扫码工位读取异常:{ex.Message}"); + // 通用异常捕获,保留完整异常堆栈便于排查 + Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] OP051扫码工位读取异常:{ex.ToString()}"); return null; } } @@ -4750,8 +4755,10 @@ namespace RIZO.Admin.WebApi.PLC.Service var stringTasks = new Dictionary> { { "产品型号", ReadPlcStringAsync(plc, _op115StringMap["产品型号"].Addr, _op115StringMap["产品型号"].Len) }, - { "产品名称", ReadPlcStringAsync(plc, _op115StringMap["产品名称"].Addr, _op115StringMap["产品名称"].Len) } - }; + { "产品名称", ReadPlcStringAsync(plc, _op115StringMap["产品名称"].Addr, _op115StringMap["产品名称"].Len) }, + {"查询SN", ReadPlcStringAsync(plc, _op115StringMap["查询SN"].Addr, _op110_3StringMap["查询SN"].Len) }, + { "保存SN", ReadPlcStringAsync(plc, _op115StringMap["保存SN"].Addr, _op110_3StringMap["保存SN"].Len) } + }; var intTasks = new Dictionary> { @@ -4776,6 +4783,8 @@ namespace RIZO.Admin.WebApi.PLC.Service var machineModel = intTasks["设备模式"].Result; var onlineStatus = intTasks["设备在线状态"].Result; var produceModel = intTasks["生产模式"].Result; + var sn1 = stringTasks["查询SN"].Result ?? string.Empty; + var sn2 = stringTasks["保存SN"].Result ?? string.Empty; // 4. 业务逻辑转换 var reworkFlag = produceModel == 2 ? "1" : "0"; @@ -4801,6 +4810,9 @@ namespace RIZO.Admin.WebApi.PLC.Service WorkstationName = "自动上下料到固化炉工位", ProductModel = productModel, ProductName = productName, + ProductCode = sn1, + SN1 = sn1, + SN2 = sn2, ReworkFlag = reworkFlag, Automanual = machineModel, Runstatus = runStatus, @@ -5651,12 +5663,29 @@ namespace RIZO.Admin.WebApi.PLC.Service { try { + if (plcName == "OP020-4" || plcName == "OP050-1") + { + WritePlcValue(plc, _mesop20_4IntReturnMap["保存结果1"], saveResult); + WritePlcValue(plc, _mesop20_4IntReturnMap["保存结果2"], saveResult); + WritePlcValue(plc, _mesop20_4IntReturnMap["保存结果3"], saveResult); + WritePlcValue(plc, _mesop20_4IntReturnMap["保存结果4"], saveResult); + return; + } + if (plcName == "OP050") + { + WritePlcValue(plc, _mesop050IntReturnMap["保存结果1"], saveResult); + WritePlcValue(plc, _mesop050IntReturnMap["保存结果2"], saveResult); + WritePlcValue(plc, _mesop050IntReturnMap["保存结果3"], saveResult); + WritePlcValue(plc, _mesop050IntReturnMap["保存结果4"], saveResult); + return; + } var targetMap = plcName switch { - "OP20-3" => _mesop20_3IntReturnMap, - "OP20-4" => _mesop20_4IntReturnMap, - "OP50-1" => _mesop20_4IntReturnMap, + "OP020-3" => _mesop20_3IntReturnMap, + //"OP020-4" => _mesop20_4IntReturnMap, + //"OP050-1" => _mesop20_4IntReturnMap, //"OP050" => _mesop050IntReturnMap,//四个保存结果 + "OP051扫码" => _mesop51ScanIntReturnMap, "OP058" => _mesop058IntReturnMap, "OP075" => _mesop075IntReturnMap, "OP080-1" => _mesop080_1IntReturnMap, diff --git a/RIZO.Admin.WebApi/Program.cs b/RIZO.Admin.WebApi/Program.cs index 15bc3bf..8dfee1c 100644 --- a/RIZO.Admin.WebApi/Program.cs +++ b/RIZO.Admin.WebApi/Program.cs @@ -112,6 +112,12 @@ builder.Services.AddLocalization(options => options.ResourcesPath = ""); //PLC进站后台服务注册 //builder.Services.AddHostedService(); +builder.Services.AddHostedService< PlcIntoStationService_OP020_2>(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); +builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); @@ -120,6 +126,8 @@ builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); +builder.Services.AddHostedService(); + //螺丝枪服务注册 //builder.Services.AddHostedService(); diff --git a/RIZO.Admin.WebApi/appsettings.json b/RIZO.Admin.WebApi/appsettings.json index 9a99ccc..58f422f 100644 --- a/RIZO.Admin.WebApi/appsettings.json +++ b/RIZO.Admin.WebApi/appsettings.json @@ -114,7 +114,7 @@ "PlcSettings": [ { "Id": 1, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP020-2", "WorkStationName": "OP020-2 合盖", "PlcType": "S71500", @@ -123,13 +123,13 @@ "Heartbeat": "DB1000.DBW0", // 心跳地址 "IntoStationAsk": "DB1001.DBW2000", // 进站请求地址 "ProductModel": "DB1001.DBB1000", - "ProductSN": "DB1001.DBB1054", - "IntoStationResp": "DB1000.DBW2002" // 进站回复结果地址 + "ProductSN": "DB1001.DBB2106", + "IntoStationResp": "DB1000.DBW2000" // 进站回复结果地址 } }, { "Id": 2, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP020-3", "WorkStationName": "OP020-3 热铆", @@ -145,7 +145,7 @@ }, { "Id": 3, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP020-4", "WorkStationName": "OP020-4 pin压合&视觉检查", "PlcType": "S71500", @@ -160,22 +160,25 @@ }, { "Id": 4, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP050", "WorkStationName": "OP050 点白胶DC744", "PlcType": "S71500", "IpAddress": "192.168.10.1", "IntoStation": { "Heartbeat": "DB300.DBW0", // 心跳地址 - "IntoStationAsk": "DB300.DBW42", // 进站请求地址 - "ProductModel": "DB300.DBB728", - "ProductSN": "DB300.DBB778", - "IntoStationResp": "DB300.DBW46" // 进站回复结果地址 + "IntoStationAsk": "DB300.DBW44", // 进站请求地址 + "ProductModel": "DB300.DBB680", + "ProductSN": "DB300.DBB50", + "IntoStationResp": "DB300.DBW46", // 进站回复结果地址 + "IntoStationResp2": "DB300.DBW202", + "IntoStationResp3": "DB300.DBW358", + "IntoStationResp4": "DB300.DBW514" } }, { "Id": 5, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP050-1", "WorkStationName": "OP050-1 自动下料", "PlcType": "S71500", @@ -190,17 +193,17 @@ }, { "Id": 41, - "isEnble": false, - "WorkStationCode": "OP51扫码", - "WorkStationName": "OP51扫码 Coating扫码", + "isEnble": true, + "WorkStationCode": "OP051扫码", + "WorkStationName": "OP051扫码 Coating扫码", "PlcType": "S71500", - "IpAddress": "待定", + "IpAddress": "192.168.0.1", "IntoStation": { - "Heartbeat": "待定", // 心跳地址 - "IntoStationAsk": "待定", // 进站请求地址 + "Heartbeat": "DB1000.DBW0", // 心跳地址 + "IntoStationAsk": "DB1001.DBW320", // 进站请求地址 "ProductModel": "待定", - "ProductSN": "待定", - "IntoStationResp": "待定" // 进站回复结果地址 + "ProductSN": "DB1001.DBW110", + "IntoStationResp": "DB1000.DBW2" // 进站回复结果地址 } }, @@ -536,16 +539,16 @@ }, { "Id": 23, - "isEnble": false, + "isEnble": true, "WorkStationCode": "OP115", "WorkStationName": "OP115 自动上下料到固化炉", "PlcType": "S71500", - "IpAddress": "192.168.11.231", + "IpAddress": "192.168.12.11", "IntoStation": { "Heartbeat": "DB1000.DBW0", // 心跳地址 "IntoStationAsk": "DB1001.DBW2000", // 进站请求地址 "ProductModel": "DB1001.DBB1000", - "ProductSN": "DB1001.DBB1054", + "ProductSN": "DB1001.DBB2100", "IntoStationResp": "DB1000.DBW2000" // 进站回复结果地址 } }, diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_Common.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_Common.cs index d43eccf..0f32c55 100644 --- a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_Common.cs +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_Common.cs @@ -44,96 +44,142 @@ namespace RIZO.Service.PLCBackground.Stations.Into _optionsSetting= options.Value; } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.Info("PLC Polling Service started"); - // 使用工厂方法创建服务实例 - - // 获取当前的工序/工站 - //WorkstationCode = await Context.Queryable().Where(it => it.PlcIP == plcSetting.IpAddress) - // .Select(it => it.WorkstationCode).FirstAsync(); - plcSetting = _optionsSetting.PlcSettings.Where(it => it.WorkStationCode == WorkstationCode).First(); - Enum.TryParse(plcSetting.PlcType, out CpuType cpuType); - - if (!plcSetting.isEnble) + try { - return; - } - - using (_plcService = new PlcConntectHepler(plcSetting.IpAddress, cpuType)) - { - - while (!stoppingToken.IsCancellationRequested) - + // 1. 优化:配置查询增加空值判断,避免未找到配置抛出异常 + plcSetting = _optionsSetting.PlcSettings + .FirstOrDefault(it => it.WorkStationCode == WorkstationCode); + if (plcSetting == null) { - try + _logger.Error($"未找到工站 {WorkstationCode} 对应的 PLC 配置,服务退出"); + return; + } + + // 2. 优化:判断 Enum 解析结果,避免无效 PLC 连接 + if (!Enum.TryParse(plcSetting.PlcType, out CpuType cpuType)) + { + _logger.Error($"工站 {WorkstationCode} 的 PLC 类型 {plcSetting.PlcType} 解析失败,服务退出"); + return; + } + + // 配置未启用,直接退出 + if (!plcSetting.isEnble) + { + _logger.Info($"工站 {WorkstationCode} 的 PLC 配置未启用,服务退出"); + return; + } + + // 保持原有 using 语法,确保 PLC 连接资源自动释放 + using (_plcService = new PlcConntectHepler(plcSetting.IpAddress, cpuType)) + { + while (!stoppingToken.IsCancellationRequested) { - //心跳检测 "DB1010.DBW0" - // await _plcService.WriteAsync(plcSetting.intoStation.Heartbeat, (short)1); - await _plcService.WriteAsync2(plcSetting.intoStation.Heartbeat, 1); - // 轮询进站请求信号/工位开始查询请求 "DB1001.DBW2000" - short intoStationAsk = await _plcService.ReadAsync(plcSetting.intoStation.IntoStationAsk); - if (intoStationAsk == 1) + try { - // 处理进站请求 - _logger.Info("Processing into station request..."); + // 心跳检测 + await _plcService.WriteAsync2(plcSetting.intoStation.Heartbeat, 1); - //获取产品SN码 "DB1001.DBB1000" - // string productModel = await _plcService.ReadStringAsync(plcSetting.intoStation.ProductModel); - string productModel = ReadPlcStringAsync(_plcService._plc, plcSetting.intoStation.ProductModel, 48).Result; - //"DB1001.DBB1054" - //string productSN = await _plcService.ReadStringAsync(plcSetting.intoStation.ProductSN); - string productSN = ReadPlcStringAsync(_plcService._plc, plcSetting.intoStation.ProductSN, 48).Result; + // 轮询进站请求信号 + short intoStationAsk = await _plcService.ReadAsync(plcSetting.intoStation.IntoStationAsk); - // 获取工单 - - //获取工艺路线工序 - List processOperations = await Context.Queryable().LeftJoin((r, o) => r.RoutingCode == o.FkRoutingCode) - .Where((r, o) => r.FkProductMaterialCode == productModel && r.Status == 1) - .Select((r, o) => o).ToListAsync(); - //判断改产品是正常件还是返工件 - - string Routingcode = processOperations?.First()?.FkRoutingCode ?? ""; - //插入入站请求ASK过站记录 - ProductPassStationRecord ASKintoStation = new ProductPassStationRecord + if (intoStationAsk > 0) { - ProductSN = productSN, - WorkstationCode = WorkstationCode, - Routingcode = Routingcode, - OperationCode = WorkstationCode, - OperationName= plcSetting.WorkStationName, - ProductionLifeStage = 1, // 1表示生产中 - PasstationType = 0, // 0表示入站请求 - PasstationDescription = "入站请求ASK", - EffectTime = DateTime.Now, - CreatedTime = DateTime.Now, - }; - await Context.Insertable(ASKintoStation).ExecuteCommandAsync(); - //判断该产品是否允许进站 - EntryPermissionResult result = await checkEntryPermission(productModel, productSN, WorkstationCode, processOperations); - // "DB1010.DBW2000" - // await _plcService.WriteAsync(plcSetting.intoStation.IntoStationResp, (short)result); - await _plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp,(int) result); - } - await Task.Delay(_pollingInterval, stoppingToken); + _logger.Info("Processing into station request..."); - } - catch (OperationCanceledException ex) - { - _logger.Info("PLC Polling Service is stopping"); - break; - } - catch (Exception ex) - { - _logger.Error(ex, "PLC polling error"); - await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); + // 3. 优化:消除 Task.Result 阻塞,改为异步 await,且并行执行两个 PLC 读操作 + Task productModelTask = ReadPlcStringAsync(_plcService._plc, plcSetting.intoStation.ProductModel, 48); + Task productSNTask = ReadPlcStringAsync(_plcService._plc, plcSetting.intoStation.ProductSN, 48); + await Task.WhenAll(productModelTask, productSNTask); + + string productModel = productModelTask.Result; + string productSN = productSNTask.Result; + + string Routingcode = ""; + List processOperations = new List(); + bool isSkipPermissionCheck = WorkstationCode == "OP051扫码" || WorkstationCode == "OP115"; + + if (!isSkipPermissionCheck) + { + // 5. 优化:数据库查询传入取消令牌,支持服务快速停止 + processOperations = await Context.Queryable() + .LeftJoin((r, o) => r.RoutingCode == o.FkRoutingCode) + .Where((r, o) => r.FkProductMaterialCode == productModel && r.Status == 1) + .Select((r, o) => o) + .ToListAsync(stoppingToken); + + Routingcode = processOperations?.FirstOrDefault()?.FkRoutingCode ?? ""; + } + + // 插入入站请求ASK过站记录(保留原有业务逻辑) + ProductPassStationRecord ASKintoStation = new ProductPassStationRecord + { + ProductSN = productSN, + WorkstationCode = WorkstationCode, + Routingcode = Routingcode, + OperationCode = WorkstationCode, + OperationName = plcSetting.WorkStationName, + ProductionLifeStage = 1, // 1表示生产中 + PasstationType = 0, // 0表示入站请求 + PasstationDescription = "入站请求ASK", + EffectTime = DateTime.Now, + CreatedTime = DateTime.Now, + }; + await Context.Insertable(ASKintoStation).ExecuteCommandAsync(stoppingToken); + + if (!isSkipPermissionCheck) + { + // 判断该产品是否允许进站 + EntryPermissionResult result = await checkEntryPermission(productModel, productSN, WorkstationCode, processOperations); + + // 6. 优化:OP050 的多个写操作并行执行,减少 PLC 通信耗时 + var plcWriteTasks = new List(); + plcWriteTasks.Add(_plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp, (int)result)); + + if (WorkstationCode == "OP050") + { + plcWriteTasks.Add(_plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp2, (int)result)); + plcWriteTasks.Add(_plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp3, (int)result)); + plcWriteTasks.Add(_plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp4, (int)result)); + } + + // 并行执行所有写操作,提升 PLC 反馈效率 + await Task.WhenAll(plcWriteTasks); + } + else + { + // 直接允许进站 + await _plcService.WriteAsync2(plcSetting.intoStation.IntoStationResp, 1); + } + } + + // 轮询延迟,保留取消令牌,服务停止时无需等待延迟完成 + await Task.Delay(_pollingInterval, stoppingToken); + } + catch (OperationCanceledException) + { + _logger.Info("PLC Polling Service is stopping"); + break; + } + catch (Exception ex) + { + _logger.Error(ex, "PLC polling error"); + await Task.Delay(10, stoppingToken); + } } } } - - _logger.Info("PLC Polling Service stopped"); + catch (Exception ex) + { + _logger.Error(ex, "PLC Polling Service encountered fatal error during initialization"); + } + finally + { + _logger.Info("PLC Polling Service stopped"); + } } /// @@ -196,9 +242,9 @@ namespace RIZO.Service.PLCBackground.Stations.Into // 2. 清理 OperationCode:去除首尾空格 + 移除 \r 等不可见控制字符(兼容你之前的问题) string cleanOperationCode = LastOperation.OperationCode - .Replace("\r", "") // 移除回车符 - .Replace("\n", "") // 可选:移除换行符 - .Trim(); // 移除首尾空格 + .Replace("\r", "") + .Replace("\n", "") + .Trim(); productSN = productSN.Replace("\r", "").Replace("\n", "").Trim(); // 3. 构建并执行真正的异步查询(补充执行方法,使 await 生效) var ExistLastOperationRecord = await DbScoped.SugarScope.CopyNew() diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-2.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-2.cs index b6ddf6c..1f44162 100644 --- a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-2.cs +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-2.cs @@ -29,7 +29,7 @@ namespace RIZO.Service.PLCBackground.Stations.Into { public PlcIntoStationService_OP020_2(IOptions options) : base(options) { - WorkstationCode = "OP020_2"; + WorkstationCode = "OP020-2"; } /// @@ -38,122 +38,122 @@ namespace RIZO.Service.PLCBackground.Stations.Into /// 产品型号 /// 产品SN /// - protected override async Task checkEntryPermission(string productModel, string productSN, string workstationCode, List processOperations) - { + //protected override async Task checkEntryPermission(string productModel, string productSN, string workstationCode, List processOperations) + //{ - EntryPermissionResult result = EntryPermissionResult.UnkownException; + // EntryPermissionResult result = EntryPermissionResult.UnkownException; - //2上工位无记录 + // //2上工位无记录 - //ProcessOperation LastOperation = processOperations.Where(operation => operation.OperationSeq < processOperations.Where(it => it.OperationCode == workstationCode).Select(it => it.OperationSeq).First()).OrderByDescending(operation => operation.OperationSeq).First(); - int LastOperationSeq = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.LastOperationSeq ?? -1).First(); - ProcessOperation LastOperation = processOperations.Where(it => it.OperationSeq == LastOperationSeq).First(); - bool isExistLastOperationRecord = await DbScoped.SugarScope.CopyNew().Queryable() - .Where(it => it.ProductSN == productSN) - .Where(it => it.OperationCode == LastOperation.OperationCode) - .AnyAsync(); - if (!isExistLastOperationRecord) - { - return EntryPermissionResult.NoRecordAtPreviousStation; - } + // //ProcessOperation LastOperation = processOperations.Where(operation => operation.OperationSeq < processOperations.Where(it => it.OperationCode == workstationCode).Select(it => it.OperationSeq).First()).OrderByDescending(operation => operation.OperationSeq).First(); + // int LastOperationSeq = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.LastOperationSeq ?? -1).First(); + // ProcessOperation LastOperation = processOperations.Where(it => it.OperationSeq == LastOperationSeq).First(); + // bool isExistLastOperationRecord = await DbScoped.SugarScope.CopyNew().Queryable() + // .Where(it => it.ProductSN == productSN) + // .Where(it => it.OperationCode == LastOperation.OperationCode) + // .AnyAsync(); + // if (!isExistLastOperationRecord) + // { + // return EntryPermissionResult.NoRecordAtPreviousStation; + // } - // 3 上工位NG 入站或者出站结果 NG - bool isExistLastOperationNG = await Context.Queryable() - .Where(it => it.ProductSN == productSN) - .Where(it => it.OperationCode == LastOperation.OperationCode) - .Where(it => it.PasstationType == 2 || it.PasstationType == 4) - .Where(it => it.ResultCode != 1) - .AnyAsync(); - if (!isExistLastOperationNG) - { - result = EntryPermissionResult.PreviousStationNG; - goto InsertPassrecord; - } + // // 3 上工位NG 入站或者出站结果 NG + // bool isExistLastOperationNG = await Context.Queryable() + // .Where(it => it.ProductSN == productSN) + // .Where(it => it.OperationCode == LastOperation.OperationCode) + // .Where(it => it.PasstationType == 2 || it.PasstationType == 4) + // .Where(it => it.ResultCode != 1) + // .AnyAsync(); + // if (!isExistLastOperationNG) + // { + // result = EntryPermissionResult.PreviousStationNG; + // goto InsertPassrecord; + // } - // 4 扫码产品型号错误 - bool isExistproductSN = await Context.Queryable() - .Where(it => it.ProductSN == productSN).AnyAsync(); + // // 4 扫码产品型号错误 + // bool isExistproductSN = await Context.Queryable() + // .Where(it => it.ProductSN == productSN).AnyAsync(); - bool isExistproductSNProducting = await Context.Queryable() - .Where(it => it.ProductSN == productSN && (it.ProductCurrentStatus != 1 && it.ProductCurrentStatus != 3)).AnyAsync(); - if (!isExistproductSN || !isExistproductSNProducting) - { - result = EntryPermissionResult.ProductModelError; - goto InsertPassrecord; - } - //6时间超出规定无法生产 + // bool isExistproductSNProducting = await Context.Queryable() + // .Where(it => it.ProductSN == productSN && (it.ProductCurrentStatus != 1 && it.ProductCurrentStatus != 3)).AnyAsync(); + // if (!isExistproductSN || !isExistproductSNProducting) + // { + // result = EntryPermissionResult.ProductModelError; + // goto InsertPassrecord; + // } + // //6时间超出规定无法生产 - //7固化时间未到规定时间 + // //7固化时间未到规定时间 - int LastOperationStandardTime = processOperations.Where(operation => operation.OperationCode == LastOperation.OperationCode) - .Select(operation => operation.StandardTime ?? 0).First(); + // int LastOperationStandardTime = processOperations.Where(operation => operation.OperationCode == LastOperation.OperationCode) + // .Select(operation => operation.StandardTime ?? 0).First(); - if (LastOperationStandardTime > 0) - { - // 上一站的入站时间 和本站的请求时间差值 - DateTime LastInStationTime = await Context.Queryable() - .Where(it => it.ProductSN == productSN) - .Where(it => it.OperationCode == LastOperation.OperationCode) - .Where(it => it.PasstationType == 1) - .MaxAsync(it => it.InStationTime ?? DateTime.MinValue); - TimeSpan timeDiff = DateTime.Now - LastInStationTime; - double totalSeconds = timeDiff.TotalSeconds; - if (totalSeconds < LastOperationStandardTime) - { - result = EntryPermissionResult.CuringTimeNotReached; - goto InsertPassrecord; - } + // if (LastOperationStandardTime > 0) + // { + // // 上一站的入站时间 和本站的请求时间差值 + // DateTime LastInStationTime = await Context.Queryable() + // .Where(it => it.ProductSN == productSN) + // .Where(it => it.OperationCode == LastOperation.OperationCode) + // .Where(it => it.PasstationType == 1) + // .MaxAsync(it => it.InStationTime ?? DateTime.MinValue); + // TimeSpan timeDiff = DateTime.Now - LastInStationTime; + // double totalSeconds = timeDiff.TotalSeconds; + // if (totalSeconds < LastOperationStandardTime) + // { + // result = EntryPermissionResult.CuringTimeNotReached; + // goto InsertPassrecord; + // } - } + // } - //12 最大重复入站次数 - int MaxRepeatEntries = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.MaxStationCount ?? 1).First(); - if (MaxRepeatEntries > 1) - { - int currentStationEntryCount = await Context.Queryable() - .Where(it => it.ProductSN == productSN) - .Where(it => it.OperationCode == workstationCode) - .Where(it => it.PasstationType == 1) - .CountAsync(); - if (currentStationEntryCount >= MaxRepeatEntries) - { - result = EntryPermissionResult.MaximumRepeatedEntries; - goto InsertPassrecord; - } - } + // //12 最大重复入站次数 + // int MaxRepeatEntries = processOperations.Where(operation => operation.OperationCode == workstationCode).Select(operation => operation.MaxStationCount ?? 1).First(); + // if (MaxRepeatEntries > 1) + // { + // int currentStationEntryCount = await Context.Queryable() + // .Where(it => it.ProductSN == productSN) + // .Where(it => it.OperationCode == workstationCode) + // .Where(it => it.PasstationType == 1) + // .CountAsync(); + // if (currentStationEntryCount >= MaxRepeatEntries) + // { + // result = EntryPermissionResult.MaximumRepeatedEntries; + // goto InsertPassrecord; + // } + // } - //OK 准许进站 - result = EntryPermissionResult.AllowIntoStation; - goto InsertPassrecord; - InsertPassrecord: - //插入入站请求Resp过站记录 - ProductPassStationRecord RespintoStation = new ProductPassStationRecord - { - ProductSN = productSN, - WorkstationCode = WorkstationCode, - Routingcode = processOperations?.First()?.FkRoutingCode ?? "", - OperationCode = WorkstationCode, - OperationName = plcSetting.WorkStationName, - ProductionLifeStage = 1, // 1表示生产中 - PasstationType = 1, // 入站完毕 - PasstationDescription = "入站完毕Resp", - EffectTime = DateTime.Now, - InStationTime = DateTime.Now, - ResultCode = (int)result, - ResultDescription = result.ToString(), - CreatedTime = DateTime.Now, + // //OK 准许进站 + // result = EntryPermissionResult.AllowIntoStation; + // goto InsertPassrecord; + //InsertPassrecord: + // //插入入站请求Resp过站记录 + // ProductPassStationRecord RespintoStation = new ProductPassStationRecord + // { + // ProductSN = productSN, + // WorkstationCode = WorkstationCode, + // Routingcode = processOperations?.First()?.FkRoutingCode ?? "", + // OperationCode = WorkstationCode, + // OperationName = plcSetting.WorkStationName, + // ProductionLifeStage = 1, // 1表示生产中 + // PasstationType = 1, // 入站完毕 + // PasstationDescription = "入站完毕Resp", + // EffectTime = DateTime.Now, + // InStationTime = DateTime.Now, + // ResultCode = (int)result, + // ResultDescription = result.ToString(), + // CreatedTime = DateTime.Now, - }; - await Context.Insertable(RespintoStation).ExecuteCommandAsync(); + // }; + // await Context.Insertable(RespintoStation).ExecuteCommandAsync(); - return result; - } + // return result; + //} } diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-3.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-3.cs index 43a389e..3d0badd 100644 --- a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-3.cs +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-3.cs @@ -29,7 +29,7 @@ namespace RIZO.Service.PLCBackground.Stations.Into { public PlcIntoStationService_OP020_3(IOptions options) : base(options) { - WorkstationCode = "OP020_3"; + WorkstationCode = "OP020-3"; } } diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-4.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-4.cs index f15f2be..9fca810 100644 --- a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-4.cs +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP020-4.cs @@ -29,7 +29,7 @@ namespace RIZO.Service.PLCBackground.Stations.Into { public PlcIntoStationService_OP020_4(IOptions options) : base(options) { - WorkstationCode = "OP020_4"; + WorkstationCode = "OP020-4"; } } diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP050-1.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP050-1.cs new file mode 100644 index 0000000..bcede5e --- /dev/null +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP050-1.cs @@ -0,0 +1,37 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using Infrastructure.Model; +using MDM.Model.Plant; +using MDM.Model.Process; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NLog; +using RIZO.Model.Mes; +using RIZO.Model.MES.product_trace; +using RIZO.Repository; +using RIZO.Service.MES.product.IService; +using RIZO.Service.PLC; +using S7.Net; +using SqlSugar.IOC; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace RIZO.Service.PLCBackground.Stations.Into +{ + /// + /// OP点散热胶GF1500 + /// + [AppService(ServiceType = typeof(PlcIntoStationService_OP050_1), ServiceLifetime = LifeTime.Singleton)] + public class PlcIntoStationService_OP050_1 : PlcIntoStationService_Common + { + public PlcIntoStationService_OP050_1(IOptions options) : base(options) + { + WorkstationCode = "OP050-1"; + } + } + +} + diff --git a/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP051Scan.cs b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP051Scan.cs new file mode 100644 index 0000000..c1a732a --- /dev/null +++ b/RIZO.Service/PLCBackground/Stations/Into/PlcIntoStationService_OP051Scan.cs @@ -0,0 +1,37 @@ +using Infrastructure.Attribute; +using Infrastructure.Extensions; +using Infrastructure.Model; +using MDM.Model.Plant; +using MDM.Model.Process; +using Microsoft.AspNetCore.JsonPatch.Operations; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NLog; +using RIZO.Model.Mes; +using RIZO.Model.MES.product_trace; +using RIZO.Repository; +using RIZO.Service.MES.product.IService; +using RIZO.Service.PLC; +using S7.Net; +using SqlSugar.IOC; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace RIZO.Service.PLCBackground.Stations.Into +{ + /// + /// OP点散热胶GF1500 + /// + [AppService(ServiceType = typeof(PlcIntoStationService_OP051Scan), ServiceLifetime = LifeTime.Singleton)] + public class PlcIntoStationService_OP051Scan : PlcIntoStationService_Common + { + public PlcIntoStationService_OP051Scan(IOptions options) : base(options) + { + WorkstationCode = "OP051扫码"; + } + } + +} +