从零搭建灌装监控系统(十六):Dashboard 设计,KPI卡片与液位可视化
Dashboard 设计KPI卡片与液位可视化这是「从零搭建灌装监控系统」系列第16篇。前面十五篇把通信、数据、报警、日志都做完了但操作员每天盯着的是首页。这篇把后端数据翻译成一眼能看懂的东西四张 KPI 卡片、一个液位柱、一个会呼吸的阀门指示灯。数据都对但没人看得懂功能联调的时候我在首页上放了一排 Label把设备状态原样显示出来产量 102、温度 25.6、运行时间 4.2、节拍 1.5。车间主任看了两分钟问我一句话“所以现在是正常的吗”那一刻我意识到问题不在数据在表达。设备状态本身是中性的操作员需要的是对比——产量对不对得上目标、温度偏离设定值多少、节拍比标准快了还是慢了、阀门到底开没开。纯数字把判断责任推给了人。首页的设计目标就变成了让操作员用一眼代替计算。四张卡片回答四个问题首页顶部排四张卡片每张回答一个问题卡片主数值对照值回答的问题当前产量ActualCountTargetCount今天做了多少离目标还差多少实时温度CurrentTempSettingTemp温度稳不稳偏没偏运行时间RunningTimeDeviceStatus设备在跑还是停了当前节拍CurrentCycleTimeStandardCycleTime快了还是慢了布局用四列等宽的Grid每张卡片套同一个CardStyleGridGrid.Row0Margin0,0,20,0Grid.ColumnDefinitionsColumnDefinitionWidth*/ColumnDefinitionWidth*/ColumnDefinitionWidth*/ColumnDefinitionWidth*//Grid.ColumnDefinitionsBorderGrid.Column0Style{StaticResource CardStyle}Margin0,0,10,0StackPanelTextBlockText当前产量PCS)Foreground{StaticResource AppTextMuted}FontSize14/TextBlockText{Binding ActualCount,StringFormat{}{0:N0}}Foreground{StaticResource AppAccentColor}FontSize32FontFamily{StaticResource FontMono}/TextBlockForeground{StaticResource AppSuccess}FontSize12RunText↑ 目标达成率/RunText{Binding ActualCount}/RunText//RunText{Binding TargetCount}//TextBlock/StackPanel/Border!-- 另外三张同构 --/Grid两个细节值得说。主数值用等宽字体FontMono。数值每秒都在跳等宽字体让数字宽度固定不会出现整行左右抖动。这个体验差异在小屏上特别明显。对照值不换行、不抢焦点。主数值 32 号对照值 12 号且用弱化色。人的视线先落在主数值需要细节时再往下看一行。液位可视化一个矩形就够了液位这种东西用数字表达最浪费。操作员看“液位 63%”要在大脑里转一道看一根柱子不用。Grid!-- 柱体容器 --BorderBackground#1A1A1ACornerRadius4/!-- 液面高度直接绑 LiquidLevel --Rectanglex:NameLiquidLevelVerticalAlignmentBottomOpacity0.8Height{Binding LiquidLevel}Rectangle.FillLinearGradientBrushStartPoint1,0EndPoint0,0GradientStopColor#007ACCOffset0/GradientStopColor#00AAFFOffset1//LinearGradientBrush/Rectangle.Fill/Rectangle!-- 底部底座 --RectangleHeight10VerticalAlignmentBottomMargin0,0,0,20Fill#555//GridVerticalAlignmentBottom加上绑定高度就是一根从底部涨上来的柱子。水平方向的渐变StartPoint1,0到EndPoint0,0让柱体有圆柱的反光感比纯色好看不少。这里有一个容易踩的点Height绑定的是像素值不是百分比。LiquidLevel在 ViewModel 里必须已经换算成实际像素高度。如果直接把 0-100 的百分比丢给Height液位 63 就只画 63 像素高永远到不了顶。换算放在 ViewModel 里或者用IMultiValueConverter把百分比和容器高度一起算。我选前者因为容器高度在界面里是已知的算好再给 UI 更简单。阀门状态让灯会呼吸“阀门打开”和“阀门关闭”只差一个词操作员扫一眼很难捕捉。加一个脉冲动画视觉上就有了优先级。用ControlTemplate的DataTrigger实现不需要任何后台代码ContentControlHorizontalAlignmentRightContentControl.TemplateControlTemplateTargetTypeContentControlStackPanelOrientationHorizontalx:NameContainerEllipsex:NameValueEllipseWidth10Height10Fill{StaticResource AppTextMuted}Margin0,0,5,0/TextBlockx:NameValueTextText阀门关闭Foreground{StaticResource AppTextMuted}FontSize12//StackPanelControlTemplate.TriggersDataTriggerBinding{Binding ValueOpen}ValueTrueSetterTargetNameValueEllipsePropertyFillValue{StaticResource AppSuccess}/SetterTargetNameValueTextPropertyTextValue阀门打开/SetterTargetNameValueTextPropertyForegroundValue{StaticResource AppSuccess}/DataTrigger.EnterActionsBeginStoryboardx:NamePulseStoryboardRepeatBehaviorForeverAutoReverseTrueDoubleAnimationStoryboard.TargetNameValueEllipseStoryboard.TargetPropertyOpacityFrom1.0To0.3Duration0:0:1//Storyboard/BeginStoryboard/DataTrigger.EnterActions/DataTrigger/ControlTemplate.Triggers/ControlTemplate/ContentControl.Template/ContentControlRepeatBehaviorForeverAutoReverseTrue就是一秒一次、来回渐隐。动画只改Opacity不触发布局开销可以忽略。数据流如下DataReceivedAlarmTriggeredPlcService 轮询DashboardViewModel四张 KPI 卡片温度曲线液位柱阀门指示灯AlarmService最近报警列表最近报警只留十条首页放一个最近报警列表让操作员不用切页面就知道刚才发生了什么。关键是限长privatevoidAlarmService_AlarmTriggered(object?sender,AlarmRecorde){Application.Current.Dispatcher.Invoke((){RecentAlarms.Insert(0,AlarmUIModel.FromAlarmRecord(e));if(RecentAlarms.Count10)RecentAlarms.RemoveAt(RecentAlarms.Count-1);});}插入到头部超长从尾部删。这样列表永远是“最近十条”不会随着运行时间无限膨胀。断线之后不要显示旧数据这是我最看重的一条通信断了首页必须清零而不是冻结在最后一帧。privatevoidOnConnectionChanged(object?sender,boolconnected){if(!connected){Application.Current.Dispatcher.Invoke((){ActualCount0;TargetCount0;CurrentTemp0;SettingTemp0;RunningTime0;CurrentCycleTime0;StandardCycleTime0;LiquidLevel0;ValueOpenfalse;});}}为什么要清零因为冻结的旧数据比空白更危险。操作员看到一个正常的温度和液位会以为设备在跑实际上通信早就断了。显示 0 很刺眼刺眼才会让人去看报警。工业界面上“看起来正常”是最贵的一种错误。踩坑记录在构造函数里直接建图表集合SeriesCollection属于 UI 对象必须在 UI 线程创建。构造函数不保证在 UI 线程执行所以要用Dispatcher.BeginInvoke包起来。这个问题我在第 17 篇展开讲。液位高度直接绑百分比Height要像素值。绑 0-100 的百分比柱子永远涨不满。换算放在 ViewModel。断线后保留旧值看起来“界面没崩”实际是在误导操作员。断线即清零。报警列表不设上限跑一整天就是几千条ObservableCollection越大每次插入的开销越明显。插头部 限长。本篇小结设计点做法KPI 卡片四列等宽 Grid 统一 CardStyle主数值可读性等宽字体 大字号 弱化对照值液位Rectangle 底部对齐 高度绑像素值 水平渐变状态指示DataTrigger Storyboard 脉冲动画最近报警插头部 限长十条断线处理全部指标清零不用旧数据糊弄首页能看了但操作员还会问一个更细的问题温度是稳住了还是在慢慢爬数字回答不了这个得靠曲线。下期预告第17篇LiveCharts 实时温度曲线下一篇把温度做成滚动曲线重点解决两个问题怎么只保留最近一段数据以及为什么图表集合不能在后台线程创建。

