当前位置: 首页 > news >正文

智能工厂项目复盘

最近参与开发了一个面向生产现场的智能工厂管理系统。项目整体基于WinForms + SQL Server + .NET Framework 4.7.2实现,采用UI / BLL / DAL / Model的分层架构,围绕设备基础信息、实时监控、报警处理、维修工单、OEE 分析和首页可视化大屏展开。

这个项目给我的收获很大,因为它不是单一的 CRUD 系统,而是把“设备管理”“实时状态模拟”“报警联动”“OEE 数据分析”和“山海鲸大屏展示”串成了一条完整的数据链路。 在这个项目中,我主要负责两块内容:

  1. 模拟数据模块

  2. 首页山海鲸大屏显示模块

下面结合项目结构、主要功能和核心代码,做一次完整复盘。

一、项目介绍

这个智能工厂系统的目标,是把生产现场分散的数据整合到统一平台中,帮助管理人员和运维人员更直观地掌握设备状态、报警情况和生产效率。

从代码结构来看,系统分为四层:

  1. UI:WinForms 界面层,负责页面展示、交互逻辑和页面切换。

  2. BLL:业务逻辑层,负责实时数据编排、状态判断、OEE 计算和大屏聚合。

  3. DAL:数据访问层,负责 SQL 查询、数据持久化和多表联查。

  4. Model:实体模型层,负责在各层之间传递结构化数据。

主界面在UI/FrmMain.cs中完成页面路由,把首页、基础数据、OEE、报警、模拟数据五个模块整合到一个入口中:

private void LoadSelectedPage() { if (uiTabControlMenu1.SelectedTab == main) { NavigateUtil.NavigateTo<FrmBigScreen>(bigpanel); } else if (uiTabControlMenu1.SelectedTab == BasicData) { NavigateUtil.NavigateTo<FrmEquipmentManager>(basePnl); } else if (uiTabControlMenu1.SelectedTab == OEE) { NavigateUtil.NavigateTo<OEEDataForm>(uiOEEPanel); } else if (uiTabControlMenu1.SelectedTab == Alarm) { NavigateUtil.NavigateTo<FrmAlarmInfo>(alarminfoPnl); } else if (uiTabControlMenu1.SelectedTab == SimulatedData) { NavigateUtil.NavigateTo<FrmEquipmentMonitorDesigner>(FrmEquipmentMonitorpanel); } }

这段代码虽然不复杂,但它体现了整个系统的功能组织方式,也能直接看出项目的核心业务组成。

二、项目主要功能

1. 首页山海鲸大屏

首页通过山海鲸大屏展示工厂的综合运营情况,包括:

  1. 设备状态总览

  2. 实时监控概况

  3. 当前报警情况

  4. 工单进度统计

  5. OEE 总览与趋势

这个页面不是简单的静态展示,而是通过本地接口实时读取系统中的业务数据。

2. 基础数据管理

基础数据模块主要用于设备信息维护,支持:

  1. 设备列表查询

  2. 按状态、设备类型、厂家筛选

  3. 分页显示

  4. 新增、编辑、删除、详情查看

这一块为后续的监控、报警、OEE 计算提供了统一的设备主数据来源。

3. OEE 查询与分析

OEE 模块支持:

  1. OEE 原始数据分页查询

  2. 按设备、日期筛选

  3. 趋势折线图展示

  4. 设备 OEE 排名

  5. AI 智能建议生成

其中 AI 建议模块会根据当前筛选范围、设备排名和近 7 日趋势,自动生成简洁的中文分析建议,这一点也增强了系统的智能化体验。

4. 报警管理

报警模块主要用于展示当前活动报警及其处理情况,支持报警确认、忽略、关联工单等操作。 它既能承接实时监控模块触发的异常,也能为首页大屏提供报警统计数据。

5. 模拟数据监控

