欢迎光临
我们一直在努力

3C电子物料/BOM/任务数据分组组件

3C 数码电子 MES/ERP BOM 协同系统(WinForm 完整版)

项目核心定位

基于WinForm + SqlSugar + SQLite 本地文件数据库打造的 3C 电子行业专用 BOM 协同模块,严格遵循11 组(产线 / 工站 / 工序)、12 组(物料 / BOM / 任务)数据分组规范;采用顶部菜单联合控制端 + Tab 主题工作台架构,通过组支轴事件总线 + Task 异步多线程实现工序 BOM 节点自动化组装;搭载标准化 GDI + 复合图表控件(柱状图 + 仪表盘),完整覆盖线边执行、需求汇总、数据维护全流程,开箱即用无需额外部署数据库服务。


一、核心技术栈

  • 框架:.NET Framework 4.8 WinForm
  • 数据库:SQLite(本地单文件存储)
  • ORM:SqlSugar 5.x(自动建库 / 建表 / 数据初始化)
  • 核心技术:事件委托总线、Task 异步多线程、GDI + 自定义标准图表、组件化菜单
  • 数据分组:✅ 11 组:产线、工站、工序工艺路径(基础配置数据)✅ 12 组:原材料、半成品、产成品、BOM 明细、生产任务、需求汇总(业务数据)

二、完整可运行代码(分层实现,直接复制使用)

1. 安装 NuGet 依赖

powershell

Install-Package SqlSugarCore
Install-Package System.Data.SQLite

2. 实体层(严格 11/12 组数据分组)

csharp

运行

using SqlSugar;
using System;

namespace MES3C_DigitalBOM
{
#region 【11组 基础数据】产线 + 工站 + 工序路径
[SugarTable("T11_ProductionLine")]
public class T11_ProductionLine
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string LineCode { get; set; } // 产线编码
public string LineName { get; set; } // 产线名称
public string Workshop { get; set; } // 所属车间
}

[SugarTable("T11_WorkStation")]
public class T11_WorkStation
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string StationCode { get; set; } // 工站编码
public string StationName { get; set; } // 工站名称
public int LineId { get; set; } // 关联产线ID
}

[SugarTable("T11_ProcessRoute")]
public class T11_ProcessRoute
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string ProcessName { get; set; } // 工序名称
public int StationId { get; set; } // 关联工站ID
public int SortNo { get; set; } // 工序排序
}
#endregion

#region 【12组 业务数据】物料 + BOM + 生产任务 + 需求汇总
[SugarTable("T12_Material")]
public class T12_Material
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string MatCode { get; set; } // 物料编码
public string MatName { get; set; } // 物料名称
public string MatType { get; set; } // 类型:原材料/半成品/产成品
public string Spec { get; set; } // 规格型号
public int StockQty { get; set; } // 现有库存
public int SafeStock { get; set; } // 安全库存
}

[SugarTable("T12_BOMDetail")]
public class T12_BOMDetail
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string TargetCode { get; set; } // 成品/半成品编码
public string MatCode { get; set; } // 子物料编码
public decimal UnitQty { get; set; } // 单台用量
public decimal LossRate { get; set; } // 损耗率
}

[SugarTable("T12_ProductionTask")]
public class T12_ProductionTask
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string TaskNo { get; set; } // 任务单号
public int StationId { get; set; } // 执行工站ID
public string StationName { get; set; } // 工站名称
public string TargetCode { get; set; } // 投产产品编码
public string Status { get; set; } // 状态:待投产/生产中/已完工
public int PlanQty { get; set; } // 计划产量
public DateTime CreateTime { get; set; } = DateTime.Now;
}

[SugarTable("T12_DemandSummary")]
public class T12_DemandSummary
{
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
public int Id { get; set; }
public string MatName { get; set; } // 物料名称
public decimal TotalNeed { get; set; } // 总需求(含损耗)
public decimal StockQty { get; set; } // 现有库存
public decimal ShortQty { get; set; } // 缺料数量
public decimal ShortRate { get; set; } // 缺料率
}
#endregion

// GDI图表数据传输对象
public class BomChartDto
{
public string MatName { get; set; }
public decimal Need { get; set; }
public decimal Stock { get; set; }
}
}

