PLC数采

This commit is contained in:
quowingwang 2026-01-27 14:27:04 +08:00
parent e7fa8b518d
commit b403a5f450

View File

@ -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<string, (Plc Client, DateTime LastUsedTime)> _plcConnPool = new(); // 连接池
private readonly SqlSugarClient Context;
public PlcService()
{
Context = DbScoped.SugarScope.CopyNew();
}
#region PLC地址块儿映射
//MES返回PLC请求映射
private readonly Dictionary<string, string> _mesIntReturnMap = new()
@ -127,6 +135,95 @@ namespace RIZO.Admin.WebApi.PLC.Service
};
// OP050 专属地址映射点白胶DC744工位DB300
private readonly Dictionary<string, (string Addr, int Len)> _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<string, string> _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<string, (string Addr, int Len)> _op050_1StringMap = new()
{
{ "报警信息", ("DB1001.DBB58", 48) }, // Array[1..48] of Byte
{ "产品型号", ("DB1001.DBB1000", 48) }, // String[48]
{ "产品名称", ("DB1001.DBB1054", 48) } // String[48]
};
private readonly Dictionary<string, string> _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<string, (string Addr, int Len)> _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<string, string> _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<string, (string Addr, int Len)> _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
/// <summary>
/// 读取OP020-2数据合盖工位
/// </summary>
private async Task<PlcProductionData> ReadOP020_2DataAsync(Plc plc, string ip, string workstationCode)
private async Task<PlcProductionData?> 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;
}
}
/// <summary>
/// 读取OP020-4数据pin压合&视觉检查工位)
/// </summary>
private async Task<PlcProductionData> ReadOP020_4DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(最大化并行效率,减少临时变量开销)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", 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<string, Task<int>>
{
{ "运行状态", 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<Task>();
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;
}
}
/// <summary>
/// 读取OP050数据点白胶DC744工位
/// </summary>
/// <param name="plc">PLC连接实例</param>
/// <param name="ip">PLC的IP地址</param>
/// <param name="workstationCode">工位编码</param>
/// <returns>PLC生产数据实体</returns>
private async Task<PlcProductionData> ReadOP050DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(最大化并行效率,按字段类型分类)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", 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<string, Task<int>>
{
{ "运行状态", ReadPlcIntAsync(plc, _op050IntMap["运行状态"]) },
{ "设备模式", ReadPlcIntAsync(plc, _op050IntMap["设备模式"]) },
{ "设备在线状态", ReadPlcIntAsync(plc, _op050IntMap["设备在线状态"]) },
{ "ByPass", ReadPlcIntAsync(plc, _op050IntMap["ByPass"]) },
{ "生产模式", ReadPlcIntAsync(plc, _op050IntMap["生产模式"]) },
{ "托盘号", ReadPlcIntAsync(plc, _op050IntMap["托盘号"]) }
};
// DInt双整数读取任务复用ReadPlcIntAsyncPLC底层兼容DInt转int
var dIntReadTasks = new Dictionary<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050IntMap["失败数量"]) }
};
// Real浮点型读取任务新增ReadPlcRealAsync方法返回float
var realReadTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op050IntMap["节拍时间"]) }
};
// 2. 并行等待所有读取任务完成合并所有任务列表单次WaitAll提升效率
var allTasks = new List<Task>();
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;
}
}
/// <summary>
/// 读取OP050-1数据自动下料工位DB1001
/// </summary>
private async Task<PlcProductionData> ReadOP050_1DataAsync(Plc plc, string ip, string workstationCode)
{
// 前置校验PLC连接无效直接返回避免无效操作
if (plc == null || !plc.IsConnected)
{
return null;
}
try
{
// 1. 批量创建并行读取任务(按字段类型分类,最大化并行效率)
var stringReadTasks = new Dictionary<string, Task<string>>
{
{ "报警信息", 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<string, Task<int>>
{
{ "运行状态", 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<string, Task<int>>
{
{ "实际产量", ReadPlcIntAsync(plc, _op050_1IntMap["实际产量"]) },
{ "合格数量", ReadPlcIntAsync(plc, _op050_1IntMap["合格数量"]) },
{ "失败数量", ReadPlcIntAsync(plc, _op050_1IntMap["失败数量"]) }
};
// Real浮点型读取任务节拍时间
var realReadTasks = new Dictionary<string, Task<float>>
{
{ "节拍时间", ReadPlcRealAsync(plc, _op050_1IntMap["节拍时间"]) }
};
// 2. 并行等待所有读取任务完成单次WaitAll最小化等待时间
var allTasks = new List<Task>();
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;
}
}
/// <summary>
/// OP070-1数据读取 - 效率优化版
/// </summary>
private async Task<PlcProductionData> ReadOP070_1DataAsync(Plc plc, string ip, string workstationCode)
private async Task<PlcProductionData?> 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
/// <summary>
/// OP075数据读取
/// </summary>
private async Task<PlcProductionData> ReadOP075DataAsync(Plc plc, string ip, string workstationCode)
private async Task<PlcProductionData?> 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
}
}
///// <summary>
///// 读取OP080-1数据 - 效率优化版
///// </summary>
//private async Task<PlcProductionData> 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 = "读取异常"
// };
// }
//}
/// <summary>
/// 读取OP080-1数据 - 极致优化版(批量并行+内存复用+异步优化)
/// </summary>
@ -1320,7 +1502,7 @@ namespace RIZO.Admin.WebApi.PLC.Service
/// <param name="workstationCode">工位编码</param>
/// <param name="strSaveRequest">保存请求类型</param>
/// <returns>PLC生产数据</returns>
private async Task<PlcProductionData> ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest)
private async Task<PlcProductionData?> ReadOP080_1DataAsync(Plc plc, string ip, string workstationCode, string strSaveRequest)
{
// 前置核心校验避免无效PLC操作节省10+ms无效耗时
if (plc == null || !plc.IsConnected)
@ -1551,7 +1733,7 @@ namespace RIZO.Admin.WebApi.PLC.Service
/// <param name="workstationCode"></param>
/// <returns></returns>
/// <summary>
private async Task<PlcProductionData> ReadOP080_2DataAsync(Plc plc, string ip, string plcName)
private async Task<PlcProductionData?> ReadOP080_2DataAsync(Plc plc, string ip, string plcName)
{
try
{
@ -2143,9 +2325,6 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
}
/// <summary>
/// 修复版异步读取PLC整数DBW地址16位短整型
/// 增强类型兼容、异常日志、地址校验
/// </summary>
/// <param name="plc">PLC客户端实例</param>
/// <param name="addr">读取地址如DB1010.DBW226</param>
@ -2403,62 +2582,72 @@ namespace RIZO.Admin.WebApi.PLC.Service
}
}
//记录PLC过站状态
private void RecordPlcOperationResult(string plcName, PlcProductionData prodData)
/// <summary>
/// 记录PLC过站状态
/// </summary>
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<ProcessRouting>()
.LeftJoin<ProcessOperation>((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)
{
// 情况1记录存在
if (existingRecord.Result == result)
// 4.1 工艺路线校验(合并判断,减少分支)
if (string.IsNullOrWhiteSpace(routingCode))
{
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
{
// 情况2记录存在但结果不一致执行修改操作
existingRecord.Result = result;
existingRecord.UpdatedBy = "PLC";
existingRecord.UpdatedTime = DateTime.Now;
_plcOperationResultService.Update(existingRecord);
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();
}
}
else
catch (ArgumentNullException ex)
{
// 情况3记录不存在执行新增操作
PlcOperationResult porNew = new PlcOperationResult();
porNew.Sn = strSN;
porNew.Workstationcode = plcName;
porNew.Result = result;
porNew.CreatedBy = "PLC";
porNew.CreatedTime = DateTime.Now;
_plcOperationResultService.Insert(porNew);
}
Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - 入参异常:{ex.Message}");
throw;
}
catch (Exception ex)
{
Console.WriteLine($"[{now:HH:mm:ss}] {plcName} - {strSN} 记录异常:{ex.Message}");
}
}
/// <summary>
/// 异步复位上传请求(独立方法,非阻塞)
/// </summary>