模拟数据模块是我负责的重点部分。这个页面不是单纯把数据库里的数据读出来,而是主动模拟设备传感器采样过程,并结合阈值动态判断设备状态。主要功能包括:

  1. 设备监控数据每秒自动刷新

  2. 温度、湿度、粉尘、噪音、压力、电流、振动等多指标模拟

  3. 按状态、类型筛选

  4. 分页浏览

  5. 手动开关机

  6. 手动报警

  7. 左侧详情面板联动展示

三、我负责的模块一:模拟数据模块

1. 模块设计目标

模拟数据模块的核心目标,不是“随机生成几个数字”这么简单,而是尽可能贴近真实设备监控场景:

  1. 新设备首次进入监控页时,要生成一组合理的初始数据;

  2. 在线设备每次刷新时,数据要围绕当前值做小幅波动;

  3. 数据要与阈值联动,能够自然地产生正常、预警、危险等状态;

  4. 出现危险状态时,要自动触发保护停机;

  5. 页面刷新后,数据要及时回写数据库,供报警、大屏等模块复用。

2. 业务处理主流程

模拟数据模块的核心业务入口在BLL/MonitorServiceBLL.cs

我在这里做了“读取原始数据 -> 生成/推进采样值 -> 状态评估 -> 危险停机 -> 回写数据库”的完整闭环:

public List<EquipmentMonitorDtoModels> GetMonitorList() { DataTable dt = _monitorDal.GetMonitorRawData(); var list = new List<EquipmentMonitorDtoModels>(); foreach (DataRow row in dt.Rows) { var dto = Map(row); bool refreshSample = false; if (!dto.HasRealtimeRecord) { ResetToNormalState(dto); refreshSample = true; } else if (ShouldResetToNormalState(dto)) { ResetToNormalState(dto); refreshSample = true; } else { refreshSample = dto.IsOnline && !IsOfflineByTimeout(dto); if (refreshSample) { AdvanceRealtimeSample(dto); } } StatusEvaluateResultModels result = EvaluateStatus(dto); if (ShouldAutoShutdown(result)) { ApplyDangerShutdown(dto, result); } dto.DeviceStatus = result.DeviceStatus; dto.StatusDescription = result.StatusDescription; dto.SuggestedAlarmLevel = result.SuggestedAlarmLevelName; dto.IsOnline = result.IsOnline; _monitorDal.SaveMonitorSnapshot(dto, refreshSample); list.Add(dto); } return list.OrderBy(item => item.EquipmentId).ToList(); }

这段代码的价值在于,它把“模拟”和“业务判断”真正结合在了一起。页面每刷新一次,都不是简单查库,而是在模拟一次设备新的运行状态。

3. 模拟数据生成算法

为了让数据变化更自然,我没有直接使用“完全随机值”,而是使用“以当前值为中心的小范围漂移 + 小概率越界”的方式生成下一个采样点:

private decimal? NextMetricValue(decimal? current, decimal? min, decimal? max, decimal fallbackStep, decimal maxJump) { if (!current.HasValue && !min.HasValue && !max.HasValue) { return null; } decimal lower = min ?? ((current ?? 0m) - (fallbackStep * 6m)); decimal upper = max ?? ((current ?? 0m) + (fallbackStep * 6m)); decimal range = Math.Max(upper - lower, fallbackStep * 4m); decimal center = current ?? ((lower + upper) / 2m); decimal driftFactor = (decimal)(_random.NextDouble() * 2d - 1d); decimal next = center + (driftFactor * Math.Max(range * 0.08m, fallbackStep)); double alertChance = _random.NextDouble(); if (min.HasValue && alertChance < 0.08d) { next = min.Value - Math.Max(range * 0.12m, fallbackStep); } else if (max.HasValue && alertChance < 0.16d) { next = max.Value + Math.Max(range * 0.12m, fallbackStep); } else { next = Clamp(next, lower - (range * 0.18m), upper + (range * 0.18m)); } next = Clamp(next, center - maxJump, center + maxJump); return Math.Round(Math.Max(0m, next), 2, MidpointRounding.AwayFromZero); }

