PLC数采
This commit is contained in:
parent
e7fa8b518d
commit
b403a5f450
@ -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(双整数)读取任务(复用ReadPlcIntAsync,PLC底层兼容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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user