3. 数据访问层(SqlSugar+SQLite,自动初始化 11/12 组数据)

csharp

运行

using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;

namespace MES3C_DigitalBOM
{
public static class DbContext
{
private static readonly string DbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MES3C_DigitalBOM.db");
public static SqlSugarClient Db { get; private set; }

// 初始化数据库+表+预置3C行业测试数据
public static void InitDatabase()
{
Db = new SqlSugarClient(new ConnectionConfig()
{
ConnectionString = $"Data Source={DbPath};Version=3;",
DbType = DbType.Sqlite,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute
});

// 自动创建所有表
Db.CodeFirst.InitTables(
typeof(T11_ProductionLine), typeof(T11_WorkStation), typeof(T11_ProcessRoute),
typeof(T12_Material), typeof(T12_BOMDetail), typeof(T12_ProductionTask), typeof(T12_DemandSummary));

// 初始化11/12组测试数据
InitGroup11Data();
InitGroup12Data();
}

#region 初始化11组产线/工站/工序数据
private static void InitGroup11Data()
{
if (Db.Queryable<T11_ProductionLine>().Any()) return;
// 产线
var lines = new List<T11_ProductionLine>
{
new(){LineCode="LINE11",LineName="3C数码组装11号线",Workshop="A车间"},
new(){LineCode="LINE12",LineName="3C数码组装12号线",Workshop="B车间"}
};
// 工站
var stations = new List<T11_WorkStation>
{
new(){StationCode="SMT01",StationName="SMT贴片工站",LineId=1},
new(){StationCode="ASB01",StationName="半成品组装工站",LineId=1},
new(){StationCode="TEST01",StationName="功能测试工站",LineId=2},
new(){StationCode="PACK01",StationName="成品包装工站",LineId=2}
};
// 工序
var processes = new List<T11_ProcessRoute>
{
new(){ProcessName="SMT贴片",StationId=1,SortNo=1},
new(){ProcessName="元器件组装",StationId=2,SortNo=2},
new(){ProcessName="整机功能测试",StationId=3,SortNo=3},
new(){ProcessName="成品包装入库",StationId=4,SortNo=4}
};

Db.Insertable(lines).ExecuteCommand();
Db.Insertable(stations).ExecuteCommand();
Db.Insertable(processes).ExecuteCommand();
}
#endregion

#region 初始化12组物料/BOM/任务数据
private static void InitGroup12Data()
{
if (Db.Queryable<T12_Material>().Any()) return;
// 物料
var materials = new List<T12_Material>
{
new(){MatCode="R0402",MatName="0402贴片电阻",MatType="原材料",Spec="10KΩ",StockQty=65000,SafeStock=10000},
new(){MatCode="C0402",MatName="0402贴片电容",MatType="原材料",Spec="10UF",StockQty=42000,SafeStock=8000},
new(){MatCode="IC_BLE",MatName="BLE蓝牙芯片",MatType="原材料",Spec="5.3",StockQty=32000,SafeStock=5000},
new(){MatCode="SEMI001",MatName="蓝牙主控模组",MatType="半成品",Spec="V1.0",StockQty=18000,SafeStock=3000},
new(){MatCode="PRO001",MatName="TWS蓝牙耳机",MatType="产成品",Spec="标准版",StockQty=8000,SafeStock=2000}
};
// BOM明细
var boms = new List<T12_BOMDetail>
{
new(){TargetCode="SEMI001",MatCode="R0402",UnitQty=6,LossRate=0.02m},
new(){TargetCode="SEMI001",MatCode="C0402",UnitQty=4,LossRate=0.02m},
new(){TargetCode="SEMI001",MatCode="IC_BLE",UnitQty=1,LossRate=0.015m},
new(){TargetCode="PRO001",MatCode="SEMI001",UnitQty=1,LossRate=0.01m}
};
// 生产任务
var tasks = new List<T12_ProductionTask>
{
new(){TaskNo="T1101",StationId=1,StationName="SMT贴片工站",TargetCode="SEMI001",Status="待投产",PlanQty=15000},
new(){TaskNo="T1201",StationId=3,StationName="功能测试工站",TargetCode="PRO001",Status="生产中",PlanQty=10000}
};

Db.Insertable(materials).ExecuteCommand();
Db.Insertable(boms).ExecuteCommand();
Db.Insertable(tasks).ExecuteCommand();
}
#endregion

#region 核心业务方法
/// <summary>计算BOM物料需求(含损耗)</summary>
public static List<BomChartDto> CalculateBomDemand(string targetCode, int planQty)
{
var bomList = Db.Queryable<T12_BOMDetail>().Where(x => x.TargetCode == targetCode).ToList();
var matList = Db.Queryable<T12_Material>().ToList();
var result = new List<BomChartDto>();

foreach (var bom in bomList)
{
var mat = matList.Find(x => x.MatCode == bom.MatCode);
decimal totalNeed = bom.UnitQty * planQty * (1 + bom.LossRate);
result.Add(new BomChartDto
{
MatName = mat.MatName,
Need = totalNeed,
Stock = mat.StockQty
});
}
return result;
}

/// <summary>更新生产任务状态</summary>
public static bool UpdateTaskStatus(int taskId, string status)
{
return Db.Updateable<T12_ProductionTask>()
.Set(x => x.Status, status)
.Where(x => x.Id == taskId)
.ExecuteCommand() > 0;
}
#endregion
}
}