这样的设计有几个好处:

  1. 数据波动更接近真实设备运行过程;

  2. 不会每次刷新都剧烈跳变;

  3. 又能以一定概率制造异常状态,便于测试报警和联动逻辑。

4. 状态判断与危险停机

我在这一块实现了按多指标阈值判断设备状态的逻辑:如果全部正常,状态为“正常”;如果命中 1 个异常指标,则为“预警”;命中 2 个及以上,则升级为“危险”;若危险状态成立,则自动停机。

private StatusEvaluateResultModels EvaluateStatus(EquipmentMonitorDtoModels dto) { var problems = new List<string>(); bool offlineByTimeout = IsOfflineByTimeout(dto); if (!dto.IsOnline) { return new StatusEvaluateResultModels { DeviceStatus = "离线", StatusDescription = string.IsNullOrWhiteSpace(dto.StatusDescription) ? "设备当前处于离线状态。" : dto.StatusDescription, SuggestedAlarmLevel = 3, SuggestedAlarmLevelName = "紧急", IsOnline = false }; } if (offlineByTimeout) { return new StatusEvaluateResultModels { DeviceStatus = "离线", StatusDescription = string.Format("超过 {0} 秒未收到新数据,设备已判定为离线。", dto.OfflineTimeoutSeconds), SuggestedAlarmLevel = 3, SuggestedAlarmLevelName = "紧急", IsOnline = false }; } CheckRange(problems, "温度", dto.Temperature, dto.TemperatureMin, dto.TemperatureMax, "℃"); CheckRange(problems, "湿度", dto.Humidity, dto.HumidityMin, dto.HumidityMax, "%"); CheckRange(problems, "粉尘", dto.Dust, dto.DustMin, dto.DustMax, string.Empty); CheckRange(problems, "噪音", dto.Noise, dto.NoiseMin, dto.NoiseMax, "dB"); CheckRange(problems, "压力", dto.Pressure, dto.PressureMin, dto.PressureMax, "MPa"); CheckRange(problems, "电流", dto.ElectricCurrent, dto.ElectricCurrentMin, dto.ElectricCurrentMax, "A"); CheckRange(problems, "振动", dto.Vibration, dto.VibrationMin, dto.VibrationMax, "mm/s"); if (problems.Count == 0) return CreateResult("正常", "全部指标正常", 0, "无", true); if (problems.Count == 1) return CreateResult("预警", string.Join(";", problems), 1, "警告", true); if (problems.Count == 2) return CreateResult("危险", string.Join(";", problems), 2, "严重", true); return CreateResult("危险", string.Join(";", problems), 3, "紧急", true); }

危险状态触发后,我还补充了自动保护停机逻辑:

private void ApplyDangerShutdown(EquipmentMonitorDtoModels dto, StatusEvaluateResultModels result) { dto.IsOnline = false; result.IsOnline = false; result.SuggestedAlarmLevel = 3; result.SuggestedAlarmLevelName = "紧急"; result.StatusDescription = BuildDangerShutdownDescription(result.StatusDescription); dto.CollectTime = DateTime.Now; }

这样做的意义在于,模拟数据模块不只是“能看”,而是真的具备了业务联动能力。

5. 页面层实现:自动刷新 + 筛选 + 分页 + 仪表盘

UI/FrmEquipmentMonitorDesigner.cs中,我把监控页做成了一个完整工作台。页面每秒刷新一次数据,并联动更新筛选、分页、统计区和详情区。

private void LoadMonitorData() { if (_loading) { return; } try { _loading = true; int? selectedEquipmentId = GetSelectedEquipmentId(); List<EquipmentMonitorDtoModels> list = _monitorService.GetMonitorList(); AlarmStatisticsDtoModels alarmStatistics = _monitorService.GetAlarmStatistics(); _monitorItems.Clear(); _monitorItems.AddRange(list); UpdateFilterOptions(_monitorItems); ApplyFilterAndPaging(selectedEquipmentId, false); UpdateDashboard(list, alarmStatistics); UpdateRefreshState(list); } finally { _loading = false; } }

