初始化版本

This commit is contained in:
LL
2025-11-14 16:12:32 +08:00
commit ea40f18aa6
326 changed files with 137063 additions and 0 deletions

357
SLC1-N/Chart.cs Normal file
View File

@@ -0,0 +1,357 @@
using Sunny.UI.Win32;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Excel = Microsoft.Office.Interop.Excel;
using System.Windows.Forms.DataVisualization;
using System.Windows.Forms.DataVisualization.Charting;
using System.Drawing.Imaging;
using System.Drawing;
using DocumentFormat.OpenXml.EMMA;
namespace SLC1_N
{
class Chart
{
// 生成泄漏量趋势图
public static void Create_TrendChart(int CH, string filepath, int maxProducts = 10)
{
try
{
string datatime = DateTime.Now.ToString("yyyyMMdd");
//string filepath = GetExcelFilePath(CH, datatime);
if (!File.Exists(filepath))
{
mxlLog.Instance.Error($"Excel文件不存在无法生成图表");
return;
}
// 读取Excel数据
var Exceldata = ReadExcelData(filepath, maxProducts);
if (Exceldata.Rows.Count == 0)
{
mxlLog.Instance.Error($"没有足够的数据生成趋势图");
return;
}
// 提取泄漏量数据
List<double> leakValues_list = new List<double>();
List<string> productLabels = new List<string>();
List<string> code_list = new List<string>();
List<string> results_list = new List<string>();
for (int i = 0; i < Exceldata.Rows.Count; i++)
{
string leakStr = Exceldata.Rows[i]["微漏泄漏量"].ToString();
Console.WriteLine($"Chart:{i}: {leakStr}");
// 移除单位,只保留数值
leakStr = leakStr.Replace("KPa", "")
.Replace("Pa/s", "")
.Replace("mbar/s", "")
.Replace("Pa", "")
.Replace("s", "").Trim();
Console.WriteLine($"Chart2:{i}: {leakStr}");
if (double.TryParse(leakStr, out double leakage))
{
leakValues_list.Add(leakage);
productLabels.Add($"产品{i + 1}");
code_list.Add(Exceldata.Rows[i]["条形码"].ToString());
results_list.Add(Exceldata.Rows[i]["测试结果"].ToString());
}
}
if (leakValues_list.Count == 0)
{
mxlLog.Instance.Error($"没有有效的泄漏量数据");
return;
}
// 创建图表图像
int width = 1000;
int height = 600;
using (Bitmap bitmap = new Bitmap(width, height))
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // 抗锯齿
// 设置边距
int margin = 50;
int chartWidth = width - 2 * margin;
int chartHeight = height - 2 * margin;
// 计算Y轴数据范围最大值加10%最小值减10%但不小于0
double maxValue = leakValues_list.Max() * 1.1;
double minValue = Math.Max(0, leakValues_list.Min() * 0.9);
// 绘制标题
using (Font titleFont = new Font("Arial", 16, FontStyle.Bold))
using (Brush titleBrush = new SolidBrush(Color.Black))
{
graphics.DrawString($"通道{CH} - 最近{maxProducts}个产品泄漏量趋势",
titleFont, titleBrush,
new PointF(width / 2 - 150, 10)); // 居中
}
// 绘制坐标轴Y轴坐标是向下的原点50550
using (Pen axisPen = new Pen(Color.Black, 2))
{
// X轴
graphics.DrawLine(axisPen, margin, height - margin, width - margin, height - margin);
// Y轴
graphics.DrawLine(axisPen, margin, margin, margin, height - margin);
}
// 绘制Y轴刻度
using (Font scaleFont = new Font("Arial", 8))
using (Brush scaleBrush = new SolidBrush(Color.Black))
{
for (int i = 0; i <= 5; i++) // 在 Y 轴上绘制 5 个等分刻度。
{
double value = minValue + (maxValue - minValue) * i / 5;
int y = height - margin - (int)(chartHeight * i / 5);
graphics.DrawString(value.ToString("F2"), scaleFont, scaleBrush,
margin - 45, y - 10); // 刻度标签坐标
}
}
// 绘制数据点
using (Pen dataPen = new Pen(Color.Blue, 2)) // 连线
using (Brush pointBrush = new SolidBrush(Color.Red)) // 坐标点
using (Font labelFont = new Font("Arial", 8))
using (Brush labelBrush = new SolidBrush(Color.DarkBlue)) // 数据点数值标签
{
for (int i = 0; i < leakValues_list.Count; i++)
{
double leakvalue = leakValues_list[i];
int x = margin + (int)(chartWidth * i / (leakValues_list.Count - 1));
int y = height - margin - (int)(chartHeight * (leakvalue - minValue) / (maxValue - minValue));
// 绘制数据点连接线
if (i > 0)
{
double prevValue = leakValues_list[i - 1]; // 前一个数据值
int prevX = margin + (int)(chartWidth * (i - 1) / (leakValues_list.Count - 1));
int prevY = height - margin - (int)(chartHeight * (prevValue - minValue) / (maxValue - minValue));
graphics.DrawLine(dataPen, prevX, prevY, x, y); // 连接前一个点和当前点
}
// 绘制数据点
graphics.FillEllipse(pointBrush, x - 4, y - 4, 8, 8);
// 绘制数值标签
string label = leakvalue.ToString("F2");
graphics.DrawString(label, labelFont, labelBrush, x - 15, y - 20);
// 绘制X轴标签
graphics.DrawString(productLabels[i], labelFont, labelBrush,
x - 10, height - margin + 10);
}
}
// 绘制图例
using (Font legendFont = new Font("Arial", 10))
using (Brush legendBrush = new SolidBrush(Color.Black))
{
graphics.DrawString("泄漏量趋势", legendFont, legendBrush, width - 150, margin);
graphics.DrawLine(new Pen(Color.Blue, 2), width - 170, margin + 10, width - 140, margin + 10);
graphics.FillEllipse(Brushes.Red, width - 145, margin + 6, 8, 8);
}
// 保存图表
string chartDir = Path.Combine(Path.GetDirectoryName(filepath), "Charts");
if (!Directory.Exists(chartDir))
Directory.CreateDirectory(chartDir);
string chartPath = Path.Combine(chartDir, $"CH{CH}_LeakageTrend_{datatime}.png");
bitmap.Save(chartPath, ImageFormat.Png);
//MessageBox.Show($"图表已保存至: {chartPath}");
}
}
catch (Exception ex)
{
mxlLog.Instance.Error($"图表生成错误: {ex.Message}", ex);
}
}
// 生成结果统计图
public static void Create_PieChart(int CH, string filepath)
{
try
{
string datatime = DateTime.Now.ToString("yyyyMMdd");
//string filepath = GetExcelFilePath(CH, datatime);
if (!File.Exists(filepath))
return;
var data = ReadExcelData(filepath, 1000);
int okCount = 0;
int ngCount = 0;
foreach (DataRow row in data.Rows)
{
string result = row["测试结果"].ToString();
if (result.Equals("OK", StringComparison.OrdinalIgnoreCase))
okCount++;
else if (result.Equals("NG", StringComparison.OrdinalIgnoreCase))
ngCount++;
}
int total = okCount + ngCount;
if (total == 0)
return;
// 创建统计图
int width = 600;
int height = 400;
using (Bitmap bitmap = new Bitmap(width, height))
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.Clear(Color.White);
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
// 绘制标题
using (Font titleFont = new Font("Arial", 16, FontStyle.Bold))
{
graphics.DrawString($"通道{CH} - 测试结果统计", titleFont, Brushes.Black, 150, 10);
graphics.DrawString($"总计: {total} 个产品", titleFont, Brushes.Black, 200, 40);
}
// 绘制饼图
int centerX = width / 2;
int centerY = height / 2 + 20;
int radius = 120;
if (okCount > 0)
{
float okAngle = 360f * okCount / total;
graphics.FillPie(Brushes.Green, centerX - radius, centerY - radius,
radius * 2, radius * 2, 0, okAngle);
}
if (ngCount > 0)
{
float ngAngle = 360f * ngCount / total;
graphics.FillPie(Brushes.Red, centerX - radius, centerY - radius,
radius * 2, radius * 2, 360f * okCount / total, ngAngle);
}
// 绘制图例
using (Font legendFont = new Font("Arial", 12))
{
graphics.FillRectangle(Brushes.Green, 100, height - 80, 20, 20);
graphics.DrawString($"OK: {okCount} ({okCount * 100f / total:F1}%)",
legendFont, Brushes.Black, 130, height - 80);
graphics.FillRectangle(Brushes.Red, 300, height - 80, 20, 20);
graphics.DrawString($"NG: {ngCount} ({ngCount * 100f / total:F1}%)",
legendFont, Brushes.Black, 330, height - 80);
}
// 保存图表
string chartDir = Path.Combine(Path.GetDirectoryName(filepath), "Charts");
if (!Directory.Exists(chartDir))
Directory.CreateDirectory(chartDir);
string chartPath = Path.Combine(chartDir, $"CH{CH}_ResultStat_{datatime}.png");
bitmap.Save(chartPath, ImageFormat.Png);
}
}
catch (Exception ex)
{
mxlLog.Instance.Error($"生成统计图错误: {ex.Message}", ex);
}
}
// 读取Excel数据
private static DataTable ReadExcelData(string filePath, int maxRows = 10)
{
DataTable dt = new DataTable();
Excel.Application xapp = null;
Excel.Workbook xbook = null;
try
{
xapp = new Excel.Application();
xapp.Visible = false;
xapp.DisplayAlerts = false;
xbook = xapp.Workbooks.Open(filePath);
Excel.Worksheet xsheet = (Excel.Worksheet)xbook.Sheets[1];
// 获取最后一行
int lastRow = xsheet.Cells.Find("*", System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
System.Reflection.Missing.Value,
Excel.XlSearchOrder.xlByRows,
Excel.XlSearchDirection.xlPrevious,
false, System.Reflection.Missing.Value,
System.Reflection.Missing.Value).Row;
// 读取表头创建列
for (int col = 1; col <= 15; col++)
{
string header = (xsheet.Cells[1, col] as Excel.Range)?.Value2?.ToString() ?? $"Column{col}";
dt.Columns.Add(header);
}
// 读取数据从最后maxRows行开始
int startRow = Math.Max(2, lastRow - maxRows + 1);
for (int row = startRow; row <= lastRow; row++)
{
DataRow dr = dt.NewRow();
for (int col = 1; col <= 15; col++)
{
var cellValue = (xsheet.Cells[row, col] as Excel.Range)?.Value2;
dr[col - 1] = cellValue?.ToString() ?? "";
}
dt.Rows.Add(dr);
}
}
catch (Exception ex)
{
mxlLog.Instance.Error($"读取Excel数据错误", ex);
}
finally
{
if (xbook != null)
{
xbook.Close(false);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xbook);
}
if (xapp != null)
{
xapp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xapp);
}
GC.Collect();
GC.WaitForPendingFinalizers();
}
return dt;
}
// 获取Excel文件路径
private static string GetExcelFilePath(int CH, string date)
{
string basePath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string chPath = CH == 1 ? "CH1" : "CH2";
return Path.Combine(basePath, chPath, $"{CH}_{date}.xls");
}
}
}