相关新闻

数据库系统概论第3章例题代码SQL Server实现与避坑指南

数据库系统概论第3章例题代码SQL Server实现与避坑指南

简介:这份文档面向正在学习《数据库系统概论》的高校学生与数据库入门者,聚焦教材第3章数据定义相关例题的代码实现,帮助读者把课堂上的SQL理论落到可运行的语句上。包内仅含1个doc文件,约1.49MB,集中收录了学生表stud…

2026/10/9 10:16:36 阅读更多 →
可执行的软件设计说明书:面向CI/CD与团队协作的实战模板

可执行的软件设计说明书:面向CI/CD与团队协作的实战模板

简介:本资源是一份面向软件开发工程师、系统架构师及高校计算机专业学生的《软件设计说明书》标准化写作模板与实战案例,解决初学者对设计文档结构不清、内容缺失、规范性不足等常见问题。文档基于UML建模工具Rose构建,覆盖简介、需求描述、两…

2026/10/9 10:16:36 阅读更多 →
C++ 继承与多态:从基础语法到虚函数机制全解析

C++ 继承与多态:从基础语法到虚函数机制全解析

1. 继承定义继承是面向对象程序设计中最核心的特性之一,它允许一个类(派生类)基于另一个类(基类)来定义,从而自动获得基类的成员变量和成员函数。继承体现了类之间的层次关系,是代码复用的重要手…