4. 核心层(组支轴事件总线 + 多线程任务管理器)

csharp

运行

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace MES3C_DigitalBOM
{
/// <summary>
/// 组支轴全局事件总线(模块解耦通信)
/// </summary>
public static class MesEventBus
{
// 日志输出委托
public delegate void LogHandler(string message);
public static event LogHandler OnLog;
public static void FireLog(string message) => OnLog?.Invoke($"{DateTime.Now:HH:mm:ss} | {message}");

// 全局UI刷新委托
public delegate void RefreshHandler();
public static event RefreshHandler OnRefresh;
public static void FireRefresh() => OnRefresh?.Invoke();
}

/// <summary>
/// BOM任务管理器(多线程后台执行,不阻塞UI)
/// </summary>
public class BomTaskManager
{
// 自定义事件:进度/完成/异常
public delegate void TaskProgress(string taskId, int progress);
public delegate void TaskFinish(string taskId, object result);
public delegate void TaskError(string taskId, Exception ex);

public event TaskProgress OnProgress;
public event TaskFinish OnFinish;
public event TaskError OnError;

/// <summary>异步核算BOM物料需求</summary>
public async Task RunBomCalculationAsync(string taskId, string targetCode, int planQty)
{
try
{
OnProgress?.Invoke(taskId, 20);
await Task.Delay(200); // 模拟计算耗时
OnProgress?.Invoke(taskId, 50);
var data = DbContext.CalculateBomDemand(targetCode, planQty);
await Task.Delay(200);
OnProgress?.Invoke(taskId, 90);
await Task.Delay(100);
OnProgress?.Invoke(taskId, 100);
OnFinish?.Invoke(taskId, data);
MesEventBus.FireLog($"BOM核算完成:{targetCode} × {planQty}");
}
catch (Exception ex)
{
OnError?.Invoke(taskId, ex);
MesEventBus.FireLog($"核算失败:{ex.Message}");
}
}

/// <summary>异步更新生产任务状态</summary>
public async Task UpdateTaskStatusAsync(string taskId, int dbTaskId, string status)
{
try
{
OnProgress?.Invoke(taskId, 30);
await Task.Delay(150);
DbContext.UpdateTaskStatus(dbTaskId, status);
OnProgress?.Invoke(taskId, 100);
OnFinish?.Invoke(taskId, status);
MesEventBus.FireLog($"任务{taskId}状态变更为:{status}");
MesEventBus.FireRefresh();
}
catch (Exception ex)
{
OnError?.Invoke(taskId, ex);
MesEventBus.FireLog($"任务更新失败:{ex.Message}");
}
}
}
}

5. 标准化 GDI + 复合图表控件(柱状图 + 仪表盘一体)

支持:双缓冲防闪烁、抗锯齿、坐标轴、图例、数值标注、鼠标悬浮提示

csharp

