修改统计
This commit is contained in:
@ -22,9 +22,11 @@ using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@ -36,6 +38,7 @@ using static DH.Commons.Enums.EnumHelper;
|
||||
using Camera = DHSoftware.Models.Camera;
|
||||
using LogLevel = DH.Commons.Enums.EnumHelper.LogLevel;
|
||||
using ResultState = DH.Commons.Base.ResultState;
|
||||
using Timer = System.Threading.Timer;
|
||||
|
||||
namespace DHSoftware
|
||||
{
|
||||
@ -43,6 +46,13 @@ namespace DHSoftware
|
||||
{
|
||||
private Dictionary<string, List<string>> _cameraRelatedDetectionDict = null;
|
||||
public event Action<LogMsg> OnLog;
|
||||
|
||||
public List<CameraSummary> CameraSummaries { get; set; } = new List<CameraSummary>();
|
||||
public List<ProductSummary> ProductSummaries = new List<ProductSummary>();
|
||||
static object _productSummaryLock = new object();
|
||||
public event Action<DateTime, object, string> OnUpdateResult;
|
||||
public event Action<DateTime, object, string> OnUpdateCamResult;
|
||||
|
||||
private string _loginName;
|
||||
|
||||
public string LoginName
|
||||
@ -173,8 +183,7 @@ namespace DHSoftware
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
//refreshTimer.Start();
|
||||
InitialCameraSumsView(); //refreshTimer.Start();
|
||||
//初始化数据
|
||||
InitData();
|
||||
//绑定事件
|
||||
@ -185,6 +194,317 @@ namespace DHSoftware
|
||||
//userControlFrm.Dock = DockStyle.Fill;
|
||||
//tabPage2.Controls.Add(userControlFrm);
|
||||
}
|
||||
//#region OEE
|
||||
// public event Action<RunState> OnProcessRunStateChanged;
|
||||
#region INotifyPropertyChanged
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public virtual void Set<T>(ref T field, T newValue, [CallerMemberName] string propName = null)
|
||||
{
|
||||
if (!field.Equals(newValue))
|
||||
{
|
||||
field = newValue;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
#region Properties
|
||||
private int uph = 0;
|
||||
private int upm = 0;
|
||||
|
||||
private DateTime? startTime = null;
|
||||
private TimeSpan runTime = new TimeSpan();
|
||||
private TimeSpan idleTime = new TimeSpan();
|
||||
private TimeSpan downTime = new TimeSpan();
|
||||
private TimeSpan totalTime = new TimeSpan();
|
||||
private int qty_OEE = 0;
|
||||
private int qty_OEE_OK = 0;
|
||||
private float oee = 0;
|
||||
|
||||
public int UPH
|
||||
{
|
||||
get => uph;
|
||||
set => Set(ref uph, value);
|
||||
}
|
||||
public int UPM
|
||||
{
|
||||
get => upm;
|
||||
set => Set(ref upm, value);
|
||||
}
|
||||
public DateTime? StartTime
|
||||
{
|
||||
get => startTime;
|
||||
set => Set(ref startTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 有效运行时间
|
||||
/// </summary>
|
||||
public TimeSpan RunTime
|
||||
{
|
||||
get => runTime;
|
||||
set => Set(ref runTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 空闲待机时间
|
||||
/// </summary>
|
||||
public TimeSpan IdleTime
|
||||
{
|
||||
get => idleTime;
|
||||
set => Set(ref idleTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 故障宕机时间
|
||||
/// </summary>
|
||||
public TimeSpan DownTime
|
||||
{
|
||||
get => downTime;
|
||||
set => Set(ref downTime, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 总开机时间
|
||||
/// </summary>
|
||||
public TimeSpan TotalTime
|
||||
{
|
||||
get => totalTime;
|
||||
set => Set(ref totalTime, value);
|
||||
}
|
||||
|
||||
public float OEE
|
||||
{
|
||||
get => oee;
|
||||
set => Set(ref oee, value);
|
||||
}
|
||||
#endregion
|
||||
#region Timer
|
||||
System.Threading.Timer _runTimer = null;
|
||||
System.Threading.Timer _idleTimer = null;
|
||||
System.Threading.Timer _downTimer = null;
|
||||
System.Threading.Timer _checkIdleTimer = null;
|
||||
//System.Threading.Timer _calculateTimer = null;
|
||||
|
||||
private RunState? currentState = null;
|
||||
public RunState? CurrentState
|
||||
{
|
||||
get => currentState;
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (value.Value == RunState.Running)
|
||||
{
|
||||
_checkIdleTimer?.Change(10 * 1000, -1);
|
||||
}
|
||||
|
||||
if (currentState != value.Value)
|
||||
{
|
||||
switch (currentState)
|
||||
{
|
||||
case RunState.Idle:
|
||||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Idle, false);
|
||||
break;
|
||||
case RunState.Down:
|
||||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Down, false);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (value.Value)
|
||||
{
|
||||
case RunState.Stop:
|
||||
_runTimer?.Change(-1, -1);
|
||||
_idleTimer?.Change(-1, -1);
|
||||
_downTimer?.Change(-1, -1);
|
||||
break;
|
||||
case RunState.Running:
|
||||
_idleTimer?.Change(-1, -1);
|
||||
_downTimer?.Change(-1, -1);
|
||||
_runTimer?.Change(0, 1000);
|
||||
break;
|
||||
case RunState.Idle:
|
||||
_runTimer?.Change(-1, -1);
|
||||
_downTimer?.Change(-1, -1);
|
||||
_idleTimer?.Change(0, 1000);
|
||||
|
||||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Idle, true);
|
||||
break;
|
||||
case RunState.Down:
|
||||
_idleTimer?.Change(-1, -1);
|
||||
_runTimer?.Change(-1, -1);
|
||||
_downTimer?.Change(0, 1000);
|
||||
|
||||
//AddRunEventInBuffer(DateTime.Now, RunEvent_EventType.Down, true);
|
||||
break;
|
||||
}
|
||||
|
||||
currentState = value;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckIdleTimeStart(object state)
|
||||
{
|
||||
if (CurrentState == RunState.Running)
|
||||
{
|
||||
RunTime = RunTime.Add(new TimeSpan(0, 0, 0 - 10));
|
||||
IdleTime = IdleTime.Add(new TimeSpan(0, 0, 10));
|
||||
|
||||
CurrentState = RunState.Idle;
|
||||
}
|
||||
}
|
||||
|
||||
public void InitialOEEStatistic()
|
||||
{
|
||||
InitialStatisticTimers();
|
||||
ResetOEETimeDistribute();
|
||||
ResetProductSummaries();
|
||||
}
|
||||
|
||||
public void ResetProductSummaries()
|
||||
{
|
||||
ProductSummaries = new List<ProductSummary>();
|
||||
}
|
||||
private void InitialStatisticTimers()
|
||||
{
|
||||
if (_checkIdleTimer == null)
|
||||
{
|
||||
_checkIdleTimer = new Timer(new TimerCallback(CheckIdleTimeStart), null, -1, -1);
|
||||
}
|
||||
|
||||
if (_runTimer == null)
|
||||
{
|
||||
_runTimer = new System.Threading.Timer(RunTimerCallBack, null, -1, -1);
|
||||
}
|
||||
|
||||
if (_idleTimer == null)
|
||||
{
|
||||
_idleTimer = new System.Threading.Timer(IdleTimerCallBack, null, -1, -1);
|
||||
}
|
||||
|
||||
if (_downTimer == null)
|
||||
{
|
||||
_downTimer = new System.Threading.Timer(DownTimerCallBack, null, -1, -1);
|
||||
}
|
||||
|
||||
StartTime = DateTime.Now;
|
||||
DownTime = IdleTime = RunTime = new TimeSpan(0, 0, 0);
|
||||
CurrentState = RunState.Running;
|
||||
}
|
||||
|
||||
private void DownTimerCallBack(object state)
|
||||
{
|
||||
DownTime = DownTime.Add(new TimeSpan(0, 0, 1));
|
||||
GetTotalTime();
|
||||
}
|
||||
|
||||
private void IdleTimerCallBack(object state)
|
||||
{
|
||||
IdleTime = IdleTime.Add(new TimeSpan(0, 0, 1));
|
||||
GetTotalTime();
|
||||
}
|
||||
|
||||
private void RunTimerCallBack(object state)
|
||||
{
|
||||
RunTime = RunTime.Add(new TimeSpan(0, 0, 1));
|
||||
GetTotalTime();
|
||||
}
|
||||
|
||||
private void GetTotalTime()
|
||||
{
|
||||
TotalTime = RunTime + IdleTime + DownTime;
|
||||
}
|
||||
|
||||
public void ResetOEETimeDistribute()
|
||||
{
|
||||
StartTime = DateTime.Now;
|
||||
DownTime = IdleTime = RunTime = new TimeSpan(0, 0, 0);
|
||||
|
||||
ProductNum_Total = ProductNum_OK = 0;
|
||||
}
|
||||
|
||||
public void CloseStatisticTimers()
|
||||
{
|
||||
CloseTimer(ref _checkIdleTimer);
|
||||
CloseTimer(ref _runTimer);
|
||||
CloseTimer(ref _idleTimer);
|
||||
CloseTimer(ref _downTimer);
|
||||
|
||||
CurrentState = RunState.Stop;
|
||||
}
|
||||
|
||||
private void CloseTimer(ref System.Threading.Timer timer)
|
||||
{
|
||||
timer?.Change(-1, -1);
|
||||
timer?.Dispose();
|
||||
timer = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CameraSum
|
||||
private void InitialCameraSumsView()
|
||||
{
|
||||
dgvProductNums.AutoGenerateColumns = false;
|
||||
|
||||
dgvProductNums.DefaultCellStyle.Font = new Font("Tahoma", 12, FontStyle.Regular, GraphicsUnit.World);
|
||||
|
||||
dgvProductNums.DataSource = null;
|
||||
dgvProductNums.DataSource = ProductSummaries;
|
||||
|
||||
|
||||
dgvCamreaNums.AutoGenerateColumns = false;
|
||||
|
||||
dgvCamreaNums.DefaultCellStyle.Font = new Font("Tahoma", 12, FontStyle.Regular, GraphicsUnit.World);
|
||||
|
||||
dgvCamreaNums.DataSource = null;
|
||||
dgvCamreaNums.Columns.Clear();
|
||||
|
||||
// 添加 CCD 列
|
||||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
HeaderText = "CCD",
|
||||
DataPropertyName = "CameraName"
|
||||
});
|
||||
|
||||
// 添加 合格 列
|
||||
var okColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
HeaderText = "合格",
|
||||
DataPropertyName = "OKCount"
|
||||
};
|
||||
okColumn.DefaultCellStyle.ForeColor = Color.LightGreen; // 设置背景为绿色
|
||||
dgvCamreaNums.Columns.Add(okColumn);
|
||||
|
||||
// 添加 不合格 列
|
||||
var ngColumn = new DataGridViewTextBoxColumn
|
||||
{
|
||||
HeaderText = "不合格",
|
||||
DataPropertyName = "NGCount"
|
||||
};
|
||||
ngColumn.DefaultCellStyle.ForeColor = Color.LightCoral; // 设置背景为红色
|
||||
dgvCamreaNums.Columns.Add(ngColumn);
|
||||
|
||||
// 添加 总数 列
|
||||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
HeaderText = "总数",
|
||||
DataPropertyName = "TotalCount"
|
||||
|
||||
});
|
||||
|
||||
// 添加 良率 列
|
||||
dgvCamreaNums.Columns.Add(new DataGridViewTextBoxColumn
|
||||
{
|
||||
HeaderText = "良率",
|
||||
DataPropertyName = "YieldStr"
|
||||
});
|
||||
|
||||
dgvCamreaNums.DataSource = new BindingList<CameraSummary>(CameraSummaries);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 窗体对象实例
|
||||
@ -425,6 +745,43 @@ namespace DHSoftware
|
||||
LoggerHelper.LogPrefix = "Process";
|
||||
OnLog -= LogDisplay;
|
||||
OnLog += LogDisplay;
|
||||
|
||||
OnUpdateCamResult -= UpdateCamResult;
|
||||
|
||||
OnUpdateCamResult += UpdateCamResult;
|
||||
OnUpdateResult -= UpdateResult;
|
||||
OnUpdateResult += UpdateResult;
|
||||
}
|
||||
private void UpdateCamResult(DateTime updateTime, object objData, string customMessage)
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
|
||||
BindingList<CameraSummary> cameraSummaries = new BindingList<CameraSummary>(CameraSummaries);
|
||||
dgvCamreaNums.DataSource = cameraSummaries;
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
private void UpdateResult(DateTime updateTime, object objData, string result)
|
||||
{
|
||||
this.Invoke(new Action(() =>
|
||||
{
|
||||
dgvProductNums.DataSource = null;
|
||||
dgvProductNums.DataSource = ProductSummaries;
|
||||
|
||||
if (dgvProductNums.Rows.Count > 0)
|
||||
{
|
||||
dgvProductNums.Height = dgvProductNums.Rows[0].Height * dgvProductNums.Rows.Count + 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
dgvProductNums.Height = 15;
|
||||
}
|
||||
|
||||
//lblOEE_Rate.Text = ProcessControl.OEE.ToString("f2") + " %";
|
||||
lblUPH.Text = UPH.ToString();
|
||||
}));
|
||||
}
|
||||
|
||||
private void BtnDeleteProject_Click(object? sender, EventArgs e)
|
||||
@ -647,7 +1004,7 @@ namespace DHSoftware
|
||||
private void StartProcess()
|
||||
{
|
||||
ProcessstartTime = DateTime.Now;
|
||||
lblstarttime2.Text = ProcessstartTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
lblstarttime.Text = ProcessstartTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
//计数清零
|
||||
PieceCount = 0;
|
||||
|
||||
@ -907,7 +1264,9 @@ namespace DHSoftware
|
||||
}
|
||||
}
|
||||
stopwatch.Stop();
|
||||
|
||||
if (product.ResultCollection.Count != 0)
|
||||
UpdateResultoverride(dt, camera, resultStates, totalTime, _cameraRelatedDetectionDict.Keys.Count);
|
||||
|
||||
product.InferenceOne();
|
||||
|
||||
// LogAsync(DateTime.Now, LogLevel.Information, $"{camera.Name} 推理完成,产品{productNumber}");
|
||||
@ -916,7 +1275,7 @@ namespace DHSoftware
|
||||
{
|
||||
return;
|
||||
}
|
||||
UpdateResult(DateTime.Now, null, product.ProductResult.GetEnumDescription());
|
||||
UpdateResultPro(DateTime.Now, null, product.ProductResult.GetEnumDescription());
|
||||
|
||||
|
||||
#region 6. 统计产品结果
|
||||
@ -1010,19 +1369,116 @@ namespace DHSoftware
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public async Task UpdateResult(DateTime dt, object objData, string resultStr)
|
||||
public virtual void AddOKProduct(string resultStr)
|
||||
{
|
||||
// CurrentState = RunState.Running;
|
||||
if (resultStr.ToLower() == "ok")
|
||||
{
|
||||
ProductNum_OK++;
|
||||
}
|
||||
}
|
||||
public async Task UpdateResultoverride(DateTime dt, CameraBase objData, List<ResultState> resultStr, double total, int _cameraDictCount)
|
||||
{
|
||||
// CurrentState = RunState.Running;
|
||||
|
||||
|
||||
|
||||
// 根据相机名称找到对应的信息(假设有一个字典或其他集合保存相机相关信息)
|
||||
var cameraName = objData?.CameraName; // 假设 CameraBase 有 Name 属性
|
||||
if (string.IsNullOrEmpty(cameraName))
|
||||
{
|
||||
throw new ArgumentException("相机名称不能为空");
|
||||
}
|
||||
|
||||
|
||||
|
||||
lock (_cameraSummaryLock)
|
||||
{
|
||||
// 查找或添加相机统计项
|
||||
var summary = CameraSummaries.FirstOrDefault(c => c.CameraName == cameraName)
|
||||
?? new CameraSummary { CameraName = cameraName };
|
||||
|
||||
if (!CameraSummaries.Contains(summary))
|
||||
{
|
||||
CameraSummaries.Add(summary);
|
||||
}
|
||||
|
||||
if (resultStr.Any(u => u.ToString().ToLower() == "ok"))
|
||||
{
|
||||
summary.OKCount++;
|
||||
}
|
||||
|
||||
else /*if (resultStr.Equals("TBD", StringComparison.OrdinalIgnoreCase))*/
|
||||
{
|
||||
summary.NGCount++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
OnUpdateCamResult?.Invoke(dt, objData, "");
|
||||
});
|
||||
}
|
||||
|
||||
public async Task UpdateResultPro(DateTime dt, object objData, string resultStr)
|
||||
{
|
||||
CurrentState = RunState.Running;
|
||||
|
||||
ProductNum_Total++;
|
||||
//AddOKProduct(resultStr);
|
||||
AddOKProduct(resultStr);
|
||||
|
||||
|
||||
|
||||
|
||||
lock (_productSummaryLock)
|
||||
{
|
||||
var product = ProductSummaries.FirstOrDefault(u => u.ResultDesc == resultStr);
|
||||
if (product != null)
|
||||
{
|
||||
product.ProductAmount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
product = new ProductSummary();
|
||||
product.ResultDesc = resultStr;
|
||||
product.ProductAmount = 1;
|
||||
|
||||
ProductSummaries.Add(product);
|
||||
}
|
||||
|
||||
int totalNum = ProductSummaries.Sum(p => p.ProductAmount);
|
||||
ProductSummaries.ForEach(p => p.PercentStr = ((double)p.ProductAmount * 100.0 / totalNum).ToString("f2") + " %");
|
||||
}
|
||||
|
||||
CalculateOEE();
|
||||
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
OnUpdateResult?.Invoke(dt, objData, resultStr);
|
||||
});
|
||||
lock (_cameraSummaryLock)
|
||||
{
|
||||
// 查找或添加相机统计项
|
||||
var summary = CameraSummaries.FirstOrDefault(c => c.CameraName == "合计")
|
||||
?? new CameraSummary { CameraName = "合计" };
|
||||
|
||||
summary.OKCount = ProductNum_OK;
|
||||
summary.NGCount = ProductNum_Total - ProductNum_OK;
|
||||
if (!CameraSummaries.Contains(summary))
|
||||
{
|
||||
CameraSummaries.Add(summary);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
await Task.Run(() =>
|
||||
{
|
||||
OnUpdateCamResult?.Invoke(dt, objData, "合计");
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void HandleStopButton()
|
||||
@ -1035,21 +1491,33 @@ namespace DHSoftware
|
||||
//sLDMotion.Stop();
|
||||
}
|
||||
|
||||
public int UPH = 0;
|
||||
|
||||
|
||||
public void CalculateOEE()
|
||||
{
|
||||
TimeSpan timeSpan = DateTime.Now - ProcessstartTime;
|
||||
|
||||
UPH = (int)(ProductNum_Total / timeSpan.TotalHours) + 100;
|
||||
//UPM = (int)UPH / 60;
|
||||
this.BeginInvoke(new MethodInvoker(delegate ()
|
||||
if (TotalTime.TotalHours == 0)
|
||||
{
|
||||
lblNowtime2.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
lblUPH2.Text = UPH.ToString();
|
||||
lblNum2.Text = ProductNum_Total.ToString();
|
||||
labuph.Text = UPH.ToString();
|
||||
}));
|
||||
UPH = 0;
|
||||
UPM = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
UPH = (int)(ProductNum_Total / RunTime.TotalHours) + 100;
|
||||
UPM = (int)UPH / 60;
|
||||
}
|
||||
|
||||
|
||||
//TimeSpan timeSpan = DateTime.Now - ProcessstartTime;
|
||||
|
||||
//UPH = (int)(ProductNum_Total / timeSpan.TotalHours) + 100;
|
||||
////UPM = (int)UPH / 60;
|
||||
//this.BeginInvoke(new MethodInvoker(delegate ()
|
||||
//{
|
||||
// lblNowtime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
// lblUPH.Text = UPH.ToString();
|
||||
// lblNum.Text = ProductNum_Total.ToString();
|
||||
|
||||
//}));
|
||||
}
|
||||
|
||||
private void HandleResetButton()
|
||||
|
Reference in New Issue
Block a user