这三个系统其实是上位机里最典型的"业务三件套":配置管参数、报表管统计、报警管异常。它们共享同一套数据层和权限体系,建议一起设计而不是各写各的。
一、参数配置管理系统
1. 核心设计原则
所有参数不写死在代码里,PLC IP、端口、站号、采集间隔、报警阈值、权限都应外置到 JSON/XML 或配置类中,好处是不改代码就能适配不同现场。
2. 版本化与迁移(最容易出事故的地方)
JSON 配置文件中必须包含版本号字段(如configVersion: 3),启动时根据版本号执行逐步迁移逻辑,而不是简单判断文件能否打开。禁止因新增字段直接生成新配置覆盖旧文件,需通过版本比对做字段映射与数据转换。
publicclassConfigManager{privateconstintCurrentVersion=3;publicAppConfigLoad(stringpath){varraw=File.ReadAllText(path);vardoc=JObject.Parse(raw);varver=doc["configVersion"]?.Value<int>()??1;// 逐级迁移,不要跳级if(ver<2)MigrateV1ToV2(doc);if(ver<3)MigrateV2ToV3(doc);varcfg=doc.ToObject<AppConfig>();Validate(cfg);// 关键:禁止字段缺失时静默用默认值returncfg;}}几个必须守住的细节:配置按用途拆分为独立文件(如 system.json 系统参数、device.json 设备标定参数、recipe/ 工艺配方),不同配置有独立生命周期,避免导出工艺配方时误覆盖设备地址或标定参数;加载时对关键字段做显式校验,并限制参数范围、明确单位(如速度要区分毫米/秒与毫米/分);保存时采用原子性替换策略,先写临时文件确认成功后再替换原文件,关键配置保存前保留上一份备份以支持快速恢复。
3. 权限分级
工控场景通常采用三级权限:操作员(查看、确认、启停)、管理员(参数修改、报表导出)、超级管理员(配置通信、用户管理)。参数修改入口务必挂权限校验,并同步写操作日志。
二、生产报表统计系统
1. 先分清数据类别
工控数据分两类,存储策略完全不同:配置数据和业务数据(设备信息、用户权限、工单记录、报警历史)结构化、需要事务支持、查询条件复杂,属于关系型数据库的活儿;时序数据(温度曲线、转速波动)写入频繁、单条简单、按时间范围查询、很少修改,是时序数据库的主场。两类数据用不同方案,别图省事用一个库搞定所有事。
历史数据建议采用分钟级聚合归档,既保证追溯精度,又控制数据量膨胀。
2. 报表生成流程
报表生成基于历史数据,结合 NPOI、EPPlus 等 Excel 操作组件,无需依赖 Office 环境。核心流程分四步:数据查询(按时间范围、设备类型从数据库查询,需优化语句避免大数据量阻塞主线程);模板设计(定义表头、列名、数据格式和统计规则如平均值/最大值/最小值);数据填充与样式设置;导出与归档,可设置定时归档避免文件堆积。
publicasyncTaskGenerateDailyReportAsync(DateTimeday){// 1. 异步查询,避免阻塞 UIvardata=await_repo.GetAggregatedAsync(day,day.AddDays(1));// 2. 模板填充 + 统计usingvarpkg=newExcelPackage();varws=pkg.Workbook.Worksheets.Add("日报");ws.Cells["A1"].Value=$"生产日报{day:yyyy-MM-dd}";// ... 表头、数据、边框样式// 3. 归档并记录日志varpath=Path.Combine(_archivePath,$"Daily_{day:yyyyMMdd}.xlsx");awaitpkg.SaveAsAsync(newFileInfo(path));}如果是 Web 端或需要复杂中国式报表,可以考虑后端基于 ASP.NET Core Web API 提供数据接口,用 EF Core 或 Dapper 做数据访问,SignalR 实现报表数据实时推送,Redis 缓存高频查询数据;也可以集成 FineReport 这类专业工具通过 API 对接数据源。数据库设计需建立事实表与维度表,多厂区场景可采用主库+业务库动态路由,读写分离优化查询性能。
三、设备报警记录系统
1. 分级与规则
常见报警类型包括上限报警(超过设定值)、下限报警(低于设定值)、变化率报警(变化太快)、偏差报警(偏离正常值)、超时报警(长时间无数据)。分级上可参考:紧急(红色闪烁,如温度超上限 15℃、热电偶断线,声光报警+弹窗置顶+短信通知)、重要(橙色,超上下限 5℃,弹窗+记录+企业微信推送)、一般(黄色,偏差预警或通信短暂中断,界面提示+日志)、提示(蓝色,开关机、参数变更,仅记录不打扰)。
2. 全生命周期 + 防抖
每条报警应完整记录"产生 → 确认 → 恢复 → 关闭"四个时间节点,支持追溯响应时长。防抖是必做的:温度在阈值附近来回跳动会导致报警反复出现,可用延时确认(连续 3 次超限才报警)或滞回区间(触发值 80、恢复值 75)来避免临界抖动。
publicclassAlarmEngine{privatereadonlyDictionary<string,int>_overCount=new();publicvoidEvaluate(AlarmRulerule,doublevalue){if(value>rule.UpperLimit){if(++_overCount[rule.PointId]<rule.ConfirmCount)return;// 延时确认_=_service.RaiseAsync(rule,value);}elseif(value<rule.RecoverLimit)// 滞回,而非直接等于上限{_overCount[rule.PointId]=0;_=_service.RecoverAsync(rule);}}}3. 表结构与实现要点
核心表可参考:MachineInfo(机台编号、型号、位置、OPC 地址)、AlarmRule(点位、上下限、优先级、防抖时间)、AlarmRecord(产生/确认/恢复时间、确认人、持续时长)、OperationLog(用户、操作类型、时间、IP)、SystemUser(账号、角色、密码哈希)。EF Core 配置上建议用 DateTime 精准映射 SQL Server 的 datetime2(3) 保证毫秒级精度,温度历史表按月份分区,报警记录表建立 MachineId + RaiseTime 复合索引。
实现要点:报警判断放在子线程避免卡 UI;报警记录存数据库保证可追溯;确认操作要记录谁在什么时候确认的;历史报警定期清理。另外建议加上报警屏蔽功能,维护时可临时屏蔽,避免检修期间刷屏。
四、三者如何协同
建议按模块拆分:通信模块、数据采集模块、报警模块、曲线模块、报表模块、权限模块、配置模块、日志模块,做到新增设备不改动旧代码、新增协议实现接口即可、新增字段配置加一行而不用改逻辑。日志方面至少要覆盖四类:通信日志(收发报文、IP、端口、时间)、操作日志(谁、何时、做了什么)、报警日志(变量、值、阈值、时间)、异常日志(堆栈、方法、现场信息)。
如果你目前的项目是 WinForm 还是 WPF、数据库用的是 SQLite 还是 SQL Server,可以告诉我,我按你的实际结构给一份更具体的表设计和模块划分方案。