首次提交
This commit is contained in:
506
SCADA/Funtion/B_DB_Opera.cs
Normal file
506
SCADA/Funtion/B_DB_Opera.cs
Normal file
@@ -0,0 +1,506 @@
|
||||
using DC_A95;
|
||||
using ExternalDataSync;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库操作
|
||||
/// </summary>
|
||||
public class B_DB_Opera
|
||||
{
|
||||
|
||||
public static void Event_WorkStart(string opName, int tagTypeCodeID, string partType, string tagID)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_WorkStart";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@PartType", partType),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
public static void Event_WorkEnd(string opName, int tagTypeCodeID, string partType
|
||||
, string barCode, int qualityMask, int outCount, int duration
|
||||
, string tagID)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_WorkEnd";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@PartType", partType),
|
||||
new SqlParameter("@BarCode", barCode),
|
||||
new SqlParameter("@QualityMask", qualityMask),
|
||||
new SqlParameter("@OutCount", outCount),
|
||||
new SqlParameter("@Duration", duration),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID)
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
}
|
||||
|
||||
|
||||
public static void Event_Signal_Log(string opName, int tagTypeCodeID, string value, string tagID)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_Signal_Log";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@Value", value),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID)
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
}
|
||||
|
||||
|
||||
public static void Event_Alarm_Start(string opName, int tagTypeCodeID, string alarmText, string alarmLevel, string tagID)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_Alarm_Start";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@AlarmText", alarmText),
|
||||
new SqlParameter("@AlarmLevel", alarmLevel),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID)
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void Event_Alarm_End(string opName, int tagTypeCodeID, string alarmText, string alarmLevel, string tagID)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_Alarm_End";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@AlarmText", alarmText),
|
||||
new SqlParameter("@AlarmLevel", alarmLevel),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID)
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
public static void Event_AlarmAndTip_Start(string opName, int tagTypeCodeID, string alarmText, string tagID, int Alarm1_Tip2)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_AlarmAndTip_Start";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@TagTypeCodeID", tagTypeCodeID),
|
||||
new SqlParameter("@AlarmText", alarmText),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
new SqlParameter("@TagID", tagID),
|
||||
new SqlParameter("@Alarm1_Tip2", Alarm1_Tip2),
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
public static void MES_StatusChange(string opName, int StatusCode, string TriggerTime)
|
||||
{
|
||||
var procedureName = "设备管理_状态变化新增";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@opName", opName),
|
||||
new SqlParameter("@StatusCode", StatusCode),
|
||||
new SqlParameter("@TriggerTime", TriggerTime),
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void Query_AlarmData(string opName, out int count, out string text)
|
||||
{
|
||||
count = 0;
|
||||
text = "";
|
||||
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Query_AlarmData";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out DataTable dt, out string errorMessage);
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
count = Convert.ToInt32(dt.Rows[0]["COUNT"].ToString());
|
||||
text = dt.Rows[0]["TEXT"].ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void Event_DeviceStatus_UseTime(string opName, string Onhours, string Workhours, string DeviceStatus)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_DeviceStatus_UseTime";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@Onhours", Onhours),
|
||||
new SqlParameter("@Workhours", Workhours),
|
||||
new SqlParameter("@DeviceStatus", DeviceStatus),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
public static void Event_DeviceStatus_Change(string opName, string DeviceStatus)
|
||||
{
|
||||
var ChangeTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var procedureName = "Event_DeviceStatus_Change";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@OpName", opName),
|
||||
new SqlParameter("@DeviceStatus", DeviceStatus),
|
||||
new SqlParameter("@ChangeTime",ChangeTime),
|
||||
};
|
||||
|
||||
SqlOperation.ExecuteStoredProcedure(procedureName, sqlParameter, out string errorMessage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志记录
|
||||
/// </summary>
|
||||
public static void SaveLog_Request(string StationName, Log_Type LogType, string ReqCode, Log_FromAndTo ReqFrom, Log_FromAndTo ReqTo, string ReqStr, out long AID, string ReqStrSafe = "")
|
||||
{
|
||||
AID = -1;
|
||||
var CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
ReqStr = PLC_R.GetString_CleanGarbled(ReqStr);
|
||||
|
||||
var param1 = new SqlParameter[] {
|
||||
new SqlParameter("@工位号", StationName),
|
||||
new SqlParameter("@日志类型", LogType.ToString()),
|
||||
new SqlParameter("@TaskID", ReqCode),
|
||||
new SqlParameter("@请求CMD",""),
|
||||
new SqlParameter("@请求FROM",ReqFrom.ToString()),
|
||||
new SqlParameter("@请求TO",ReqTo.ToString()),
|
||||
new SqlParameter("@请求时间",CreateTime),
|
||||
new SqlParameter("@请求内容",ReqStr),
|
||||
new SqlParameter("@请求内容安全",ReqStrSafe)
|
||||
};
|
||||
DataLinkMesWork.SQLCommon.ExecuteStoredProcedure("Event_Log_Request", MesWorkForm.ConnectionString, ref param1, out DataTable dt, out string errorMessage);
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
AID = Convert.ToInt64(dt.Rows[0]["AID"]);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 响应日志记录
|
||||
/// </summary>
|
||||
public static void SaveLog_Response(string result, long AID)
|
||||
{
|
||||
try
|
||||
{
|
||||
var CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
|
||||
var param4 = new SqlParameter[]
|
||||
{
|
||||
new SqlParameter("@AID",AID),
|
||||
new SqlParameter("@响应时间",CreateTime),
|
||||
new SqlParameter("@响应内容",JsonConvert.SerializeObject(result))
|
||||
};
|
||||
DataLinkMesWork.SQLCommon.ExecuteStoredProcedure("Event_Log_Respond", MesWorkForm.ConnectionString, ref param4, out string errorMessage);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ====================================================================
|
||||
// 称重业务数据库方法(调用存储过程,统一 result/msg 返回格式)
|
||||
// ====================================================================
|
||||
|
||||
/// <summary>
|
||||
/// 从工件管理表查询机型参数(加油量/抽油量/密度/残油量上下限)
|
||||
/// </summary>
|
||||
public static bool QueryWorkpieceByModel(string modelNo, out decimal addOilQty, out decimal extractOilQty, out decimal density,
|
||||
out decimal residualOilUpperLimit, out decimal residualOilLowerLimit)
|
||||
{
|
||||
addOilQty = 0; extractOilQty = 0; density = 0; residualOilUpperLimit = 0; residualOilLowerLimit = 0;
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@机型号", modelNo)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重_查询工件参数", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
var row = dt.Rows[0];
|
||||
decimal.TryParse(row["加油量"]?.ToString(), out addOilQty);
|
||||
decimal.TryParse(row["抽油量"]?.ToString(), out extractOilQty);
|
||||
decimal.TryParse(row["密度"]?.ToString(), out density);
|
||||
decimal.TryParse(row["残油量上限"]?.ToString(), out residualOilUpperLimit);
|
||||
decimal.TryParse(row["残油量下限"]?.ToString(), out residualOilLowerLimit);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 插入称重记录
|
||||
/// </summary>
|
||||
/// <returns>新记录ID,失败返回-1</returns>
|
||||
public static long InsertWeighingRecord(
|
||||
string stationNo, string weighType, string engineNo, string modelNo,
|
||||
string orderNo, string palletNo,
|
||||
decimal inWeight, decimal outWeight,
|
||||
decimal addOilQty, decimal extractOilQty, decimal density,
|
||||
decimal residualOilUpperLimit, decimal residualOilLowerLimit,
|
||||
decimal oilRelease, decimal residualOil,
|
||||
int qualityFlag, decimal waterContent,
|
||||
string dataSource, string worker, int isComplete)
|
||||
{
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@工位号", stationNo),
|
||||
new SqlParameter("@称重类型", weighType),
|
||||
new SqlParameter("@发动机号", engineNo),
|
||||
new SqlParameter("@机型号", modelNo),
|
||||
new SqlParameter("@工单号", orderNo),
|
||||
new SqlParameter("@托盘号", palletNo),
|
||||
new SqlParameter("@进站重量", inWeight),
|
||||
new SqlParameter("@离站重量", outWeight),
|
||||
new SqlParameter("@加油量", addOilQty),
|
||||
new SqlParameter("@抽油量", extractOilQty),
|
||||
new SqlParameter("@密度", density),
|
||||
new SqlParameter("@残油量上限", residualOilUpperLimit),
|
||||
new SqlParameter("@残油量下限", residualOilLowerLimit),
|
||||
new SqlParameter("@放油量", oilRelease),
|
||||
new SqlParameter("@残油量", residualOil),
|
||||
new SqlParameter("@合格标志", qualityFlag),
|
||||
new SqlParameter("@水含量", waterContent),
|
||||
new SqlParameter("@数据来源", dataSource),
|
||||
new SqlParameter("@操作者", worker),
|
||||
new SqlParameter("@是否完成", isComplete)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重记录_增加", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
return Convert.ToInt64(dt.Rows[0]["ID"]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询放油前记录(按发动机号匹配,称重类型='空中'且未完成)
|
||||
/// </summary>
|
||||
public static bool QueryWeighingBeforeOil(string engineNo, out long recordId, out decimal preWeight, out decimal addOilQty, out decimal extractOilQty, out decimal density)
|
||||
{
|
||||
recordId = 0; preWeight = 0; addOilQty = 0; extractOilQty = 0; density = 0;
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@发动机号", engineNo)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重记录_查询放油前", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
var row = dt.Rows[0];
|
||||
recordId = Convert.ToInt64(row["ID"]);
|
||||
decimal.TryParse(row["进站重量"]?.ToString(), out preWeight);
|
||||
decimal.TryParse(row["加油量"]?.ToString(), out addOilQty);
|
||||
decimal.TryParse(row["抽油量"]?.ToString(), out extractOilQty);
|
||||
decimal.TryParse(row["密度"]?.ToString(), out density);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询指定工位最新的称重记录(不过滤完成状态)
|
||||
/// </summary>
|
||||
public static bool QueryLatestRecord(string stationNo, string engineNo,
|
||||
out long recordId, out decimal preWeight,
|
||||
out decimal addOilQty, out decimal extractOilQty, out decimal density)
|
||||
{
|
||||
recordId = 0; preWeight = 0; addOilQty = 0; extractOilQty = 0; density = 0;
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@工位号", stationNo),
|
||||
new SqlParameter("@发动机号", engineNo)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重记录_查询最新", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
var row = dt.Rows[0];
|
||||
recordId = Convert.ToInt64(row["ID"]);
|
||||
decimal.TryParse(row["进站重量"]?.ToString(), out preWeight);
|
||||
decimal.TryParse(row["加油量"]?.ToString(), out addOilQty);
|
||||
decimal.TryParse(row["抽油量"]?.ToString(), out extractOilQty);
|
||||
decimal.TryParse(row["密度"]?.ToString(), out density);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新称重记录为完成状态(保存称重结果)
|
||||
/// </summary>
|
||||
public static bool UpdateWeighingComplete(long recordId, string weighType, string stationNo,
|
||||
decimal weight, decimal oilRelease, decimal residualOil, decimal waterContent, out int qualityFlag, out string msg)
|
||||
{
|
||||
qualityFlag = 2;
|
||||
msg = "";
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@ID", recordId),
|
||||
new SqlParameter("@称重类型", weighType),
|
||||
new SqlParameter("@工位号", stationNo),
|
||||
new SqlParameter("@称重重量", weight),
|
||||
new SqlParameter("@放油量", oilRelease),
|
||||
new SqlParameter("@残油量", residualOil),
|
||||
new SqlParameter("@水含量", waterContent)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重记录_完成更新", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt == null || dt.Rows.Count == 0)
|
||||
{
|
||||
msg = string.IsNullOrEmpty(err) ? "称重记录完成更新未返回结果" : err;
|
||||
return false;
|
||||
}
|
||||
|
||||
qualityFlag = Convert.ToInt32(dt.Rows[0]["result"]);
|
||||
msg = dt.Rows[0]["msg"].ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 过站记录操作方法
|
||||
// ====================================================================
|
||||
|
||||
/// <summary>
|
||||
/// 新增过站记录(case 44 请求工作时调用)
|
||||
/// </summary>
|
||||
public static long InsertStationRecord(string engineNo, string modelNo, string orderNo, string palletNo,
|
||||
string stationNo, string stationName, decimal addOilQty, decimal extractOilQty, decimal density, string worker)
|
||||
{
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@发动机号", engineNo),
|
||||
new SqlParameter("@机型号", modelNo),
|
||||
new SqlParameter("@工单号", orderNo),
|
||||
new SqlParameter("@托盘号", palletNo),
|
||||
new SqlParameter("@工位号", stationNo),
|
||||
new SqlParameter("@工位名称", stationName),
|
||||
new SqlParameter("@加油量", addOilQty),
|
||||
new SqlParameter("@抽油量", extractOilQty),
|
||||
new SqlParameter("@油密度", density),
|
||||
new SqlParameter("@操作者", worker)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("过站记录_新增", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
return Convert.ToInt64(dt.Rows[0]["ID"]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新过站记录为完成(case 19 请求保存时调用)
|
||||
/// </summary>
|
||||
public static bool UpdateStationComplete(string engineNo, string stationNo, decimal weight)
|
||||
{
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@发动机号", engineNo),
|
||||
new SqlParameter("@工位号", stationNo),
|
||||
new SqlParameter("@称重重量", weight)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("过站记录_完成", sqlParameter, out DataTable dt, out string err);
|
||||
return dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1";
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// 称重曲线数据操作方法
|
||||
// ====================================================================
|
||||
|
||||
/// <summary>
|
||||
/// 创建曲线段记录(工件到位时调用)
|
||||
/// </summary>
|
||||
/// <returns>段ID,失败返回-1</returns>
|
||||
public static long Curve_StartSegment(string opName, string engineNo, string modelNo)
|
||||
{
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@工位号", opName),
|
||||
new SqlParameter("@发动机号", engineNo),
|
||||
new SqlParameter("@机型号", modelNo ?? (object)DBNull.Value)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重曲线_开始段", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
return Convert.ToInt64(dt.Rows[0]["ID"]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量写入曲线采样点(采集线程每攒够N条调用一次)
|
||||
/// </summary>
|
||||
/// <param name="segmentId">段ID</param>
|
||||
/// <param name="points">采样点列表</param>
|
||||
/// <returns>写入条数,失败返回0</returns>
|
||||
public static int Curve_WritePoints(long segmentId, List<CurveSamplePoint> points)
|
||||
{
|
||||
if (points == null || points.Count == 0) return 0;
|
||||
|
||||
// 用 JSON 序列化避免小数区域格式和字符串拼接转义问题。
|
||||
var json = JsonConvert.SerializeObject(points.Select(p => new
|
||||
{
|
||||
seq = p.SeqNo,
|
||||
time = p.SampleTime.ToString("yyyy-MM-ddTHH:mm:ss.fff"),
|
||||
weight = p.Weight
|
||||
}));
|
||||
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@段ID", segmentId),
|
||||
new SqlParameter("@采样数据", json)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重曲线_批量写入", sqlParameter, out DataTable dt, out string err);
|
||||
if (dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
return Convert.ToInt32(dt.Rows[0]["count"]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束曲线段(请求保存时调用,关联称重记录ID)
|
||||
/// </summary>
|
||||
public static bool Curve_EndSegment(long segmentId, long weighingRecordId)
|
||||
{
|
||||
var sqlParameter = new SqlParameter[] {
|
||||
new SqlParameter("@段ID", segmentId),
|
||||
new SqlParameter("@称重记录ID", weighingRecordId > 0 ? (object)weighingRecordId : DBNull.Value)
|
||||
};
|
||||
SqlOperation.ExecuteStoredProcedure("称重曲线_结束段", sqlParameter, out DataTable dt, out string err);
|
||||
return dt != null && dt.Rows.Count > 0 && dt.Rows[0]["result"].ToString() == "1";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 曲线采样点数据结构
|
||||
/// </summary>
|
||||
public class CurveSamplePoint
|
||||
{
|
||||
public int SeqNo;
|
||||
public DateTime SampleTime;
|
||||
public decimal Weight;
|
||||
}
|
||||
}
|
||||
40
SCADA/Funtion/MIS_Device.cs
Normal file
40
SCADA/Funtion/MIS_Device.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using DC_A95;
|
||||
using OpcBasic;
|
||||
using OpcData;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using SystemFramework;
|
||||
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备状态的处理
|
||||
/// </summary>
|
||||
public partial class MesWorkForm
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 设备状态的处理
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
private void MIS_Device(object e)
|
||||
{
|
||||
var eState = (DeviceDriver_BasicData.PlcStateEvetnArgs)e;
|
||||
var ip = eState.IP.ToString();
|
||||
var onLine = eState.OnLine;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
509
SCADA/Funtion/MIS_Funtion.cs
Normal file
509
SCADA/Funtion/MIS_Funtion.cs
Normal file
@@ -0,0 +1,509 @@
|
||||
using ExternalDataSync;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using DC_A95;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
namespace MesWork
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理MIS逻辑
|
||||
/// </summary>
|
||||
public partial class MesWorkForm
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC信号变化处理入口
|
||||
/// 当Bool型信号值变化时由框架自动触发
|
||||
/// </summary>
|
||||
/// <param name="e"></param>
|
||||
private void MIS_Funtion(object e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var msgEvent = (DeviceDriver_BasicData.CustomeEvetnArgs)e;
|
||||
if (msgEvent.TagValue == null) return;
|
||||
var tagID = msgEvent.TagID.ToString();
|
||||
var opName = msgEvent.OpName.ToString();
|
||||
var tagTypeCodeID = (int)msgEvent.TagTypeCodeID;
|
||||
var tagTypeID = (EnumTagTypeID)msgEvent.TagTypeID;
|
||||
var isFirstValue = msgEvent.IsFirstValue.ToString().ToLower();
|
||||
var alarmLevel = msgEvent.ShaftID.ToString();
|
||||
var alarmMsg = msgEvent.ItemName.ToString();
|
||||
string tagValue;
|
||||
switch (tagTypeID)
|
||||
{
|
||||
case EnumTagTypeID.BOOL:
|
||||
tagValue = (Convert.ToInt32(msgEvent.TagValue)).ToString();
|
||||
break;
|
||||
default:
|
||||
tagValue = msgEvent.TagValue.ToString();
|
||||
break;
|
||||
}
|
||||
// ── 报警处理(编码900~2000)──
|
||||
if (tagTypeCodeID >= 900 & tagTypeCodeID < 2000)
|
||||
{
|
||||
if (ValueT(isFirstValue))
|
||||
{
|
||||
//不处理第一次变化的值
|
||||
return;
|
||||
}
|
||||
var opNameNew = opName.Replace("_Alarm", "");
|
||||
if (tagValue == "1")
|
||||
{
|
||||
B_DB_Opera.Event_Alarm_Start(opNameNew, tagTypeCodeID, alarmMsg, alarmLevel, tagID);
|
||||
}
|
||||
else
|
||||
{
|
||||
B_DB_Opera.Event_Alarm_End(opNameNew, tagTypeCodeID, alarmMsg, alarmLevel, tagID);
|
||||
}
|
||||
}
|
||||
// ── 信号分发 ──
|
||||
switch (tagTypeCodeID)
|
||||
{
|
||||
case 2: // 工件到位 → 启动/停止实时重量曲线采集
|
||||
if (tagValue == "1")
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{opName}] 工件到位信号触发");
|
||||
CurveCollector_Start(opName);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurveCollector_Stop(opName);
|
||||
}
|
||||
break;
|
||||
case 14: // PLC心跳 → 回写PC心跳
|
||||
WritePLC_IF(15, opName, tagValue);
|
||||
break;
|
||||
case 44: // 请求工作
|
||||
if (ValueT(isFirstValue)) return;
|
||||
if (tagValue == "1")
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{opName}] PLC请求工作,开始处理...");
|
||||
Weighing_HandleRequestWork(opName, tagID);
|
||||
}
|
||||
else
|
||||
{
|
||||
WritePLC_IF(66, opName, false); //允许工作
|
||||
}
|
||||
break;
|
||||
case 19: // 请求保存
|
||||
if (ValueT(isFirstValue)) return;
|
||||
if (tagValue == "1")
|
||||
{
|
||||
CurveCollector_StopSampling(opName, true); // 先停止采样,保存完成后再关联称重记录ID
|
||||
WeighingPage?.AppendLog($"[{opName}] PLC请求保存数据...");
|
||||
Weighing_HandleRequestSave(opName, tagID);
|
||||
}
|
||||
else
|
||||
{
|
||||
WritePLC_IF(20, opName, false); //保存完成
|
||||
WritePLC_IF(21, opName, false); //合格标志
|
||||
}
|
||||
break;
|
||||
case 203: // 设备状态
|
||||
B_DB_Opera.Event_DeviceStatus_Change(opName, tagValue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{ }
|
||||
}
|
||||
// ====================================================================
|
||||
// 称重交互核心方法
|
||||
// ====================================================================
|
||||
/// <summary>
|
||||
/// 获取称重类型:地面/放油前/放油后
|
||||
/// Ground模式:统一返回"地面"
|
||||
/// Hanging模式:OP10=放油前,OP20=放油后
|
||||
/// </summary>
|
||||
private string GetWeighingType(string opName)
|
||||
{
|
||||
if (WeighingType == "Ground")
|
||||
return "地面";
|
||||
// Hanging模式
|
||||
return opName == "OP10" ? "放油前" : "放油后";
|
||||
}
|
||||
/// <summary>
|
||||
/// 处理请求工作信号 (tagTypeCodeID=44)
|
||||
/// 流程:读取工件信息 → 查询参数 → 写过站记录 → 按类型处理称重记录 → 回写允许工作
|
||||
/// </summary>
|
||||
private void Weighing_HandleRequestWork(string opName, string tagID)
|
||||
{
|
||||
B_DB_Opera.SaveLog_Request(opName, Log_Type.ZK_MesHandler, "MIS_Function",
|
||||
Log_FromAndTo.ZK, Log_FromAndTo.ZK, $"触发信号【44-请求工作】", out long AID);
|
||||
try
|
||||
{
|
||||
// 1. 读取PLC工件信息
|
||||
string engineNo = PLC_R.GetString_CleanGarbled(ReadPLC(10, opName)); // 总成编号
|
||||
string modelNo = PLC_R.GetString_CleanGarbled(ReadPLC(11, opName)); // 机型号
|
||||
string orderNo = PLC_R.GetString_CleanGarbled(ReadPLC(39, opName)); // 工单号
|
||||
string palletNo = PLC_R.GetString_CleanGarbled(ReadPLC(80, opName)); // 托盘号
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】读取工件:发动机={engineNo},机型={modelNo},工单={orderNo},托盘={palletNo}", AID);
|
||||
// 推送工件信息到称重UI
|
||||
int stIdx = WeighingPage?.GetStationIndex(opName) ?? 1;
|
||||
WeighingPage?.UpdateStationInfo(stIdx, engineNo, modelNo, orderNo);
|
||||
WeighingPage?.AppendLog($"[{opName}] 读取工件:{engineNo},机型={modelNo}");
|
||||
// 2. 查询工件管理参数(加油量/抽油量/密度/残油量上下限)
|
||||
if (!B_DB_Opera.QueryWorkpieceByModel(modelNo, out decimal addOilQty, out decimal extractOilQty, out decimal density,
|
||||
out decimal residualOilUpperLimit, out decimal residualOilLowerLimit))
|
||||
{
|
||||
WritePLC_IF(112, opName, 3); // 报警代码=3,机型错误
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】工件管理中未找到机型[{modelNo}]的参数,发动机={engineNo}", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] 机型[{modelNo}]未找到配置参数");
|
||||
return;
|
||||
}
|
||||
// 3. 推送工件参数到UI
|
||||
WeighingPage?.UpdateOilInfo(stIdx, addOilQty, extractOilQty, density, 0, 0);
|
||||
// 4. 确定称重类型和工位名称
|
||||
string weighType = GetWeighingType(opName); // 地面/放油前/放油后
|
||||
string stationName = weighType; // 工位名称直接用称重类型名
|
||||
// 4. 写过站记录(所有类型统一:INSERT一条,到达时间=NOW)
|
||||
B_DB_Opera.InsertStationRecord(engineNo, modelNo, orderNo, palletNo,
|
||||
opName, stationName, addOilQty, extractOilQty, density, Curr_UserName);
|
||||
// 5. 按类型处理称重记录
|
||||
if (weighType == "放油后")
|
||||
{
|
||||
// 空中放油后:查找最新放油前记录(无论是否完成,支持多次测量)
|
||||
if (!B_DB_Opera.QueryWeighingBeforeOil(engineNo, out _, out decimal preWeight, out _, out _, out _))
|
||||
{
|
||||
// 写报警代码=3(发动机号错误),阻断流程
|
||||
WritePLC_IF(112, opName, 3);
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】未找到发动机[{engineNo}]的空中称重记录", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] 未找到[{engineNo}]放油前记录,进站失败");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】空中放油后准备完成,发动机={engineNo},机型={modelNo},放油前重量={preWeight}kg", AID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 地面 或 空中放油前:每次都新建称重记录(支持同一产品多次测量取最新)
|
||||
string recordType = weighType == "地面" ? "地面" : "空中";
|
||||
B_DB_Opera.InsertWeighingRecord(opName, recordType, engineNo, modelNo, orderNo, palletNo,
|
||||
0, 0, addOilQty, extractOilQty, density, residualOilUpperLimit, residualOilLowerLimit, 0, 0, 0, 0,
|
||||
opName, Curr_UserName, isComplete: 0);
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】{weighType}准备完成,发动机={engineNo},机型={modelNo},残油量范围={residualOilLowerLimit:F4}-{residualOilUpperLimit:F4}L", AID);
|
||||
}
|
||||
// 6. 回写允许工作
|
||||
WritePLC_IF(66, opName, true);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
WritePLC_IF(112, opName, 1); // 报警代码=1,获取数据失败
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】请求工作处理失败:{err.Message}", AID);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 处理请求保存信号 (tagTypeCodeID=19)
|
||||
/// 流程:读取称重数据 → 更新过站记录 → 按类型处理称重记录 → 回写保存完成
|
||||
/// </summary>
|
||||
private void Weighing_HandleRequestSave(string opName, string tagID)
|
||||
{
|
||||
B_DB_Opera.SaveLog_Request(opName, Log_Type.ZK_MesHandler, "MIS_Function",
|
||||
Log_FromAndTo.ZK, Log_FromAndTo.ZK, $"触发信号【19-请求保存】", out long AID);
|
||||
try
|
||||
{
|
||||
// 1. 读取PLC数据
|
||||
decimal weight = Convert.ToDecimal(ReadPLC(100140, opName)); // 重量
|
||||
decimal waterContent = Convert.ToDecimal(ReadPLC(100180, opName)); // 水含量
|
||||
string engineNo = PLC_R.GetString_CleanGarbled(ReadPLC(10, opName)); // 产品编号
|
||||
long curveWeighingRecordId = 0;
|
||||
// 2. 更新过站记录(离开时间+称重重量)
|
||||
B_DB_Opera.UpdateStationComplete(engineNo, opName, weight);
|
||||
// 3. 确定类型并处理
|
||||
string weighType = GetWeighingType(opName);
|
||||
decimal oilReleaseQty = 0;
|
||||
decimal residualOilQty = 0;
|
||||
int finalQualityFlag = 1;
|
||||
string qualityMsg = "";
|
||||
if (weighType == "地面")
|
||||
{
|
||||
// 地面:查最新记录 → 放油量=重量/密度 → 标记完成
|
||||
B_DB_Opera.QueryLatestRecord(opName, engineNo,
|
||||
out long recordId, out _, out decimal addOil, out decimal extractOil, out decimal dens);
|
||||
curveWeighingRecordId = recordId;
|
||||
oilReleaseQty = dens > 0 ? weight / dens : 0;
|
||||
residualOilQty = addOil - extractOil - oilReleaseQty;
|
||||
B_DB_Opera.UpdateWeighingComplete(recordId, "地面", opName,
|
||||
weight, oilReleaseQty, residualOilQty, waterContent, out finalQualityFlag, out qualityMsg);
|
||||
B_DB_Opera.SaveLog_Response(
|
||||
$"【{opName}】地面保存完成:发动机={engineNo},重量={weight}kg,放油量={oilReleaseQty:F4}L,残油量={residualOilQty:F4}L,合格标志={finalQualityFlag},{qualityMsg}", AID);
|
||||
WeighingPage?.UpdateOilResult(WeighingPage?.GetStationIndex(opName) ?? 1, oilReleaseQty, residualOilQty);
|
||||
WeighingPage?.AppendLog($"[{opName}] 保存完成:{engineNo},重量={weight:F2}kg,放油量={oilReleaseQty:F4}L");
|
||||
}
|
||||
else if (weighType == "放油前")
|
||||
{
|
||||
// 空中放油前:查最新记录 → 仅写入进站重量,不标记完成
|
||||
B_DB_Opera.QueryLatestRecord(opName, engineNo,
|
||||
out long recordId, out _, out _, out _, out _);
|
||||
curveWeighingRecordId = recordId;
|
||||
B_DB_Opera.UpdateWeighingComplete(recordId, "空中放油前", opName,
|
||||
weight, 0, 0, waterContent, out finalQualityFlag, out qualityMsg);
|
||||
B_DB_Opera.SaveLog_Response(
|
||||
$"【{opName}】空中放油前保存完成:发动机={engineNo},进站重量={weight}kg,合格标志={finalQualityFlag},{qualityMsg}", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] 放油前保存:{engineNo},重量={weight:F2}kg");
|
||||
}
|
||||
else // 放油后
|
||||
{
|
||||
// 空中放油后:查最新放油前记录(无论是否完成),计算放油量更新到该记录
|
||||
if (B_DB_Opera.QueryWeighingBeforeOil(engineNo, out long recordId, out decimal preWeight,
|
||||
out decimal addOil, out decimal extractOil, out decimal dens))
|
||||
{
|
||||
curveWeighingRecordId = recordId;
|
||||
oilReleaseQty = dens > 0 ? (preWeight - weight) / dens : 0;
|
||||
residualOilQty = addOil - extractOil - oilReleaseQty;
|
||||
B_DB_Opera.UpdateWeighingComplete(recordId, "空中放油后", opName,
|
||||
weight, oilReleaseQty, residualOilQty, waterContent, out finalQualityFlag, out qualityMsg);
|
||||
B_DB_Opera.SaveLog_Response(
|
||||
$"【{opName}】空中放油后保存完成:发动机={engineNo},放油前={preWeight}kg,放油后={weight}kg,放油量={oilReleaseQty:F4}L,残油量={residualOilQty:F4}L,合格标志={finalQualityFlag},{qualityMsg}", AID);
|
||||
WeighingPage?.UpdateOilResult(WeighingPage?.GetStationIndex(opName) ?? 1, oilReleaseQty, residualOilQty);
|
||||
WeighingPage?.AppendLog($"[{opName}] 放油后保存:{engineNo},放油量={oilReleaseQty:F4}L,残油量={residualOilQty:F4}L");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 找不到放油前记录(可能直接进OP20):创建一条放油后记录并标记完成
|
||||
curveWeighingRecordId = B_DB_Opera.InsertWeighingRecord(opName, "空中放油后", engineNo, "", "", "",
|
||||
0, weight, 0, 0, 0, 0, 0, 0, 0, 2, waterContent,
|
||||
opName, Curr_UserName, isComplete: 1);
|
||||
finalQualityFlag = 2;
|
||||
qualityMsg = "未找到放油前记录";
|
||||
B_DB_Opera.SaveLog_Response(
|
||||
$"【{opName}】放油后保存(无放油前记录):发动机={engineNo},放油后重量={weight}kg", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] ⚠️ 放油后保存:{engineNo}(无放油前记录,已新建)");
|
||||
}
|
||||
}
|
||||
CurveCollector_EndSegment(opName, curveWeighingRecordId);
|
||||
// TODO: MES接口数据上传(接口对接后实现)
|
||||
if (finalQualityFlag == 2 && !string.IsNullOrWhiteSpace(qualityMsg))
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{opName}] 判定不合格:{qualityMsg}");
|
||||
}
|
||||
// 4. 先回写上位机判定的合格标志,再回写保存完成
|
||||
WritePLC_IF(21, opName, finalQualityFlag);
|
||||
WritePLC_IF(20, opName, true);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
CurveCollector_EndSegment(opName, 0);
|
||||
WritePLC_IF(112, opName, 2); // 报警代码=2,保存失败
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】保存处理失败:{err.Message}", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] ❌ 保存异常:{err.Message}");
|
||||
}
|
||||
}
|
||||
// ====================================================================
|
||||
// 扫码枪业务处理
|
||||
// ====================================================================
|
||||
/// <summary>
|
||||
/// 扫码枪扫码完成后的业务处理
|
||||
/// 将码值写入PLC地址102500,触发完成信号100016=1,1秒后复位
|
||||
/// </summary>
|
||||
/// <param name="opName">工位号(OP10/OP20),由COM口绑定决定</param>
|
||||
/// <param name="barcode">扫到的条码值</param>
|
||||
public void Barcode_HandleScan(string opName, string barcode)
|
||||
{
|
||||
B_DB_Opera.SaveLog_Request(opName, Log_Type.ZK_MesHandler, "MIS_Function",
|
||||
Log_FromAndTo.ZK, Log_FromAndTo.ZK, $"扫码枪触发【{opName}】码值={barcode}", out long AID);
|
||||
try
|
||||
{
|
||||
// 1. 写入码值到 PLC 地址 102500(PLC_PC_扫码枪值)
|
||||
WritePLC_IF(102500, opName, barcode);
|
||||
// 2. 写入扫码完成信号 100016 = 1(PC_PLC_扫码枪扫码完成)
|
||||
WritePLC_IF(100016, opName, true);
|
||||
// 3. 日志
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】扫码完成:码值={barcode}", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] 触发扫码 码值:{barcode}");
|
||||
// 4. 1秒后复位 100016 = 0
|
||||
System.Threading.Tasks.Task.Delay(1000).ContinueWith(_ =>
|
||||
{
|
||||
try { WritePLC_IF(100016, opName, false); }
|
||||
catch { }
|
||||
});
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
B_DB_Opera.SaveLog_Response($"【{opName}】扫码处理失败:{err.Message}", AID);
|
||||
WeighingPage?.AppendLog($"[{opName}] ❌ 扫码处理异常:{err.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private class CurveCollectorState
|
||||
{
|
||||
public string OpName;
|
||||
public long SegmentId;
|
||||
public Thread WorkerThread;
|
||||
public volatile bool IsRunning;
|
||||
public bool IsSegmentEnded;
|
||||
public bool IsWaitingSave;
|
||||
public int SeqNo;
|
||||
public readonly object BufferLock = new object();
|
||||
public readonly List<CurveSamplePoint> Buffer = new List<CurveSamplePoint>();
|
||||
}
|
||||
|
||||
private static readonly ConcurrentDictionary<string, CurveCollectorState> _curveCollectors
|
||||
= new ConcurrentDictionary<string, CurveCollectorState>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// 工件到位后启动实时重量曲线采集。
|
||||
/// </summary>
|
||||
private void CurveCollector_Start(string opName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_curveCollectors.TryGetValue(opName, out CurveCollectorState oldState) && !oldState.IsSegmentEnded)
|
||||
{
|
||||
if (oldState.IsRunning) return;
|
||||
CurveCollector_EndSegment(opName, 0);
|
||||
}
|
||||
|
||||
string engineNo = PLC_R.GetString_CleanGarbled(ReadPLC(10, opName));
|
||||
string modelNo = PLC_R.GetString_CleanGarbled(ReadPLC(11, opName));
|
||||
long segmentId = B_DB_Opera.Curve_StartSegment(opName, engineNo, modelNo);
|
||||
if (segmentId <= 0)
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{opName}] 曲线段创建失败,未启动采集");
|
||||
return;
|
||||
}
|
||||
|
||||
var state = new CurveCollectorState
|
||||
{
|
||||
OpName = opName,
|
||||
SegmentId = segmentId,
|
||||
IsRunning = true
|
||||
};
|
||||
state.WorkerThread = new Thread(() => CurveCollector_Work(state))
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = $"CurveCollector_{opName}"
|
||||
};
|
||||
|
||||
_curveCollectors[opName] = state;
|
||||
state.WorkerThread.Start();
|
||||
WeighingPage?.AppendLog($"[{opName}] 实时重量曲线采集启动,段ID={segmentId}");
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{opName}] 曲线采集启动异常:{err.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集线程:200ms读取一次实时重量,满10条批量写库。
|
||||
/// </summary>
|
||||
private void CurveCollector_Work(CurveCollectorState state)
|
||||
{
|
||||
while (state.IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
decimal weight = Convert.ToDecimal(ReadPLC(100220, state.OpName));
|
||||
List<CurveSamplePoint> writePoints = null;
|
||||
lock (state.BufferLock)
|
||||
{
|
||||
state.Buffer.Add(new CurveSamplePoint
|
||||
{
|
||||
SeqNo = ++state.SeqNo,
|
||||
SampleTime = DateTime.Now,
|
||||
Weight = weight
|
||||
});
|
||||
if (state.Buffer.Count >= 10)
|
||||
{
|
||||
writePoints = new List<CurveSamplePoint>(state.Buffer);
|
||||
state.Buffer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (writePoints != null)
|
||||
{
|
||||
B_DB_Opera.Curve_WritePoints(state.SegmentId, writePoints);
|
||||
}
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
WeighingPage?.AppendLog($"[{state.OpName}] 曲线采样异常:{err.Message}");
|
||||
}
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
CurveCollector_Flush(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止采样线程并刷出剩余点,但暂不关闭曲线段。
|
||||
/// </summary>
|
||||
private void CurveCollector_StopSampling(string opName, bool waitingSave = false)
|
||||
{
|
||||
if (!_curveCollectors.TryGetValue(opName, out CurveCollectorState state)) return;
|
||||
|
||||
if (waitingSave)
|
||||
{
|
||||
state.IsWaitingSave = true;
|
||||
}
|
||||
state.IsRunning = false;
|
||||
if (state.WorkerThread != null && state.WorkerThread.IsAlive)
|
||||
{
|
||||
state.WorkerThread.Join(2000);
|
||||
}
|
||||
CurveCollector_Flush(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工件离开时停止采集并关闭曲线段。
|
||||
/// </summary>
|
||||
private void CurveCollector_Stop(string opName)
|
||||
{
|
||||
if (_curveCollectors.TryGetValue(opName, out CurveCollectorState state) && state.IsWaitingSave)
|
||||
{
|
||||
return;
|
||||
}
|
||||
CurveCollector_EndSegment(opName, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存完成后关闭曲线段,并关联称重记录ID。
|
||||
/// </summary>
|
||||
private void CurveCollector_EndSegment(string opName, long weighingRecordId)
|
||||
{
|
||||
if (!_curveCollectors.TryGetValue(opName, out CurveCollectorState state)) return;
|
||||
|
||||
CurveCollector_StopSampling(opName);
|
||||
if (!state.IsSegmentEnded)
|
||||
{
|
||||
B_DB_Opera.Curve_EndSegment(state.SegmentId, weighingRecordId);
|
||||
state.IsSegmentEnded = true;
|
||||
WeighingPage?.AppendLog($"[{opName}] 实时重量曲线采集结束,段ID={state.SegmentId}");
|
||||
}
|
||||
_curveCollectors.TryRemove(opName, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将采集缓冲区剩余点写入数据库。
|
||||
/// </summary>
|
||||
private void CurveCollector_Flush(CurveCollectorState state)
|
||||
{
|
||||
List<CurveSamplePoint> writePoints = null;
|
||||
lock (state.BufferLock)
|
||||
{
|
||||
if (state.Buffer.Count > 0)
|
||||
{
|
||||
writePoints = new List<CurveSamplePoint>(state.Buffer);
|
||||
state.Buffer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (writePoints != null)
|
||||
{
|
||||
B_DB_Opera.Curve_WritePoints(state.SegmentId, writePoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user