另外,我还做了动态状态渲染,不同设备状态对应不同颜色,让页面在视觉上更容易突出异常设备。

四、我负责的模块二:首页山海鲸大屏显示模块

1. 模块设计思路

首页大屏模块的核心目标,是把分散在设备、实时监控、报警、工单、OEE 等多个表中的数据整合成山海鲸大屏可以直接绑定的数据结构。

这里我主要做了三件事:

  1. 启动本地接口服务,把系统业务数据以 JSON 形式对外暴露;

  2. 在业务层完成多模块聚合,输出统一 DTO;

  3. 对图表数据做结构转换,让山海鲸无需额外脚本也能直接绑定。

2. 启动本地大屏接口服务

UI/Program.cs中,程序启动后会先初始化CefSharp,再尝试启动本地大屏接口服务:

static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); InitializeCefSharp(); if (!BigScreenApiHostService.TryStart()) { MessageBox.Show( "山海鲸本地接口启动失败,监控大屏页面可能无法获取实时数据。\r\n\r\n" + "错误信息:" + BigScreenApiHostService.LastErrorMessage, "接口启动提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); } Application.Run(new FrmLogin()); }

这一步的意义在于,让 WinForms 桌面程序具备“本地后端服务”的能力,大屏页面就可以像访问普通 Web 接口一样读取系统数据。

3. 大屏接口路由设计

我在UI/util/BigScreenApiHostService.cs中通过HttpListener实现了轻量级接口服务,并定义了首页总览、设备状态、实时监控、报警、工单、OEE 等多个接口。

private void HandleRequest(HttpListenerContext context) { AddCorsHeaders(context.Response); if (!string.Equals(context.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { WriteJson(context, 405, new ApiResponse<object> { Success = false, Message = "当前接口仅支持 GET 请求。", GeneratedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Data = null }); return; } string path = NormalizePath(context.Request.Url.AbsolutePath); switch (path) { case "api/bigscreen/dashboard": WriteJson(context, 200, new ApiResponse<object> { Success = true, Message = "大屏完整数据获取成功。", GeneratedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Data = _service.GetDashboardData( GetIntQuery(context, "realtimeCount", GetIntSetting("DefaultRealtimeItemCount", 10)), GetIntQuery(context, "alarmCount", GetIntSetting("DefaultAlarmItemCount", 10)), GetIntQuery(context, "workOrderCount", GetIntSetting("DefaultWorkOrderItemCount", 10)), GetIntQuery(context, "oeeCount", GetIntSetting("DefaultOeeItemCount", 10)), GetIntQuery(context, "trendDays", GetIntSetting("DefaultOeeTrendDayCount", 7))) }); return; } }

这里我还统一加上了 CORS 响应头,确保山海鲸大屏页面可以直接跨域取数。

4. 大屏聚合逻辑

首页大屏聚合的核心入口在BLL/BigScreenServiceBLL.cs。 我把设备状态、实时监控、报警、工单和 OEE 五大区块一次性聚合成一个BigScreenDashboardModels对象:

public BigScreenDashboardModels GetDashboardData( int realtimeItemCount = 10, int alarmItemCount = 10, int workOrderItemCount = 10, int oeeItemCount = 10, int oeeTrendDayCount = 7) { return new BigScreenDashboardModels { GeneratedAt = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), DeviceStatusOverview = GetDeviceStatusOverview(), RealtimeOverview = GetRealtimeOverview(realtimeItemCount), AlarmOverview = GetAlarmOverview(alarmItemCount), WorkOrderOverview = GetWorkOrderOverview(workOrderItemCount), OeeOverview = GetOeeOverview(oeeItemCount, oeeTrendDayCount) }; }

这样的封装方式非常适合大屏场景,因为前端只需要请求一次,就能拿到首页所需的完整数据。

5. 图表数据结构转换

山海鲸大屏对数据结构有比较明确的要求,所以我在业务层提前把原始统计结果转换成图表可直接绑定的结构,例如Name + ValueCategory + SeriesName + Value

比如单系列图表转换:

private List<BigScreenSeriesChartItemModels> BuildSingleSeriesChartItems( IEnumerable<BigScreenNameValueChartItemModels> items, string seriesName) { var list = new List<BigScreenSeriesChartItemModels>(); if (items == null) { return list; } foreach (BigScreenNameValueChartItemModels item in items) { list.Add(CreateSeriesChartItem(item.Name, seriesName, item.Value)); } return list; }

再比如 OEE 多系列趋势图转换:

private List<BigScreenSeriesChartItemModels> BuildOeeTrendChartItems( List<BigScreenOeeTrendItemModels> trendItems, int trendDayCount) { var list = new List<BigScreenSeriesChartItemModels>(); if (trendItems == null || trendItems.Count == 0) { return BuildEmptyOeeTrendChartItems(trendDayCount); } foreach (BigScreenOeeTrendItemModels item in trendItems) { list.Add(CreateSeriesChartItem(item.CalculateDate, "OEE", item.OeeRate)); list.Add(CreateSeriesChartItem(item.CalculateDate, "Availability", item.AvailabilityRate)); list.Add(CreateSeriesChartItem(item.CalculateDate, "Performance", item.PerformanceRate)); list.Add(CreateSeriesChartItem(item.CalculateDate, "Quality", item.QualityRate)); } return list; }

这样处理后,山海鲸端几乎不需要再写额外脚本,绑定效率会高很多。

6. WinForms 内嵌山海鲸页面

UI/FrmBigScreen.cs中,我通过CefSharp将山海鲸大屏页面直接嵌入到 WinForms 首页。

private const string BigScreenUrl = @"http://大屏部署地址/"; private ChromiumWebBrowser browser; private void EnsureBrowser() { if (browser != null && !browser.IsDisposed) { return; } browser = new ChromiumWebBrowser(BigScreenUrl) { Dock = DockStyle.Fill }; browser.IsBrowserInitializedChanged += Browser_IsBrowserInitializedChanged; Controls.Add(browser); browser.BringToFront(); }

这样一来,首页既保留了桌面端程序的一体化体验,又能使用山海鲸的可视化能力。

五、项目亮点

亮点 1:模拟数据不是纯随机,而是“可控波动 + 阈值联动”

很多课程项目的模拟数据只是Random.Next(),但这个项目里,我做的是面向业务场景的动态模拟。 初始值尽量落在安全区间中间,后续每次采样以当前值为中心小幅漂移,并保留一定概率触发越界,这样就能自然演示“正常 -> 预警 -> 危险 -> 停机”的完整流程。

private decimal? CreateInitialMetricValue(decimal? min, decimal? max, decimal fallbackCenter, decimal fallbackSpread) { decimal lower; decimal upper; if (min.HasValue || max.HasValue) { lower = min ?? Math.Max(0m, (max ?? fallbackCenter) - (fallbackSpread * 4m)); upper = max ?? (lower + (fallbackSpread * 4m)); } else { lower = Math.Max(0m, fallbackCenter - fallbackSpread); upper = fallbackCenter + fallbackSpread; } decimal padding = Math.Min((upper - lower) * 0.18m, fallbackSpread); decimal safeLower = lower + padding; decimal safeUpper = upper - padding; decimal next = safeLower + ((safeUpper - safeLower) * (decimal)_random.NextDouble()); return Math.Round(Math.Max(0m, next), 2, MidpointRounding.AwayFromZero); }

亮点 2:大屏接口和桌面程序深度融合

这个项目不是“WinForms 一套、大屏一套”,而是把桌面程序和可视化大屏打通了。 程序启动时先拉起本地接口服务,大屏再通过接口直接读取业务层聚合结果。

public static bool TryStart() { if (_server != null) { return true; } try { _server = new BigScreenApiServer(ReadPrefixesFromConfig(), new BigScreenServiceBLL()); _server.Start(); LastErrorMessage = string.Empty; return true; } catch (Exception ex) { LastErrorMessage = ex.Message; Stop(); return false; } }

这种方式的好处是:

  1. 保留原有三层架构;

  2. 不需要额外单独部署 Web 后端;

  3. 大屏和业务系统使用同一份数据来源,避免口径不一致。

六、总结

这个智能工厂项目让我比较有成就感的地方,在于我负责的两块模块都不是孤立功能:

  1. 模拟数据模块负责生产“可用、可信、可联动”的实时监控数据;

  2. 山海鲸大屏模块负责把这些数据和报警、工单、OEE 聚合起来,变成更直观的可视化结果。

从开发体验上来说,我觉得这个项目最有价值的地方有三点:

  1. 不是只做页面,而是打通了数据、业务、展示三个层次;

  2. 不是只做静态功能,而是加入了实时刷新、状态判断、自动停机等动态逻辑;

  3. 不是只做后台管理,而是把大屏可视化和 AI 建议也融合进来了。

如果让我再总结一句,这个项目真正锻炼我的地方,不是单独写了多少代码,而是让我学会了如何把多个模块串成一套完整的智能工厂业务流程。

http://www.jsqmd.com/news/639779/

相关文章:

  • 告别模拟器!用Pixel 7真机调试Framework:Android 15 userdebug编译、刷机与JAR包热更新实战
  • Windows APK安装终极指南:告别模拟器的轻量级解决方案
  • Skylum Aperty v1.6.1.1567 人工智能图像修饰和编辑软件
  • 2026年在线客服系统推荐,免费按需付费年费便宜售后有保障 - 品牌2026
  • 仓库管理怎么管?仓库管理每天必看这5个数据
  • 5个步骤搞定CLIP图文匹配:本地工具实测,效果直观看得见
  • 2026届学术党必备的AI辅助写作神器推荐
  • Tiny11Builder终极指南:让你的老旧电脑流畅运行Windows 11
  • 2026年降AI工具怎么选才不踩坑?过来人总结的3个选择标准 - 还在做实验的师兄
  • 从零到一:在Nginx中部署SM2国密证书实战指南
  • 2026年日本国际食品展JFEX - 中国组团单位- 新天国际会展 - 新天国际会展
  • 涨薪技术|Prometheus之PromQL聚合操作
  • 2026年AI客服机器人哪个好?系统推荐选型避坑指南 - 品牌2026
  • 参加过一次就懂:半导体全产业链展会该怎么选 - 品牌2026
  • 2026年全渠道智能客服哪家好?支持抖音网页微博电话邮件 - 品牌2026
  • 【多模态大模型推理加速终极指南】:20年AI基础设施专家亲授7大实战优化路径,90%团队尚未掌握的低延迟部署密钥
  • Xilinx差分输入缓冲原语实战解析:从基础IBUFDS到高级节能控制
  • 前电机效率表(转速,扭矩:效率%)
  • 【技术综述】MedIAnomaly:医学图像异常检测三大范式深度解析与实战指南
  • SCMP供应链管理专家报名,靠谱授权培训机构推荐 - 众智商学院官方
  • 通达信缠论分析插件终极指南:5分钟告别复杂技术分析
  • Windows Defender 彻底移除指南:免费开源工具解决系统性能问题终极教程
  • 2026年理工科论文降AI工具推荐:专业术语保护哪款做得更好 - 还在做实验的师兄
  • Boost/Buck-Boost电路电感计算Excel工具分享(附频率避坑技巧)
  • macOS Xbox控制器驱动架构:360Controller内核扩展深度解析与生产环境部署指南
  • JT808协议、JT809协议、JT1078协议的定义及区别
  • 如何在Windows上高效构建词法语法分析器:完整实战指南
  • 从FlashAttention到通用内核:TileLang如何用一套Python语法统一AI高性能编程
  • CompressO:一站式解决视频存储难题的智能压缩方案
  • 2026年旅游行业智能客服推荐,旅行社酒店景区客服系统平台优选 - 品牌2026