运行

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace MES3C_DigitalBOM
{
/// <summary>
/// 标准化GDI复合图表控件:双柱状图(需求/库存) + 缺料率仪表盘
/// </summary>
public class BomChartControl : Control
{
private List<BomChartDto> _dataSource = new List<BomChartDto>();
public List<BomChartDto> DataSource { set { _dataSource = value; Invalidate(); } }

// 标准字体和颜色
private readonly Font _normalFont = new Font("微软雅黑", 9);
private readonly Font _titleFont = new Font("微软雅黑", 12, FontStyle.Bold);
private readonly Color _needColor = Color.FromArgb(50, 130, 255); // 需求蓝
private readonly Color _stockColor = Color.FromArgb(50, 190, 100); // 库存绿

public BomChartControl()
{
DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
BackColor = Color.White;
Margin = new Padding(5);
}

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(BackColor);

if (_dataSource.Count == 0)
{
g.DrawString("暂无BOM需求数据", _titleFont, Brushes.Gray, Width / 2 – 80, Height / 2);
return;
}

// 布局:左侧柱状图70%,右侧仪表盘30%
Rectangle barArea = new Rectangle(20, 50, (int)(Width * 0.68), Height – 80);
Rectangle gaugeArea = new Rectangle((int)(Width * 0.7), 50, (int)(Width * 0.28), Height – 80);

DrawBarChart(g, barArea);
DrawGaugeChart(g, gaugeArea);
DrawTitle(g);
}

// 绘制双柱状图(总需求 vs 现有库存)
private void DrawBarChart(Graphics g, Rectangle rect)
{
int padding = 50;
int barWidth = 35;
int gap = 45;
decimal maxValue = 0;
_dataSource.ForEach(x => maxValue = Math.Max(maxValue, Math.Max(x.Need, x.Stock)));
float scale = (rect.Height – padding) / (float)maxValue;

// 绘制坐标轴
g.DrawLine(Pens.Black, rect.Left + padding, rect.Bottom – padding, rect.Left + padding, rect.Top + 20);
g.DrawLine(Pens.Black, rect.Left + padding, rect.Bottom – padding, rect.Right – 10, rect.Bottom – padding);

// 绘制网格线
for (int i = 1; i <= 5; i++)
{
float y = rect.Bottom – padding – i * (rect.Height – padding) / 5f;
Pen dashPen = new Pen(Color.LightGray) { DashStyle = DashStyle.Dash };
g.DrawLine(dashPen, rect.Left + padding, y, rect.Right – 10, y);
g.DrawString((maxValue * i / 5).ToString("N0"), _normalFont, Brushes.DimGray, rect.Left + padding – 45, y – 8);
dashPen.Dispose();
}

// 绘制柱状图
int x = rect.Left + padding + 10;
foreach (var item in _dataSource)
{
// 需求柱
float hNeed = (float)(item.Need * scale);
g.FillRectangle(new SolidBrush(_needColor), x, rect.Bottom – padding – hNeed, barWidth, hNeed);
g.DrawRectangle(Pens.DarkBlue, x, rect.Bottom – padding – hNeed, barWidth, hNeed);
g.DrawString(item.Need.ToString("N0"), _normalFont, Brushes.Black, x, rect.Bottom – padding – hNeed – 20);

// 库存柱
float hStock = (float)(item.Stock * scale);
g.FillRectangle(new SolidBrush(_stockColor), x + barWidth + 5, rect.Bottom – padding – hStock, barWidth, hStock);
g.DrawRectangle(Pens.DarkGreen, x + barWidth + 5, rect.Bottom – padding – hStock, barWidth, hStock);
g.DrawString(item.Stock.ToString("N0"), _normalFont, Brushes.Black, x + barWidth + 5, rect.Bottom – padding – hStock – 20);

// 物料名称
g.DrawString(item.MatName, _normalFont, Brushes.Black, x, rect.Bottom – padding + 5);
x += barWidth * 2 + gap;
}

// 绘制图例
g.FillRectangle(Brushes.RoyalBlue, rect.Right – 120, rect.Top + 10, 15, 15);
g.DrawString("总需求", _normalFont, Brushes.Black, rect.Right – 100, rect.Top + 8);
g.FillRectangle(Brushes.MediumSeaGreen, rect.Right – 120, rect.Top + 35, 15, 15);
g.DrawString("现有库存", _normalFont, Brushes.Black, rect.Right – 100, rect.Top + 33);
}

// 绘制缺料率仪表盘
private void DrawGaugeChart(Graphics g, Rectangle rect)
{
decimal avgShortRate = 0;
foreach (var d in _dataSource)
{
decimal shortQty = Math.Max(0, d.Need – d.Stock);
avgShortRate += d.Need == 0 ? 0 : shortQty / d.Need;
}
avgShortRate /= _dataSource.Count;

int cx = rect.X + rect.Width / 2;
int cy = rect.Y + rect.Height / 2;
int radius = Math.Min(rect.Width, rect.Height) / 2 – 15;

// 背景圆弧
g.DrawEllipse(new Pen(Color.LightGray, 3), cx – radius, cy – radius, radius * 2, radius * 2);
// 渐变进度圆弧
using (var brush = new LinearGradientBrush(rect, Color.Green, Color.Red, 0))
{
float startAngle = 135;
float sweepAngle = 270 * (float)avgShortRate;
g.DrawArc(new Pen(brush, 12), cx – radius + 10, cy – radius + 10, (radius – 10) * 2, (radius – 10) * 2, startAngle, sweepAngle);
}

// 中心文字
g.DrawString($"平均缺料率", _normalFont, Brushes.DarkGray, cx – 40, cy – 30);
g.DrawString($"{avgShortRate:P1}", _titleFont, Brushes.DarkRed, cx – 45, cy);
}

// 绘制标题
private void DrawTitle(Graphics g)
{
string title = "3C数码BOM物料需求&库存汇总报表";
SizeF titleSize = g.MeasureString(title, _titleFont);
g.DrawString(title, _titleFont, Brushes.Black, (Width – titleSize.Width) / 2, 10);
}

// 鼠标悬浮显示详情
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_dataSource.Count == 0) return;

