Files
52-NingdePDC-MesProject/MisDataFunction/Function1062/DataAccess/DataAccess.cs
2026-05-31 10:22:04 +08:00

361 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using DataLinkMesWork1;
using MesServerWork;
using MisDataFunDll;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
namespace MesServerFunctions
{
partial class FunctionMES
{
private const string ManualStaticOutOpName = "OP431";
private const string ManualStaticPadTopic = "OP431PAD";
private const decimal DefaultManualStaticMinutes = 30m;
private const string ManualStaticLocation = "777777";
private const string ManualStaticOperator = "PAD";
private static readonly object ManualStaticMinutesLocker = new object();
private static readonly Dictionary<string, decimal> ManualStaticMinutesByEngine = new Dictionary<string, decimal>();
private class ManualStaticOutProduct
{
public string EngineID { get; set; }
public string OrderForm { get; set; }
public string EngineType { get; set; }
public int EngineTypeID { get; set; }
}
private class ManualStaticOutData
{
public string SourceOpName { get; set; }
public DateTime StartTime { get; set; }
public DateTime FinishTime { get; set; }
public decimal Minutes { get; set; }
public int QualityMask { get; set; }
}
private bool TryGetManualStaticOutProduct(string engineID, out ManualStaticOutProduct product, out string message)
{
product = null;
message = "";
if (string.IsNullOrWhiteSpace(engineID))
{
message = "产品码为空";
return false;
}
MisDataFun.Moby_Select_PDC(engineID, out string orderForm, out string engineType, out int engineTypeID);
if (engineTypeID <= 0 || string.IsNullOrWhiteSpace(engineType))
{
message = "未查询到产品执行信息:" + engineID;
return false;
}
product = new ManualStaticOutProduct
{
EngineID = engineID.Trim(),
OrderForm = orderForm,
EngineType = engineType,
EngineTypeID = engineTypeID
};
return true;
}
private bool TryGetManualStaticStartTime(string engineID, out string sourceOpName, out DateTime startTime, out string message)
{
sourceOpName = "";
startTime = DateTime.MinValue;
message = "";
try
{
// 取 OP400/OP410/OP420 最后一条有效离开记录作为常温静置开始时间。
string procedureName = "OP431手动静置出库_前序离开时间_查询";
SqlParameter[] sqlParameters = new SqlParameter[1];
sqlParameters[0] = new SqlParameter("@发动机号", engineID);
DataAccess.ExecuteStoredProcedure(procedureName, ref sqlParameters, out DataTable dt, out string errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
message = "查询前序出站时间失败:" + errorMessage;
return false;
}
if (dt == null || dt.Rows.Count == 0)
{
message = "未查询到 OP400/OP410/OP420 前序出站记录";
return false;
}
sourceOpName = Convert.ToString(dt.Rows[0]["工位号"]);
startTime = Convert.ToDateTime(dt.Rows[0]["开始静置时间"]);
return true;
}
catch (Exception err)
{
message = "查询前序出站时间失败:" + err.Message;
return false;
}
}
private bool TryBuildManualStaticOutData(string engineID, int qualityMask, out ManualStaticOutData staticOutData, out string message)
{
staticOutData = null;
message = "";
if (!TryGetManualStaticStartTime(engineID, out string sourceOpName, out DateTime startTime, out message))
{
return false;
}
DateTime finishTime = DateTime.Now;
decimal minutes = Math.Round(Convert.ToDecimal((finishTime - startTime).TotalMinutes), 2);
staticOutData = new ManualStaticOutData
{
SourceOpName = sourceOpName,
StartTime = startTime,
FinishTime = finishTime,
Minutes = minutes,
QualityMask = NormalizeManualStaticQualityMask(qualityMask)
};
return true;
}
private int NormalizeManualStaticQualityMask(int qualityMask)
{
return qualityMask == 1 ? 1 : 2;
}
private bool IsManualStaticTimeEnough(ManualStaticOutData staticOutData, decimal minStaticMinutes, out string message)
{
message = "";
if (staticOutData.Minutes < minStaticMinutes)
{
message = "静置时间不足 " + minStaticMinutes.ToString("0.##") + " 分钟,当前已静置 " + staticOutData.Minutes + " 分钟";
return false;
}
return true;
}
private bool WriteManualStaticOutQualityData(string opName, string engineID, ManualStaticOutData data, out string message)
{
message = "";
int idTagCf = 0;
if (!TryGetManualStaticMinutesForProduct(engineID, out decimal rememberedMinStaticMinutes))
{
message = "未找到PAD确认的最小静置标准请在PAD重新确认上线后再保存" + engineID;
return false;
}
string minStaticMinutes = rememberedMinStaticMinutes.ToString("0.##");
// OP431 的静置数据由 Function 直接落库,不再通过 OnlineCheckData 做 HTTP 自调用。
SqlParameter[] indexParams = new SqlParameter[6];
indexParams[0] = new SqlParameter("@EngineID", engineID);
indexParams[1] = new SqlParameter("@工位号", opName);
indexParams[2] = new SqlParameter("@操作者工号", ManualStaticOperator);
indexParams[3] = new SqlParameter("@扫码时间", data.FinishTime);
indexParams[4] = new SqlParameter("@合格标志", data.QualityMask);
indexParams[5] = new SqlParameter("@Id_tagCF", idTagCf);
indexParams[5].Direction = ParameterDirection.Output;
DataAccess.ExecuteStoredProcedure("测量数据合格索引_增加_测试设备", ref indexParams, out string errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
message = "写入静置质量索引失败:" + errorMessage;
return false;
}
idTagCf = Convert.ToInt32(indexParams[5].Value.ToString());
if (idTagCf <= 0)
{
message = "写入静置质量索引失败:未生成 Id_tagCF";
return false;
}
object[,] detailRows = new object[,]
{
{ "OP431_M0001_001", "开始静置时间", "min", "1", "60", minStaticMinutes, data.StartTime.ToString("yyyy-MM-dd HH:mm:ss"), data.QualityMask },
{ "OP431_M0001_002", "静置完成时间", "min", "1", "60", minStaticMinutes, data.FinishTime.ToString("yyyy-MM-dd HH:mm:ss"), data.QualityMask },
{ "OP431_M0001_003", "静置时间差", "min", "1", "60", minStaticMinutes, data.Minutes.ToString("0.##"), data.QualityMask },
{ "OP431_M0001_004", "静置库位号", "静置库位", "-1", "-1", "-1", ManualStaticLocation, data.QualityMask }
};
for (int i = 0; i < detailRows.GetLength(0); i++)
{
SqlParameter[] detailParams = new SqlParameter[]
{
new SqlParameter("@Id_tagCF", idTagCf),
new SqlParameter("@EngineID", engineID),
new SqlParameter("@TagID", detailRows[i, 0]),
new SqlParameter("@TagValue", detailRows[i, 6]),
new SqlParameter("@IsGoodBad", detailRows[i, 7]),
new SqlParameter("@工位号", opName),
new SqlParameter("@理论值", detailRows[i, 3]),
new SqlParameter("@上限值", detailRows[i, 4]),
new SqlParameter("@下限值", detailRows[i, 5]),
new SqlParameter("@测量项目", detailRows[i, 1]),
new SqlParameter("@测量单位", detailRows[i, 2])
};
DataAccess.ExecuteStoredProcedure("测量数据合格_增加_测试设备", ref detailParams, out errorMessage);
if (!string.IsNullOrWhiteSpace(errorMessage))
{
message = "写入静置质量明细失败:" + errorMessage;
return false;
}
}
return true;
}
private bool CheckManualStaticPadPrecondition(string opName, out string message)
{
message = "";
MIS_BASE.Read_WorkStart(opName, out bool workStart);
if (!workStart)
{
message = "当前无托盘到位信号,不允许扫码确认";
return false;
}
MIS_BASE.Read_PartLoad(opName, out bool partLoad);
if (!partLoad)
{
message = "PLC尚未申请上线不允许扫码确认";
return false;
}
return true;
}
private bool ConfirmManualStaticOutProduct(string opName, string engineID, decimal minStaticMinutes, out string message)
{
message = "";
// PAD 确认上线时必须重新校验托盘和 PLC 申请状态,不能复用查询时的旧结果。
if (!CheckManualStaticPadPrecondition(opName, out message))
{
return false;
}
if (!TryGetManualStaticOutProduct(engineID, out ManualStaticOutProduct product, out message))
{
return false;
}
if (!TryBuildManualStaticOutData(product.EngineID, 1, out ManualStaticOutData staticOutData, out message))
{
return false;
}
// 二次校验静置时间,最小分钟数来自 PAD 当前配置,默认 30 分钟。
if (!IsManualStaticTimeEnough(staticOutData, minStaticMinutes, out message))
{
return false;
}
MIS_BASE.Read_PalletCode(opName, out int palletCode);
MisDataFun.OpName_MIS_MOBY_Insert(opName, product.EngineTypeID, product.EngineType, product.EngineID, palletCode, product.OrderForm, 0, 0, "");
// 写入 MES->PLC 产品区PLC 收到 EngineTypeGetOver_MES 后再回传 44 做进站校验。
MIS_BASE.Write_EngineTypeID_MES(opName, product.EngineTypeID);
MIS_BASE.Write_EngineID_MES(opName, product.EngineID);
MIS_BASE.Write_EngineType_MES(opName, product.EngineType);
MIS_BASE.Write_OrderForm_MES(opName, product.OrderForm);
MIS_BASE.Write_EngineTypeGetOver_MES(opName, true);
RememberManualStaticMinutesForProduct(product.EngineID, minStaticMinutes);
message = "PAD确认上线成功" + product.EngineID;
return true;
}
private bool QueryManualStaticOutProduct(string opName, string engineID, decimal minStaticMinutes, out string resultMessage)
{
resultMessage = "";
// 扫码查询只返回产品与静置信息,不写 PLC、不调用进站也不依赖托盘到位/PLC申请上线实时消息。
// PAD 页面可能不是一直打开,托盘到位等实时 MQTT 可能丢失,最终状态由确认上线时后端再次校验。
if (!TryGetManualStaticOutProduct(engineID, out ManualStaticOutProduct product, out resultMessage))
{
return false;
}
if (!TryBuildManualStaticOutData(product.EngineID, 1, out ManualStaticOutData staticOutData, out resultMessage))
{
return false;
}
bool timeEnough = IsManualStaticTimeEnough(staticOutData, minStaticMinutes, out string timeMessage);
MIS_BASE.Read_PartLoad(opName, out bool partLoad);
bool canConfirm = timeEnough && partLoad;
string confirmMessage = canConfirm
? "允许确认上线"
: !timeEnough
? timeMessage
: "PLC尚未申请上线不允许确认上线";
resultMessage = string.Join("^", new string[]
{
product.EngineID,
product.OrderForm,
product.EngineType,
product.EngineTypeID.ToString(),
staticOutData.SourceOpName,
staticOutData.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
staticOutData.Minutes.ToString("0.##"),
minStaticMinutes.ToString("0.##"),
partLoad ? "1" : "0",
canConfirm ? "1" : "0",
confirmMessage
});
return true;
}
private void SendManualStaticOutResult(string opName, string command, bool success, string message)
{
string value = (success ? "1" : "0") + "^" + message;
SendManualStaticPadMqttMessage(command, opName, value);
// 同步给工位主题保留现有页面状态监听能力PAD 以 OP431PAD 主题为准。
SendMessageFun.SendInfomation(command, value, opName);
if (!success)
{
SendMessage.AsyncSendMessage_Notice(opName, "【" + opName + "】" + message);
}
}
private void SendManualStaticPadMqttMessage(string command, string opName, string value)
{
SendMessage.AsyncSendNotOpMessage(ManualStaticPadTopic, "MES|" + command + "|" + opName + "|" + value);
}
private void RememberManualStaticMinutesForProduct(string engineID, decimal minStaticMinutes)
{
lock (ManualStaticMinutesLocker)
{
ManualStaticMinutesByEngine[engineID] = minStaticMinutes;
}
}
private bool TryGetManualStaticMinutesForProduct(string engineID, out decimal minStaticMinutes)
{
lock (ManualStaticMinutesLocker)
{
if (ManualStaticMinutesByEngine.ContainsKey(engineID))
{
minStaticMinutes = ManualStaticMinutesByEngine[engineID];
return true;
}
}
minStaticMinutes = DefaultManualStaticMinutes;
return false;
}
}
}