552 lines
21 KiB
C#
552 lines
21 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Data;
|
||
using System.Drawing;
|
||
using System.Globalization;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using static CowainHmi.LogSearch;
|
||
using System.IO;
|
||
using System.Runtime.InteropServices;
|
||
using PCHMI;
|
||
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;
|
||
using System.Data.OleDb;
|
||
using CowainHmi.ProductionQty;
|
||
using System.Drawing.Design;
|
||
using System.Threading;
|
||
|
||
namespace CowainHmi
|
||
{
|
||
public partial class ProductionDisplay : UserControl
|
||
{
|
||
public ProductionDisplay()
|
||
{
|
||
InitializeComponent();
|
||
}
|
||
[Category("PCHMI"), Description("PLC编号")]
|
||
public int PLCId
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
// 定义并添加自定义属性
|
||
[Browsable(true)]
|
||
[Category("Custom Properties")]
|
||
[Description("产量文件路径")]
|
||
public string ProductionFolderPath
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别A开始时间")]
|
||
public string ShiftAStartAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别A结束时间")]
|
||
public string ShiftAEndAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别B开始时间")]
|
||
public string ShiftBStartAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别B结束时间")]
|
||
public string ShiftBEndAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别C开始时间")]
|
||
public string ShiftCStartAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Browsable(true)]
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("Custom Properties")]
|
||
[Description("班别C结束时间")]
|
||
public string ShiftCEndAddress
|
||
{
|
||
get;
|
||
set;
|
||
}
|
||
[Category("PCHMI"), Description("工站名称")]
|
||
public string StationName { get; set; }
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("PCHMI"), Description("上传命令地址")]
|
||
public string UpCmdAddr { get; set; }
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("PCHMI"), Description("上传命令计数地址")]
|
||
|
||
public string RetCmdAddr { get; set; }
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("PCHMI"), Description("反馈命令计数地址")]
|
||
public string RetCountAddr { get; set; }
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("PCHMI"), Description("上传工单地址")]
|
||
public string UpOrderAddr { get; set; }
|
||
[Editor(typeof(StringText), typeof(UITypeEditor))]
|
||
[Category("PCHMI"), Description("上传部件号地址")]
|
||
public string UpPartNumAddr { get; set; }
|
||
private void SetCombox()
|
||
{
|
||
string text = System.Windows.Forms.Application.StartupPath + @"\" + ProductionFolderPath;
|
||
if (!Directory.Exists(text) && text.Length > 0)
|
||
{
|
||
Directory.CreateDirectory(text);
|
||
}
|
||
string productionFile = text + @"\" + dateTimePicker1.Value.ToString("yyMMdd") + ".csv";
|
||
List<生产数据> productionData = ReadProductionData(productionFile);
|
||
//PartNum下拉框获取唯一的零部件编号
|
||
if (productionData.Count == 0)
|
||
{
|
||
partNum.DataSource = null;
|
||
return;
|
||
}
|
||
var listDown = (from item in productionData
|
||
where !string.IsNullOrWhiteSpace(item.零部件)
|
||
select item.零部件).Distinct().ToList();
|
||
listDown.Insert(0, "全部");
|
||
partNum.DataSource = listDown;
|
||
}
|
||
|
||
private void button1_Click(object sender, EventArgs e)
|
||
{
|
||
|
||
CalcProductionQty();
|
||
}
|
||
private void CalcProductionQty()
|
||
{
|
||
string text = System.Windows.Forms.Application.StartupPath + @"\" + ProductionFolderPath;
|
||
if (!Directory.Exists(text) && text.Length > 0)
|
||
{
|
||
Directory.CreateDirectory(text);
|
||
}
|
||
string productionFile = text + @"\" + dateTimePicker1.Value.ToString("yyMMdd") + ".csv";
|
||
List<生产数据> productionData = ReadProductionData(productionFile);
|
||
List<Hours> hoursList = new List<Hours>();
|
||
|
||
for (int i = 0; i < shiftTime.Count; i++)
|
||
{
|
||
var item = shiftTime[i];
|
||
DateTime shiftStartTime = item.开始时间;
|
||
|
||
while (shiftStartTime < item.结束时间)
|
||
{
|
||
DateTime nextShiftStartTime = item.结束时间;
|
||
|
||
// Check if there is a next shift
|
||
if (i + 1 < shiftTime.Count)
|
||
{
|
||
nextShiftStartTime = shiftTime[i + 1].开始时间;
|
||
}
|
||
|
||
DateTime endTime = shiftStartTime.AddHours(1);
|
||
|
||
// Adjust the end time if it overlaps with the next shift
|
||
if (endTime > nextShiftStartTime)
|
||
{
|
||
endTime = nextShiftStartTime;
|
||
}
|
||
|
||
Hours hours1 = new Hours()
|
||
{
|
||
开始时间 = shiftStartTime,
|
||
结束时间 = endTime,
|
||
班别 = item.班别,
|
||
};
|
||
hoursList.Add(hours1);
|
||
|
||
shiftStartTime = endTime;
|
||
}
|
||
}
|
||
|
||
List<单班产量> shift = new List<单班产量>();
|
||
string partFilter = partNum.Text == "全部" ? "" : partNum.Text;
|
||
foreach (var item in hoursList)
|
||
{
|
||
var info = productionData
|
||
.Where(pd => pd.时间 >= item.开始时间 && pd.时间 < item.结束时间
|
||
&& (partFilter == "" || pd.零部件 == partFilter));
|
||
单班产量 production = new 单班产量()
|
||
{
|
||
时间 = item.开始时间,
|
||
工单 = info.Any() ? info.FirstOrDefault().工单 : "",
|
||
零部件 = info.Any() ? info.FirstOrDefault().零部件 : "",
|
||
班别 = item.班别,
|
||
产量 = info.Any() ? info.Where(pd => pd.时间 >= item.开始时间 && pd.时间 < item.结束时间).Count() : 0,
|
||
合格 = info.Any() ? info.Where(pd => pd.时间 >= item.开始时间 && pd.时间 < item.结束时间 && pd.合格否 == 1).Count() : 0,
|
||
不合格 = info.Any() ? info.Where(pd => pd.时间 >= item.开始时间 && pd.时间 < item.结束时间 && pd.合格否 == 2).Count() : 0,
|
||
};
|
||
shift.Add(production);
|
||
};
|
||
|
||
dataGridView1.DataSource = shift;
|
||
|
||
//统计按班别的总产量,总合格,总不合格
|
||
var shiftSum = (from item in shift
|
||
group item by item.班别 into g
|
||
select new 单班产量
|
||
{
|
||
班别 = g.Key,
|
||
产量 = g.Sum(x => x.产量),
|
||
合格 = g.Sum(x => x.合格),//合格=1,则直接对1求和
|
||
不合格 = g.Sum(x => x.不合格)//不合格=2,则对2-1求和
|
||
}).ToList();
|
||
var shiftASum = shiftSum.FirstOrDefault(x => x.班别 == "A");
|
||
var shiftBSum = shiftSum.FirstOrDefault(x => x.班别 == "B");
|
||
var shiftCSum = shiftSum.FirstOrDefault(x => x.班别 == "C");
|
||
totalA.Text = shiftASum.产量.ToString();
|
||
totalB.Text = shiftBSum.产量.ToString();
|
||
totalC.Text = shiftCSum.产量.ToString();
|
||
OK_A.Text = shiftASum.合格.ToString();
|
||
OK_B.Text = shiftBSum.合格.ToString();
|
||
OK_C.Text = shiftCSum.合格.ToString();
|
||
NG_A.Text = shiftASum.不合格.ToString();
|
||
NG_B.Text = shiftBSum.不合格.ToString();
|
||
NG_C.Text = shiftCSum.不合格.ToString();
|
||
}
|
||
public bool IsWithinShiftTime(int hour, double startTime, double endTime)
|
||
{
|
||
if (startTime < endTime)
|
||
{
|
||
// 普通时间段
|
||
return hour >= startTime && hour < endTime;
|
||
}
|
||
else
|
||
{
|
||
// 跨越午夜的时间段
|
||
return hour >= startTime || hour < endTime;
|
||
}
|
||
}
|
||
private List<生产数据> ReadProductionData(string filePath)
|
||
{
|
||
var productionData = new List<生产数据>();
|
||
|
||
if (!File.Exists(filePath))
|
||
{
|
||
return productionData;
|
||
}
|
||
|
||
int N = 1;
|
||
foreach (var line in File.ReadAllLines(filePath, Encoding.GetEncoding("GB2312")))
|
||
{
|
||
try
|
||
{
|
||
if (N == 1)
|
||
{
|
||
N++;
|
||
continue;
|
||
}
|
||
var parts = line.Split(',');
|
||
var time = DateTime.ParseExact(parts[0].Trim(), "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||
|
||
productionData.Add(new 生产数据
|
||
{
|
||
时间 = time,
|
||
工单 = parts[1],
|
||
零部件 = parts[2],
|
||
合格否 = int.Parse(parts[3])
|
||
}
|
||
);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
|
||
//throw;
|
||
}
|
||
N++;
|
||
}
|
||
|
||
return productionData;
|
||
}
|
||
public class 班别时间
|
||
{
|
||
public string 班别 { get; set; }
|
||
public DateTime 开始时间 { get; set; }
|
||
public DateTime 结束时间 { get; set; }
|
||
}
|
||
public class Hours
|
||
{
|
||
public string 班别 { get; set; }
|
||
public DateTime 开始时间 { get; set; }
|
||
public DateTime 结束时间 { get; set; }
|
||
}
|
||
public class 单班产量
|
||
{
|
||
public DateTime 时间 { get; set; }
|
||
public string 工单 { get; set; }
|
||
public string 零部件 { get; set; }
|
||
public string 班别 { get; set; }
|
||
public int 产量 { get; set; }
|
||
public int 合格 { get; set; }
|
||
public int 不合格 { get; set; }
|
||
public int SortOrder { get; set; } // 新增排序字段
|
||
}
|
||
|
||
public class 生产数据
|
||
{
|
||
public DateTime 时间 { get; set; }
|
||
public string 工单 { get; set; }
|
||
public string 零部件 { get; set; }
|
||
public int 合格否 { get; set; }
|
||
}
|
||
static string ConvertTimeToFormattedString(string timeString)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(timeString) || timeString.Length != 4)
|
||
{
|
||
throw new ArgumentException("Invalid time format. Please use 'HHmm' format.");
|
||
}
|
||
|
||
// 提取小时和分钟
|
||
int hour = int.Parse(timeString.Substring(0, 2));
|
||
int minute = int.Parse(timeString.Substring(2, 2));
|
||
|
||
// 创建TimeSpan对象
|
||
TimeSpan timeSpan = new TimeSpan(hour, minute, 0);
|
||
|
||
// 将TimeSpan转换为字符串
|
||
return timeSpan.ToString("hh\\:mm\\:ss");
|
||
}
|
||
public class CalcStartEndTime
|
||
{
|
||
public DateTime StartTime { get; set; }
|
||
public DateTime EndTime { get; set; }
|
||
}
|
||
private CalcStartEndTime GetDateTime(string startTimeChar, string endTimeChar, DateTime queryDateTime)
|
||
{
|
||
CalcStartEndTime calcStartEndTime = new CalcStartEndTime();
|
||
int startTime = int.Parse(startTimeChar.Substring(0, 2));
|
||
int endTime = int.Parse(endTimeChar.Substring(0, 2));
|
||
|
||
DateTime startDateTime;
|
||
DateTime endDateTime;
|
||
|
||
// Determine the start and end dates
|
||
if (startTime > endTime)
|
||
{
|
||
startDateTime = queryDateTime;
|
||
endDateTime = queryDateTime.AddDays(1);
|
||
}
|
||
else
|
||
{
|
||
if (startTime < 9 && endTime < 9)
|
||
{
|
||
startDateTime = queryDateTime.AddDays(1);
|
||
endDateTime = queryDateTime.AddDays(1);
|
||
}
|
||
else
|
||
{
|
||
startDateTime = queryDateTime;
|
||
endDateTime = queryDateTime;
|
||
}
|
||
}
|
||
|
||
// Parse the exact times
|
||
calcStartEndTime.StartTime = DateTime.ParseExact(startDateTime.ToString("yyyy-MM-dd ") + ConvertTimeToFormattedString(startTimeChar), "yyyy-MM-dd HH:mm:ss", null);
|
||
calcStartEndTime.EndTime = DateTime.ParseExact(endDateTime.ToString("yyyy-MM-dd ") + ConvertTimeToFormattedString(endTimeChar), "yyyy-MM-dd HH:mm:ss", null);
|
||
|
||
return calcStartEndTime;
|
||
}
|
||
private void SetShiftTime()
|
||
{
|
||
ReadShiftTime();
|
||
var shiftATime = GetDateTime(shiftTimePLC[0], shiftTimePLC[1], dateTimePicker1.Value);
|
||
var shiftBTime = GetDateTime(shiftTimePLC[2], shiftTimePLC[3], dateTimePicker1.Value);
|
||
var shiftCTime = GetDateTime(shiftTimePLC[4], shiftTimePLC[5], dateTimePicker1.Value);
|
||
shiftTime = new List<班别时间>()
|
||
{
|
||
new 班别时间 { 班别="A",开始时间 = shiftATime.StartTime, 结束时间 = shiftATime.EndTime },
|
||
new 班别时间 { 班别="B",开始时间 = shiftBTime.StartTime, 结束时间 = shiftBTime.EndTime },
|
||
new 班别时间 { 班别="C",开始时间 = shiftCTime.StartTime, 结束时间 = shiftCTime.EndTime }
|
||
};
|
||
}
|
||
|
||
private List<string> shiftTimePLC = new List<string>();
|
||
private void ReadShiftTime()
|
||
{
|
||
if (!PClass.SystemRun)
|
||
{
|
||
return;
|
||
}
|
||
shiftTimePLC.Clear();
|
||
List<string> shiftTimeDuration = new List<string>()
|
||
{
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftAStartAddress,4),
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftAEndAddress,4),
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftBStartAddress, 4),
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftBEndAddress, 4),
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftCStartAddress, 4),
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftCEndAddress, 4),
|
||
};
|
||
foreach (var item in shiftTimeDuration)
|
||
{
|
||
if (!string.IsNullOrEmpty(item))
|
||
{
|
||
shiftTimePLC.Add(item);
|
||
}
|
||
}
|
||
if (shiftTimePLC.Count != 6)
|
||
{
|
||
shiftTimePLC.Clear();
|
||
shiftTimePLC.Add("0830");
|
||
shiftTimePLC.Add("1630");
|
||
shiftTimePLC.Add("1700");
|
||
shiftTimePLC.Add("0130");
|
||
shiftTimePLC.Add("0130");
|
||
shiftTimePLC.Add("0830");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据当前时间,获取存储的文件名
|
||
/// </summary>
|
||
private string GetFileName()
|
||
{
|
||
var dateTime = DateTime.Now;
|
||
var shiftATime = GetDateTime(shiftTimePLC[0], shiftTimePLC[1], dateTime.AddDays(-1));
|
||
var shiftBTime = GetDateTime(shiftTimePLC[2], shiftTimePLC[3], dateTime.AddDays(-1));
|
||
var shiftCTime = GetDateTime(shiftTimePLC[4], shiftTimePLC[5], dateTime.AddDays(-1));
|
||
List<班别时间> shiftTimeLastDay = new List<班别时间>()
|
||
{
|
||
new 班别时间 { 班别="A",开始时间 = shiftATime.StartTime, 结束时间 = shiftATime.EndTime },
|
||
new 班别时间 { 班别="B",开始时间 = shiftBTime.StartTime, 结束时间 = shiftBTime.EndTime },
|
||
new 班别时间 { 班别="C",开始时间 = shiftCTime.StartTime, 结束时间 = shiftCTime.EndTime }
|
||
};
|
||
var shiftDuration = shiftTimeLastDay.Where(item => item.开始时间 <= dateTime && dateTime < item.结束时间);
|
||
if (shiftDuration.Any())
|
||
{
|
||
return shiftTimeLastDay[0].开始时间.ToString("yyMMdd");
|
||
}
|
||
return dateTime.ToString("yyMMdd");
|
||
}
|
||
private List<班别时间> shiftTime;
|
||
private async void ProductionDisplay_Load(object sender, EventArgs e)
|
||
{
|
||
if (!PClass.SystemRun)
|
||
{
|
||
return;
|
||
}
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftAStartAddress, 4);
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftAEndAddress, 4);
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftBStartAddress, 4);
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftBEndAddress, 4);
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftCStartAddress, 4);
|
||
PCHMI.VL.GET_SIEMENS_STRING(PLCId, ShiftCEndAddress, 4);
|
||
PCHMI.RT.GET_INT16s(PLCId, UpCmdAddr, 6);
|
||
PCHMI.RT.GET_SIEMENS_STRING(PLCId, UpOrderAddr, 30);
|
||
PCHMI.RT.GET_SIEMENS_STRING(PLCId, UpPartNumAddr, 50);
|
||
await Task.Delay(300);
|
||
SetShiftTime();
|
||
dataGridView1.AutoGenerateColumns = false;
|
||
SetCombox();
|
||
ReadShiftTime();
|
||
this.timer1.Enabled = true;
|
||
}
|
||
|
||
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
|
||
{
|
||
SetShiftTime();
|
||
}
|
||
private short retCountSave;
|
||
private void timer1_Tick(object sender, EventArgs e)
|
||
{
|
||
if (PClass.IsPlcLink(PLCId) && !string.IsNullOrEmpty(UpCmdAddr))
|
||
{
|
||
var ar = PCHMI.RT.GET_INT16s(PLCId, UpCmdAddr, 6);
|
||
var order = PCHMI.RT.GET_SIEMENS_STRING(PLCId, UpOrderAddr, 30);
|
||
var partNum = PCHMI.RT.GET_SIEMENS_STRING(PLCId, UpPartNumAddr, 50);
|
||
if (ar[0] == 1 && retCountSave != ar[1])
|
||
{
|
||
//PLC触发产量上传
|
||
string fileName = GetFileName();
|
||
string stName = string.Empty;
|
||
if (string.IsNullOrEmpty(StationName))
|
||
{
|
||
stName = this.Name;
|
||
}
|
||
else
|
||
{
|
||
stName = StationName;
|
||
}
|
||
SaveData(stName, fileName, order, partNum, ar[5]);
|
||
PCHMI.RT.SEND_INT16(PLCId, RetCmdAddr, 1);
|
||
PCHMI.RT.SEND_INT16(PLCId, RetCountAddr, ar[1]);
|
||
retCountSave = ar[1];
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public void SaveData(string stationName, string fileName, string order, string partNum, short isPass)
|
||
{
|
||
if (PClass.SystemRun)
|
||
{
|
||
string text = System.Windows.Forms.Application.StartupPath + @"\" + ProductionFolderPath;
|
||
if (!Directory.Exists(text) && text.Length > 0)
|
||
{
|
||
Directory.CreateDirectory(text);
|
||
}
|
||
string productionFile = text + @"\" + fileName + ".csv";
|
||
if (!File.Exists(productionFile))
|
||
{
|
||
CsvHelper.CreateCsv(productionFile, new string[]
|
||
{
|
||
"时间",
|
||
"工单",
|
||
"零部件",
|
||
"合格否"
|
||
});
|
||
}
|
||
CsvHelper.WriteLine(productionFile, new List<string>() { DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), order, partNum, isPass.ToString() });
|
||
}
|
||
|
||
}
|
||
|
||
private void btnTimeEdit_Click(object sender, EventArgs e)
|
||
{
|
||
List<string> strings = new List<string>() { ShiftAStartAddress, ShiftAEndAddress, ShiftBStartAddress, ShiftBEndAddress, ShiftCStartAddress, ShiftCEndAddress };
|
||
DlgProductionTimeEdit dlg = new DlgProductionTimeEdit(PLCId, strings);
|
||
var result = dlg.ShowDialog();
|
||
if (result == DialogResult.OK)
|
||
{
|
||
SetShiftTime();
|
||
ReadShiftTime();
|
||
}
|
||
}
|
||
|
||
private void partNum_MouseDown(object sender, MouseEventArgs e)
|
||
{
|
||
SetCombox();
|
||
}
|
||
}
|
||
}
|