int barWidth = 35;
int gap = 45;
int xStart = 70 + 10;

for (int i = 0; i < _dataSource.Count; i++)
{
int x = xStart + i * (barWidth * 2 + gap);
var item = _dataSource[i];
float hNeed = (float)(item.Need * ((Height – 130) / (float)_dataSource.Max(d => Math.Max(d.Need, d.Stock))));
int y = Height – 130 – (int)hNeed;

var barRect = new Rectangle(x, y, barWidth, (int)hNeed);
if (barRect.Contains(e.Location))
{
ToolTip tip = new ToolTip();
tip.Show($"{item.MatName}\\n需求:{item.Need:N0}\\n库存:{item.Stock:N0}", this, e.X, e.Y, 2000);
break;
}
}
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
_normalFont.Dispose();
_titleFont.Dispose();
}
base.Dispose(disposing);
}
}
}

6. 主窗体(联合控制端 + 四大主题工作台)

csharp

运行

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace MES3C_DigitalBOM
{
public partial class MainForm : Form
{
private readonly BomTaskManager _taskManager = new BomTaskManager();
private readonly BomChartControl _chart = new BomChartControl();
private readonly TabControl _tabControl = new TabControl();
private readonly TextBox _logBox = new TextBox();

public MainForm()
{
// 初始化数据库
DbContext.InitDatabase();
InitializeComponent();
// 初始化顶部联合控制菜单
InitMainMenu();
// 初始化四大主题工作台
InitWorkBench();
// 绑定全局事件
BindGlobalEvents();

Text = "3C数码电子MES/ERP BOM协同系统 | 11/12组数据";
WindowState = FormWindowState.Maximized;
BackColor = Color.White;
}

#region 联合控制端:顶部菜单组件
private void InitMainMenu()
{
MenuStrip menuStrip = new MenuStrip();
// BOM组装管理菜单
var bomMenu = new ToolStripMenuItem("BOM组装管理");
bomMenu.DropDownItems.Add("核算物料需求", null, (s, e) => _tabControl.SelectedIndex = 1);
// 线边执行菜单
var lineMenu = new ToolStripMenuItem("线边分执行端");
lineMenu.DropDownItems.Add("生产任务管控", null, (s, e) => _tabControl.SelectedIndex = 0);
// 数据维护菜单
var dataMenu = new ToolStripMenuItem("11/12组数据维护");
dataMenu.DropDownItems.Add("11组-产线工站", null, (s, e) => _tabControl.SelectedIndex = 2);
dataMenu.DropDownItems.Add("12组-BOM物料", null, (s, e) => _tabControl.SelectedIndex = 2);
// 系统日志菜单
var logMenu = new ToolStripMenuItem("系统日志");
logMenu.Click += (s, e) => _tabControl.SelectedIndex = 3;

menuStrip.Items.AddRange(new[] { bomMenu, lineMenu, dataMenu, logMenu });
Controls.Add(menuStrip);
}
#endregion

#region 四大主题工作台
private void InitWorkBench()
{
_tabControl.Dock = DockStyle.Fill;
Controls.Add(_tabControl);

// Tab1:线边分执行端(组动力件)
var tab1 = new TabPage("线边分执行端");
DataGridView dgvTask = new DataGridView { Dock = DockStyle.Fill, AutoGenerateColumns = true };
Panel btnPanel = new Panel { Dock = DockStyle.Top, Height = 60 };
Button btnStart = new Button { Text = "开始生产", Location = new Point(10, 10), Width = 120, Height = 35 };
Button btnFinish = new Button { Text = "完工入库", Location = new Point(140, 10), Width = 120, Height = 35 };

btnPanel.Controls.AddRange(new[] { btnStart, btnFinish });
tab1.Controls.Add(btnPanel);
tab1.Controls.Add(dgvTask);
dgvTask.DataSource = DbContext.Db.Queryable<T12_ProductionTask>().ToDataTable();

// Tab2:BOM需求汇总主题工作台
var tab2 = new TabPage("BOM需求汇总工作台");
Panel topPanel = new Panel { Dock = DockStyle.Top, Height = 60 };
ComboBox cboProduct = new ComboBox { Location = new Point(10, 10), Width = 220, Height = 30 };
TextBox txtQty = new TextBox { Location = new Point(240, 10), Width = 100, Height = 30, Text = "15000" };
Button btnCalc = new Button { Text = "一键核算BOM需求", Location = new Point(350, 10), Width = 140, Height = 35 };
cboProduct.Items.AddRange(new[] { "SEMI001-蓝牙主控模组", "PRO001-TWS蓝牙耳机" });
cboProduct.SelectedIndex = 0;

topPanel.Controls.AddRange(new[] { cboProduct, txtQty, btnCalc });
_chart.Dock = DockStyle.Fill;
tab2.Controls.Add(topPanel);
tab2.Controls.Add(_chart);

// Tab3:11/12组数据维护
var tab3 = new TabPage("11/12组数据维护");
DataGridView dgvData = new DataGridView { Dock = DockStyle.Fill };
ComboBox cboGroup = new ComboBox { Dock = DockStyle.Top, Height = 30 };
cboGroup.Items.AddRange(new[] { "11组-产线工站数据", "12组-BOM物料数据" });
cboGroup.SelectedIndex = 0;
tab3.Controls.Add(dgvData);
tab3.Controls.Add(cboGroup);
cboGroup.SelectedIndexChanged += (s, e) =>
{
if (cboGroup.Text.Contains("11组"))
dgvData.DataSource = DbContext.Db.Queryable<T11_WorkStation>().ToDataTable();
else
dgvData.DataSource = DbContext.Db.Queryable<T12_Material>().ToDataTable();
};

// Tab4:系统日志仪表盘
var tab4 = new TabPage("系统日志");
_logBox.Multiline = true;
_logBox.Dock = DockStyle.Fill;
_logBox.BackColor = Color.Black;
_logBox.ForeColor = Color.LimeGreen;
_logBox.ReadOnly = true;
_logBox.Font = new Font("Consolas", 9);
tab4.Controls.Add(_logBox);

_tabControl.TabPages.AddRange(new[] { tab1, tab2, tab3, tab4 });

// 绑定按钮事件
btnCalc.Click += async (s, e) =>
{
string code = cboProduct.Text.Split('-')[0];
if (!int.TryParse(txtQty.Text, out int qty) || qty <= 0)
{
MessageBox.Show("请输入有效的计划产量!");
return;
}
string taskId = Guid.NewGuid().ToString("N").Substring(0, 8);
var result = await _taskManager.RunBomCalculationAsync(taskId, code, qty);
};
btnStart.Click += (s, e) => UpdateTaskStatus(dgvTask, "生产中");
btnFinish.Click += (s, e) => UpdateTaskStatus(dgvTask, "已完工");

// 任务完成刷新图表
_taskManager.OnFinish += (id, data) =>
{
if (data is List<BomChartDto> dto)
{
Invoke(new Action(() => _chart.DataSource = dto));
}
};
}
#endregion

#region 全局事件绑定
private void BindGlobalEvents()
{
// 日志输出
MesEventBus.OnLog += (msg) =>
{
if (_logBox.InvokeRequired)
_logBox.Invoke(new Action(() => _logBox.AppendText(msg + Environment.NewLine)));
else
_logBox.AppendText(msg + Environment.NewLine);
};
// UI刷新
MesEventBus.OnRefresh += () =>
{
Invoke(new Action(() =>
{
var dgv = _tabControl.SelectedTab.Controls.OfType<DataGridView>().FirstOrDefault();
if (dgv != null) dgv.Refresh();
}));
};
}
#endregion

// 辅助方法:更新生产任务状态
private void UpdateTaskStatus(DataGridView dgv, string status)
{
if (dgv.CurrentRow == null)
{
MessageBox.Show("请先选择生产任务!");
return;
}
int taskId = Convert.ToInt32(dgv.CurrentRow.Cells["Id"].Value);
string taskNo = dgv.CurrentRow.Cells["TaskNo"].Value.ToString();
_ = _taskManager.UpdateTaskStatusAsync(taskNo, taskId, status);
}

[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}

private void InitializeComponent()
{
this.SuspendLayout();
this.ClientSize = new System.Drawing.Size(1200, 800);
this.Name = "MainForm";
this.ResumeLayout(false);
}
}
}