2026/10/9 10:16:36 阅读更多 →

最新新闻

基于Python+MILP的风光储联合调度:电池与废弃矿井抽蓄互补优化

基于Python+MILP的风光储联合调度:电池与废弃矿井抽蓄互补优化

这两年搞新能源消纳的调度研究,有个词绕不开:互补。风电场最常见的情况是深夜大风、负荷却躺在地板上,光伏正好相反,正午出力冲顶、电网一时间吃不下。单靠任何一种电源都没法把这条曲线磨平,于是风电、光伏和储能组成…

2026/10/9 10:58:44 阅读更多 →
深度聚类开源代码库实战指南:从DEC到对比学习的工程落地

深度聚类开源代码库实战指南:从DEC到对比学习的工程落地

在无标注数据这块,很多人习惯性地打开sklearn直接跑一个KMeans,但凡是真正做过几年聚类项目的人都有体会:高维图像、文本向量、用户行为序列这类数据,传统聚类几乎每次都会翻车。原因不是聚类算法本身不行,而是输入特征…

2026/10/9 10:58:44 阅读更多 →
微网虚拟电厂多场景随机规划与CVaR风险优化调度策略

微网虚拟电厂多场景随机规划与CVaR风险优化调度策略

开场:为什么风险量化成了微网调度的硬需求做调度的人,不管是在传统电力系统还是园区级微网,现在绕不开一个词:风险。风光出力天生不稳定,负荷预测也不可能百分之百准,以前我们做确定性调度习惯了&#xff0…

2026/10/9 10:58:44 阅读更多 →
数理统计大作业实战:从假设检验到Python实现的全流程指南

数理统计大作业实战:从假设检验到Python实现的全流程指南

简介:这是一份面向数理统计课程学习者与机器学习初学者的完整大作业报告,围绕鸢尾花数据集展开多方法分析。报告以花萼与花瓣的四个属性为输入,使用马氏距离度量样本相似性,通过混合高斯模型实现聚类,借助主成分分析与…

2026/10/9 10:58:44 阅读更多 →
硅基流动+Chatbox:零成本长期运行DeepSeek-R1的本地AI工作流

硅基流动+Chatbox:零成本长期运行DeepSeek-R1的本地AI工作流

简介:本资源是一份面向初级开发者与个人AI实践者的低成本大模型应用搭建指南,聚焦如何利用硅基流动平台的DeepSeek API与开源跨平台AI助手Chatbox,构建稳定、免费且响应流畅的本地化AI应用。内容覆盖硅基流动高额度免费Token(新用…

2026/10/9 10:58:44 阅读更多 →
基于JWT/JWE的跨系统安全数据透传方案详解

基于JWT/JWE的跨系统安全数据透传方案详解

先说结论:这套“基于JWT/JWE的跨系统安全数据透传方案”,解决的是两个不同域、不同技术栈、甚至不同运维体系的服务之间,如何安全地把一段结构化数据从A端交付到B端——既保证数据在“路上”不被看、不被改,又保证接收方能够验证数…

2026/10/9 10:57:43 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →