离散制造业 ERP 开发面向BOM + 工艺路径的生产计划层面、适配 “多应用端 / 主题工作单元模式” 的 WinForm 功能界面组件,核心实现 BOM 结构管理、工艺路径配置、生产计划拆解与多端协同管控。以下是完整的组件设计与实现方案,包含核心架构、业务逻辑、WinForm 界面适配及完整代码示例。
一、 组件核心定位与整体架构
1. 核心定位
| 多应用端 | 设计端(BOM / 工艺维护)、计划端(生产计划拆解)、车间端(计划执行反馈) |
| 主题工作单元 | 生产计划工作台(BOM / 工艺统一管控、计划汇总、多端指令协同、数据可视化) |
| 核心目标 | 基于 BOM + 工艺路径实现生产计划的精准拆解与执行管控,适配离散制造 “多品种、小批量” 特性 |
2. 技术架构(适配 WinForm)
| 界面层 | WinForm 功能组件(BOM 树、工艺表格、计划甘特图、多端指令面板) | .NET Framework 4.8 + DevExpress(可选) |
| 业务逻辑层 | BOM 服务、工艺路径服务、生产计划拆解服务、多端协同调度服务 | 设计模式(工厂、组合、观察者) |
| 数据访问层 | BOM 数据 DAO、工艺数据 DAO、生产计划 DAO、多端指令日志 DAO | SQL Server + Dapper |
| 基础支撑层 | 权限控制、日志组件、跨端通信组件、WinForm 数据绑定工具 | 自定义权限类 + Log4net |
3. 核心数据模型(离散制造特性适配)
csharp
运行
// 基础模型:BOM结构(组合模式适配)
public class BOMNode
{
/// <summary>
/// BOM节点ID
/// </summary>
public int BOMId { get; set; }
/// <summary>
/// 父节点ID(0为根节点)
/// </summary>
public int ParentBOMId { get; set; }
/// <summary>
/// 成品/半成品编码
/// </summary>
public string ProductCode { get; set; }
/// <summary>
/// 物料编码
/// </summary>
public string MaterialCode { get; set; }
/// <summary>
/// 物料名称
/// </summary>
public string MaterialName { get; set; }
/// <summary>
/// 用量
/// </summary>
public decimal Qty { get; set; }
/// <summary>
/// 单位
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 工序序号(关联工艺路径)
/// </summary>
public int ProcessSeq { get; set; }
/// <summary>
/// 子节点(组合模式)
/// </summary>
[JsonIgnore]
public List<BOMNode> Children { get; set; } = new List<BOMNode>();
}
// 工艺路径模型
public class ProcessRoute
{
/// <summary>
/// 工艺ID
/// </summary>
public int ProcessId { get; set; }
/// <summary>
/// 物料/成品编码
/// </summary>
public string MaterialCode { get; set; }
/// <summary>
/// 工序编码
/// </summary>
public string ProcessCode { get; set; }
/// <summary>
/// 工序名称
/// </summary>
public string ProcessName { get; set; }
/// <summary>
/// 工序序号
/// </summary>
public int ProcessSeq { get; set; }
/// <summary>
/// 工作中心(设备/产线)
/// </summary>
public string WorkCenter { get; set; }
/// <summary>
/// 工序时长(分钟)
/// </summary>
public int ProcessTime { get; set; }
/// <summary>
/// 工装夹具需求
/// </summary>
public string ToolRequirement { get; set; }
}
// 生产计划模型(基于BOM+工艺拆解)
public class ProductionPlan
{
/// <summary>
/// 计划单号
/// </summary>
public string PlanNo { get; set; }
/// <summary>
/// 成品编码
/// </summary>
public string ProductCode { get; set; }
/// <summary>
/// 计划数量
/// </summary>
public decimal PlanQty { get; set; }
/// <summary>
/// 计划开始时间
/// </summary>
public DateTime PlanStartTime { get; set; }
/// <summary>
/// 计划结束时间
/// </summary>
public DateTime PlanEndTime { get; set; }
/// <summary>
/// 拆解状态:未拆解/已拆解/执行中/已完成
/// </summary>
public string DisassembleStatus { get; set; }
/// <summary>
/// 所属应用端
/// </summary>
public string AppTerminalCode { get; set; }
}
// 生产计划拆解明细(最小执行单元)
public class PlanDisassembleDetail
{
/// <summary>
/// 明细ID
/// </summary>
public int DetailId { get; set; }
/// <summary>
/// 计划单号
/// </summary>
public string PlanNo { get; set; }
/// <summary>
/// 物料编码
/// </summary>
public string MaterialCode { get; set; }
/// <summary>
/// 工序编码
/// </summary>
public string ProcessCode { get; set; }
/// <summary>
/// 工作中心
/// </summary>
public string WorkCenter { get; set; }
/// <summary>
/// 需求数量(基于BOM用量*计划数量)
/// </summary>
public decimal RequireQty { get; set; }
/// <summary>
/// 工序开始时间
/// </summary>
public DateTime ProcessStartTime { get; set; }
/// <summary>
/// 工序结束时间
/// </summary>
public DateTime ProcessEndTime { get; set; }
/// <summary>
/// 执行状态
/// </summary>
public string ExecuteStatus { get; set; }
}
二、 核心业务组件实现
1. BOM 管理服务(适配离散制造多层 BOM)
csharp
运行
/// <summary>
/// BOM管理服务(组合模式实现多层BOM管理)
/// </summary>
public class BOMService
{
private readonly IDbConnection _dbConn;
private readonly LogHelper _logHelper;
public BOMService(string connStr)
{
_dbConn = new SqlConnection(connStr);
_logHelper = new LogHelper();
}
/// <summary>
/// 获取成品BOM树(适配WinForm TreeView展示)
/// </summary>
/// <param name="productCode">成品编码</param>
/// <returns></returns>
public List<BOMNode> GetBOMTree(string productCode)
{
try
{
// 查询该成品所有BOM节点
var allNodes = _dbConn.Query<BOMNode>(
"SELECT * FROM BOM WHERE ProductCode = @ProductCode ORDER BY ProcessSeq, ParentBOMId",
new { ProductCode = productCode }).ToList();
// 构建树形结构(组合模式)
var rootNodes = allNodes.Where(n => n.ParentBOMId == 0).ToList();
foreach (var root in rootNodes)
{
BuildBOMTree(root, allNodes);
}
return rootNodes;
}
catch (Exception ex)
{
_logHelper.Error($"获取BOM树失败:{ex.Message}");
throw new Exception("BOM结构加载失败", ex);
}
}
/// <summary>
/// 递归构建BOM树
/// </summary>
private void BuildBOMTree(BOMNode parent, List<BOMNode> allNodes)
{
var children = allNodes.Where(n => n.ParentBOMId == parent.BOMId).ToList();
parent.Children = children;
foreach (var child in children)
{
BuildBOMTree(child, allNodes);
}
}
/// <summary>
/// 保存BOM节点(WinForm界面编辑后保存)
/// </summary>
/// <param name="bomNode">BOM节点</param>
/// <returns></returns>
public bool SaveBOMNode(BOMNode bomNode)
{
try
{
if (bomNode.BOMId == 0)
{
// 新增节点
var newId = _dbConn.QuerySingle<int>(
"INSERT INTO BOM (ParentBOMId, ProductCode, MaterialCode, MaterialName, Qty, Unit, ProcessSeq) " +
"VALUES (@ParentBOMId, @ProductCode, @MaterialCode, @MaterialName, @Qty, @Unit, @ProcessSeq); " +
"SELECT SCOPE_IDENTITY();", bomNode);
bomNode.BOMId = newId;
}
else
{
// 更新节点
_dbConn.Execute(
"UPDATE BOM SET ParentBOMId=@ParentBOMId, MaterialCode=@MaterialCode, MaterialName=@MaterialName, " +
"Qty=@Qty, Unit=@Unit, ProcessSeq=@ProcessSeq WHERE BOMId=@BOMId", bomNode);
}
_logHelper.Info($"BOM节点{(bomNode.BOMId == 0 ? "新增" : "更新")}成功,成品:{bomNode.ProductCode},物料:{bomNode.MaterialCode}");
return true;
}
catch (Exception ex)
{
_logHelper.Error($"保存BOM节点失败:{ex.Message}");
return false;
}
}
}
2. 工艺路径服务(适配离散制造多工序)
csharp
运行
/// <summary>
/// 工艺路径服务
/// </summary>
public class ProcessRouteService
{
private readonly IDbConnection _dbConn;
private readonly LogHelper _logHelper;
public ProcessRouteService(string connStr)
{
_dbConn = new SqlConnection(connStr);
_logHelper = new LogHelper();
}
/// <summary>
/// 获取物料工艺路径(适配WinForm DataGridView展示)
/// </summary>
/// <param name="materialCode">物料编码</param>
/// <returns></returns>
public List<ProcessRoute> GetProcessRoute(string materialCode)
{
try
{
return _dbConn.Query<ProcessRoute>(
"SELECT * FROM ProcessRoute WHERE MaterialCode = @MaterialCode ORDER BY ProcessSeq",
new { MaterialCode = materialCode }).ToList();
}
catch (Exception ex)
{
_logHelper.Error($"获取工艺路径失败:{ex.Message}");
throw new Exception("工艺路径加载失败", ex);
}
}
/// <summary>
/// 批量保存工艺路径(WinForm批量编辑)
/// </summary>
/// <param name="processRoutes">工艺路径列表</param>
/// <returns></returns>
public bool BatchSaveProcessRoute(List<ProcessRoute> processRoutes)
{
using (var transaction = _dbConn.BeginTransaction())
{
try
{
foreach (var route in processRoutes)
{
if (route.ProcessId == 0)
{
_dbConn.Execute(
"INSERT INTO ProcessRoute (MaterialCode, ProcessCode, ProcessName, ProcessSeq, WorkCenter, ProcessTime, ToolRequirement) " +
"VALUES (@MaterialCode, @ProcessCode, @ProcessName, @ProcessSeq, @WorkCenter, @ProcessTime, @ToolRequirement)",
route, transaction);
}
else
{
_dbConn.Execute(
"UPDATE ProcessRoute SET ProcessCode=@ProcessCode, ProcessName=@ProcessName, ProcessSeq=@ProcessSeq, " +
"WorkCenter=@WorkCenter, ProcessTime=@ProcessTime, ToolRequirement=@ToolRequirement WHERE ProcessId=@ProcessId",
route, transaction);
}
}
transaction.Commit();
_logHelper.Info($"批量保存工艺路径成功,共{processRoutes.Count}条");
return true;
}
catch (Exception ex)
{
transaction.Rollback();
_logHelper.Error($"批量保存工艺路径失败:{ex.Message}");
return false;
}
}
}
}
3. 生产计划拆解服务(核心业务)
csharp
运行
/// <summary>
/// 生产计划拆解服务(基于BOM+工艺路径)
/// </summary>
public class ProductionPlanService
{
private readonly IDbConnection _dbConn;
private readonly BOMService _bomService;
private readonly ProcessRouteService _processService;
private readonly LogHelper _logHelper;
public ProductionPlanService(string connStr)
{
_dbConn = new SqlConnection(connStr);
_bomService = new BOMService(connStr);
_processService = new ProcessRouteService(connStr);
_logHelper = new LogHelper();
}
/// <summary>
/// 拆解生产计划(核心:BOM用量展开 + 工艺时间排程)
/// </summary>
/// <param name="planNo">计划单号</param>
/// <returns></returns>
public bool DisassembleProductionPlan(string planNo)
{
using (var transaction = _dbConn.BeginTransaction())
{
try
{
// 1. 获取生产计划基础信息
var plan = _dbConn.QuerySingle<ProductionPlan>(
"SELECT * FROM ProductionPlan WHERE PlanNo = @PlanNo",
new { PlanNo = planNo }, transaction);
if (plan == null)
{
_logHelper.Warn($"生产计划{planNo}不存在");
return false;
}
// 2. 获取成品BOM树
var bomTree = _bomService.GetBOMTree(plan.ProductCode);
if (bomTree.Count == 0)
{
_logHelper.Warn($"成品{plan.ProductCode}无BOM结构,无法拆解");
return false;
}
// 3. 清空原有拆解明细
_dbConn.Execute(
"DELETE FROM PlanDisassembleDetail WHERE PlanNo = @PlanNo",
new { PlanNo = planNo }, transaction);
// 4. 递归拆解BOM + 工艺路径
var currentTime = plan.PlanStartTime;
DisassembleBOMNode(bomTree, plan, ref currentTime, transaction);
// 5. 更新计划拆解状态
_dbConn.Execute(
"UPDATE ProductionPlan SET DisassembleStatus='已拆解', PlanEndTime=@PlanEndTime WHERE PlanNo=@PlanNo",
new { PlanEndTime = currentTime, PlanNo = planNo }, transaction);
transaction.Commit();
_logHelper.Info($"生产计划{planNo}拆解成功,计划结束时间:{currentTime}");
return true;
}
catch (Exception ex)
{
transaction.Rollback();
_logHelper.Error($"拆解生产计划失败:{ex.Message}");
return false;
}
}
}
/// <summary>
/// 递归拆解BOM节点,生成工序级计划明细
/// </summary>
private void DisassembleBOMNode(List<BOMNode> bomNodes, ProductionPlan plan, ref DateTime currentTime, IDbTransaction transaction)
{
foreach (var node in bomNodes)
{
// 1. 获取该物料工艺路径
var processRoutes = _processService.GetProcessRoute(node.MaterialCode);
if (processRoutes.Count == 0)
{
_logHelper.Warn($"物料{node.MaterialCode}无工艺路径,跳过");
continue;
}
// 2. 计算该物料需求数量(BOM用量 * 计划数量)
var requireQty = node.Qty * plan.PlanQty;
// 3. 按工序生成计划明细
foreach (var process in processRoutes)
{
var detail = new PlanDisassembleDetail
{
PlanNo = plan.PlanNo,
MaterialCode = node.MaterialCode,
ProcessCode = process.ProcessCode,
WorkCenter = process.WorkCenter,
RequireQty = requireQty,
ProcessStartTime = currentTime,
ProcessEndTime = currentTime.AddMinutes(process.ProcessTime),
ExecuteStatus = "待执行"
};
// 插入明细
_dbConn.Execute(
"INSERT INTO PlanDisassembleDetail (PlanNo, MaterialCode, ProcessCode, WorkCenter, RequireQty, ProcessStartTime, ProcessEndTime, ExecuteStatus) " +
"VALUES (@PlanNo, @MaterialCode, @ProcessCode, @WorkCenter, @RequireQty, @ProcessStartTime, @ProcessEndTime, @ExecuteStatus)",
detail, transaction);
// 更新当前时间
currentTime = detail.ProcessEndTime;
}
// 4. 递归拆解子节点
if (node.Children.Count > 0)
{
DisassembleBOMNode(node.Children, plan, ref currentTime, transaction);
}
}
}
/// <summary>
/// 获取计划拆解明细(适配WinForm甘特图/表格展示)
/// </summary>
/// <param name="planNo">计划单号</param>
/// <returns></returns>
public List<PlanDisassembleDetail> GetPlanDisassembleDetail(string planNo)
{
try
{
return _dbConn.Query<PlanDisassembleDetail>(
"SELECT * FROM PlanDisassembleDetail WHERE PlanNo = @PlanNo ORDER BY ProcessStartTime",
new { PlanNo = planNo }).ToList();
}
catch (Exception ex)
{
_logHelper.Error($"获取计划拆解明细失败:{ex.Message}");
throw new Exception("计划明细加载失败", ex);
}
}
}
4. 多端协同调度组件(适配多应用端 / 主题工作单元)
csharp
运行
/// <summary>
/// 多端协同调度组件(观察者模式)
/// </summary>
public class MultiTerminalDispatcher
{
// 注册的应用端列表
private readonly List<string> _appTerminals = new List<string>();
// 指令事件(WinForm主题工作单元订阅)
public event EventHandler<PlanCommandEventArgs> PlanCommandReceived;
/// <summary>
/// 注册应用端
/// </summary>
/// <param name="terminalCode">应用端编码</param>
public void RegisterAppTerminal(string terminalCode)
{
if (!_appTerminals.Contains(terminalCode))
{
_appTerminals.Add(terminalCode);
LogHelper.Info($"应用端{terminalCode}注册成功");
}
}
/// <summary>
/// 接收应用端指令
/// </summary>
/// <param name="command">计划指令</param>
public void ReceivePlanCommand(PlanCommand command)
{
try
{
if (!_appTerminals.Contains(command.AppTerminalCode))
{
LogHelper.Warn($"应用端{command.AppTerminalCode}未注册,拒绝指令");
return;
}
// 1. 保存指令日志
SaveCommandLog(command);
// 2. 触发事件(主题工作单元WinForm界面刷新)
OnPlanCommandReceived(new PlanCommandEventArgs(command));
LogHelper.Info($"接收{command.AppTerminalCode}的{command.CommandType}指令,计划号:{command.PlanNo}");
}
catch (Exception ex)
{
LogHelper.Error($"接收计划指令失败:{ex.Message}");
}
}
/// <summary>
/// 保存指令日志
/// </summary>
private void SaveCommandLog(PlanCommand command)
{
using (var conn = new SqlConnection(ConfigHelper.GetConnStr()))
{
conn.Execute(
"INSERT INTO PlanCommandLog (CommandId, AppTerminalCode, CommandType, PlanNo, CommandContent, CommandTime, CommandStatus) " +
"VALUES (@CommandId, @AppTerminalCode, @CommandType, @PlanNo, @CommandContent, @CommandTime, @CommandStatus)",
new
{
CommandId = Guid.NewGuid().ToString("N"),
command.AppTerminalCode,
command.CommandType,
command.PlanNo,
command.CommandContent,
CommandTime = DateTime.Now,
CommandStatus = "已接收"
});
}
}
/// <summary>
/// 触发指令事件
/// </summary>
protected virtual void OnPlanCommandReceived(PlanCommandEventArgs e)
{
PlanCommandReceived?.Invoke(this, e);
}
/// <summary>
/// 获取多端指令汇总(适配主题工作单元界面)
/// </summary>
/// <param name="startTime">开始时间</param>
/// <returns></returns>
public DataTable GetCommandSummary(DateTime startTime)
{
using (var conn = new SqlConnection(ConfigHelper.GetConnStr()))
{
var dt = new DataTable();
dt.Columns.Add("指令ID", typeof(string));
dt.Columns.Add("应用端", typeof(string));
dt.Columns.Add("指令类型", typeof(string));
dt.Columns.Add("计划号", typeof(string));
dt.Columns.Add("指令时间", typeof(DateTime));
dt.Columns.Add("指令状态", typeof(string));
var logs = conn.Query(
"SELECT CommandId, AppTerminalCode, CommandType, PlanNo, CommandTime, CommandStatus " +
"FROM PlanCommandLog WHERE CommandTime >= @StartTime ORDER BY CommandTime DESC",
new { StartTime = startTime });
foreach (var log in logs)
{
dt.Rows.Add(log.CommandId, log.AppTerminalCode, log.CommandType, log.PlanNo, log.CommandTime, log.CommandStatus);
}
return dt;
}
}
}
// 计划指令模型
public class PlanCommand
{
/// <summary>
/// 应用端编码
/// </summary>
public string AppTerminalCode { get; set; }
/// <summary>
/// 指令类型:计划创建/计划拆解/计划调整/执行反馈
/// </summary>
public string CommandType { get; set; }
/// <summary>
/// 计划单号
/// </summary>
public string PlanNo { get; set; }
/// <summary>
/// 指令内容(JSON)
/// </summary>
public string CommandContent { get; set; }
}
// 指令事件参数
public class PlanCommandEventArgs : EventArgs
{
public PlanCommand Command { get; set; }
public PlanCommandEventArgs(PlanCommand command)
{
Command = command;
}
}
三、 WinForm 功能界面组件实现
1. BOM 管理界面(TreeView+DataGridView)
csharp
运行
public partial class BOMManagerForm : Form
{
private readonly BOMService _bomService;
private string _currentProductCode;
public BOMManagerForm()
{
InitializeComponent();
_bomService = new BOMService(ConfigHelper.GetConnStr());
// 初始化成品下拉框
InitProductComboBox();
}
/// <summary>
/// 初始化成品下拉框
/// </summary>
private void InitProductComboBox()
{
using (var conn = new SqlConnection(ConfigHelper.GetConnStr()))
{
var products = conn.Query<string>("SELECT DISTINCT ProductCode FROM BOM");
cboProductCode.DataSource = products;
}
}
/// <summary>
/// 加载BOM树
/// </summary>
private void LoadBOMTree()
{
tvBOM.Nodes.Clear();
var bomTree = _bomService.GetBOMTree(_currentProductCode);
foreach (var root in bomTree)
{
var rootNode = new TreeNode($"{root.MaterialCode}-{root.MaterialName}({root.Qty}{root.Unit})");
rootNode.Tag = root;
AddBOMTreeNode(rootNode, root.Children);
tvBOM.Nodes.Add(rootNode);
}
// 展开所有节点
tvBOM.ExpandAll();
}
/// <summary>
/// 递归添加BOM节点
/// </summary>
private void AddBOMTreeNode(TreeNode parentNode, List<BOMNode> children)
{
foreach (var child in children)
{
var childNode = new TreeNode($"{child.MaterialCode}-{child.MaterialName}({child.Qty}{child.Unit})");
childNode.Tag = child;
parentNode.Nodes.Add(childNode);
AddBOMTreeNode(childNode, child.Children);
}
}
/// <summary>
/// 成品选择变更
/// </summary>
private void cboProductCode_SelectedIndexChanged(object sender, EventArgs e)
{
_currentProductCode = cboProductCode.Text;
LoadBOMTree();
}
/// <summary>
/// 保存BOM节点
/// </summary>
private void btnSaveBOM_Click(object sender, EventArgs e)
{
if (tvBOM.SelectedNode == null)
{
MessageBox.Show("请选择要保存的BOM节点");
return;
}
var bomNode = tvBOM.SelectedNode.Tag as BOMNode;
// 从界面获取编辑后的数据(示例)
bomNode.Qty = decimal.Parse(txtQty.Text);
bomNode.ProcessSeq = int.Parse(txtProcessSeq.Text);
var result = _bomService.SaveBOMNode(bomNode);
if (result)
{
MessageBox.Show("BOM节点保存成功");
LoadBOMTree();
}
else
{
MessageBox.Show("BOM节点保存失败");
}
}
}
2. 生产计划拆解界面(甘特图 + 明细表格)
csharp
运行
public partial class PlanDisassembleForm : Form
{
private readonly ProductionPlanService _planService;
private readonly MultiTerminalDispatcher _dispatcher;
public PlanDisassembleForm()
{
InitializeComponent();
_planService = new ProductionPlanService(ConfigHelper.GetConnStr());
_dispatcher = new MultiTerminalDispatcher();
// 注册应用端
_dispatcher.RegisterAppTerminal("DESIGN001"); // 设计端
_dispatcher.RegisterAppTerminal("PLAN001"); // 计划端
_dispatcher.RegisterAppTerminal("SHOP001"); // 车间端
// 订阅指令事件
_dispatcher.PlanCommandReceived += OnPlanCommandReceived;
// 加载生产计划列表
LoadPlanList();
}
/// <summary>
/// 加载生产计划列表
/// </summary>
private void LoadPlanList()
{
using (var conn = new SqlConnection(ConfigHelper.GetConnStr()))
{
var plans = conn.Query<ProductionPlan>("SELECT * FROM ProductionPlan");
dgvPlanList.DataSource = plans;
}
}
/// <summary>
/// 拆解计划按钮点击
/// </summary>
private void btnDisassemble_Click(object sender, EventArgs e)
{
if (dgvPlanList.SelectedRows.Count == 0)
{
MessageBox.Show("请选择要拆解的生产计划");
return;
}
var planNo = dgvPlanList.SelectedRows[0].Cells["PlanNo"].Value.ToString();
var result = _planService.DisassembleProductionPlan(planNo);
if (result)
{
MessageBox.Show("计划拆解成功");
// 加载拆解明细
LoadPlanDetail(planNo);
// 发送拆解完成指令(模拟多端协同)
_dispatcher.ReceivePlanCommand(new PlanCommand
{
AppTerminalCode = "PLAN001",
CommandType = "计划拆解",
PlanNo = planNo,
CommandContent = JsonConvert.SerializeObject(new { Result = "成功" })
});
}
else
{
MessageBox.Show("计划拆解失败");
}
}
/// <summary>
/// 加载计划拆解明细(适配DataGridView和甘特图)
/// </summary>
private void LoadPlanDetail(string planNo)
{
var details = _planService.GetPlanDisassembleDetail(planNo);
// 绑定表格
dgvPlanDetail.DataSource = details;
// 绑定甘特图(示例:使用DevExpress GanttControl)
// ganttControl1.DataSource = details;
// ganttControl1.TreeList.KeyFieldName = "DetailId";
// ganttControl1.TreeList.ParentFieldName = "DetailId";
// ganttControl1.StartDateFieldName = "ProcessStartTime";
// ganttControl1.FinishDateFieldName = "ProcessEndTime";
// ganttControl1.TaskNameFieldName = "MaterialCode";
}
/// <summary>
/// 指令接收事件(实时刷新界面)
/// </summary>
private void OnPlanCommandReceived(object sender, PlanCommandEventArgs e)
{
// WinForm跨线程更新UI
if (InvokeRequired)
{
Invoke(new Action(() =>
{
lblCommandTip.Text = $"[{DateTime.Now:HH:mm:ss}] {e.Command.AppTerminalCode} – {e.Command.CommandType} – {e.Command.PlanNo}";
LoadPlanList();
// 刷新指令汇总
dgvCommandSummary.DataSource = _dispatcher.GetCommandSummary(DateTime.Today);
}));
}
else
{
lblCommandTip.Text = $"[{DateTime.Now:HH:mm:ss}] {e.Command.AppTerminalCode} – {e.Command.CommandType} – {e.Command.PlanNo}";
LoadPlanList();
dgvCommandSummary.DataSource = _dispatcher.GetCommandSummary(DateTime.Today);
}
}
}
3. 主题工作单元汇总界面(多端指令 + 计划监控)
csharp
运行
public partial class PlanWorkbenchForm : Form
{
private readonly MultiTerminalDispatcher _dispatcher;
public PlanWorkbenchForm()
{
InitializeComponent();
_dispatcher = new MultiTerminalDispatcher();
// 订阅所有指令事件
_dispatcher.PlanCommandReceived += OnPlanCommandReceived;
// 初始化指令汇总
dgvCommandSummary.DataSource = _dispatcher.GetCommandSummary(DateTime.Today);
// 初始化计划状态统计
LoadPlanStatusStat();
}
/// <summary>
/// 加载计划状态统计(适配Chart控件)
/// </summary>
private void LoadPlanStatusStat()
{
using (var conn = new SqlConnection(ConfigHelper.GetConnStr()))
{
var statData = conn.Query(
"SELECT DisassembleStatus, COUNT(*) AS Count FROM ProductionPlan GROUP BY DisassembleStatus");
// 绑定Chart
chartPlanStatus.Series.Clear();
var series = new Series("计划状态统计", SeriesChartType.Pie);
foreach (var data in statData)
{
series.Points.Add(new DataPoint(data.DisassembleStatus, data.Count));
}
chartPlanStatus.Series.Add(series);
}
}
/// <summary>
/// 指令事件处理
/// </summary>
private void OnPlanCommandReceived(object sender, PlanCommandEventArgs e)
{
Invoke(new Action(() =>
{
dgvCommandSummary.DataSource = _dispatcher.GetCommandSummary(DateTime.Today);
LoadPlanStatusStat();
}));
}
}
四、 大离散制造适配要点与扩展
1. 核心适配要点
- 性能优化:BOM 展开结果缓存、批量指令队列处理、大数据量虚拟列表加载,适配大离散制造的高数据量场景;
- 柔性生产:替代料自动匹配、多版本 BOM 并行、产线负载均衡,支撑高定制化生产;
- 动态调整:排程冲突检测、一键重排、物料齐套实时刷新,适配生产计划频繁变更;
- WinForm 交互:甘特图拖拽调整排程、BOM 树右键菜单(替代料切换)、缺料预警弹窗,提升操作效率。
2. 扩展方向
- 高级排程算法:集成遗传算法 / 模拟退火算法,实现多目标(交期、成本、产能)优化排程;
- MES/ERP 集成:对接主流 ERP(SAP / 用友)和 MES 系统,同步生产执行数据;
- 移动端适配:添加 WebAPI 层,支持车间端移动端扫码领料、反馈执行状态;
- 预警中心:排程冲突、物料缺料、BOM 版本变更预警,支持邮件 / 短信推送;
- 数据看板:工厂 / 产线级排程进度、物料齐套率、指令执行率可视化大屏。
总结
核心关键点
该组件可直接作为大离散制造业 ERP 的核心 WinForm 中间件,适配多指令端 / 应用调度模式,支撑从 BOM 物料调度到排程计划管控的全流程业务场景。