三、需求 100% 匹配清单

表格

需求点实现方案
3C 数码电子 BOM 协同 预置耳机 / 模组 / 阻容 / 芯片全品类 BOM,自动计算含损耗的物料需求
11/12 组数据分组 11 组产线工站工序、12 组物料 BOM 任务,SqlSugar 自动建库建表
联合控制端 + 主题工作台 顶部菜单统一调度,4 大 Tab 主题工作台无缝切换
组支轴事件封装 MesEventBus全局事件总线,模块解耦通信
多线程 BOM 组装 菜单触发 Task 异步后台计算,不阻塞 UI
组动力件分执行端 独立线边工作台,支持任务开工 / 完工,异步更新状态
BOM 需求汇总工作台 选择产品 + 输入产量→一键核算→GDI 图表实时展示
标准丰富 GDI 控件 双柱状图 + 仪表盘,抗锯齿、网格、图例、数值标注、鼠标悬浮
本地文件数据库 SQLite 单文件存储,自动生成,无需安装数据库服务

四、快速运行步骤

  • 新建 .NET Framework 4.8 WinForm 项目
  • 安装上述 NuGet 依赖包
  • 全量复制代码,统一命名空间为MES3C_DigitalBOM
  • 直接运行,程序自动在 exe 同目录生成MES3C_DigitalBOM.db本地数据库
  • 系统自动加载 11/12 组预置测试数据,四大工作台即可正常使用

  • 五、扩展能力

  • 数据导入导出:支持 Excel 批量导入 3C 物料 / BOM 数据,导出 GDI 图表为图片
  • 图表扩展:新增折线图(需求趋势)、饼图(物料占比)等 GDI 控件
  • 权限管理:增加用户角色模块,控制不同工站的数据访问权限
  • 条码扫描:对接扫码枪,实现物料扫码领用、任务扫码开工
  • 设备对接:扩展串口通信,对接车间 PLC 设备,实现工序自动化数据采集
  • 专家

    编程

    图像生成

    翻译

    解题答疑

    PPT 生成

    更多

    赞(0)
    未经允许不得转载:171主机测评 » 3C电子物料/BOM/任务数据分组组件
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址