副屏别再只显示桌面了,试试把它变成个人信息终端
如果你手头有一台双屏电脑,大概率会遇到这样的场景:主屏写代码、开会议、处理文档,副屏要么放着一个聊天窗口,要么干脆就是一张壁纸。这块屏幕明明占据了大量桌面空间,但绝大多数时间都在“吃灰”。
我的判断很直接:副屏的真正价值,不在于“能多放几个窗口”,而在于“让重要信息持续可见”。主屏是干活的,副屏应当是“扫一眼就知道现状”的信息面板。把副屏改造成个人信息终端,是双屏配置里投入产出比最高的改造之一,而且不需要太多额外硬件,软件方案完全可以搞定。
这篇文章会从信息架构、数据接入、页面渲染、自动刷新、部署播放这几个环节,完整拆解一个可运行的副屏信息面板方案。你可以直接照做,也可以改造成自己的版本。
1. 副屏为什么总是沦为“装饰屏”
先说一个反直觉的结论:副屏不好用,不是屏幕不够大,而是我们拿它干了不该干的事。
很多人默认副屏的使命是“扩展工作区”,所以把副屏和主屏平等对待:桌面放满图标,任务栏占一条,打开一堆窗口往里塞。但实际用下来你会发现几个问题。
第一,人眼的注意力是线性的。你以为“两个屏幕同时看”,实际上大部分时间只有一块屏幕处于焦点区。副屏上的窗口如果长期不交互,就会慢慢变成“看不见的窗口”,直到某天你需要找某个东西,才想起来它被扔在副屏上。
第二,窗口管理成本被严重低估。跨屏拖拽、最大化、切换窗口,这些操作看似轻量,但每切换一次都要消耗几十到几百毫秒的注意力和记忆成本。副屏窗口越多,越容易变成“信息垃圾场”。
第三,副屏的物理位置天然适合“常驻只读信息”。你侧过头去看副屏,通常不需要在副屏上打字、点按钮、拖文件,你的第一需求是“看一眼就知道状态”。这类需求包括现在的几点几分、今天有哪些会、服务器是否告警、构建是否通过、有没有新的紧急任务。
所以副屏的正确用法,不是“第二块工作区”,而是“常驻仪表盘”。两者区别在哪?
- 工作区需要频繁交互,仪表盘只需要定期刷新。
- 工作区追求窗口切换效率,仪表盘追求扫读效率。
- 工作区的内容是过程性的,仪表盘的内容是状态性的。
- 工作区适合放编辑器、终端、浏览器,仪表盘适合放时间、日程、监控、待办、天气。
这也是为什么很多开发者折腾到最后,会把副屏固定成一个只读信息面板。不是因为可玩性高,而是这个用法最贴合副屏的物理属性。
2. 个人信息终端的信息架构:先分层,再设计
在写任何代码之前,先想清楚副屏上该放什么。这一步决定了整个方案的成败——很多副屏改造项目烂尾,不是因为技术难,而是因为信息没有取舍。
副屏信息面板的设计原则可以归纳成一句话:一屏一主题,扫读优先,低频刷新。
所谓“一屏一主题”,是说副屏上所有信息应该服务于同一个核心目的。比如:
- 工作模式:日程、会议提醒、待办任务、CI/CD 状态。
- 运维模式:服务器负载、磁盘水位、日志告警、服务可用性。
- 个人模式:时间、天气、通勤、习惯打卡、新闻摘要。
不要在同一个面板里既塞公司 OKR 又塞游戏战绩,信息密度一旦超过可扫读的阈值,副屏就又变回装饰屏了。
信息层级建议按这么分:
| 优先级 | 信息类型 | 示例 | 刷新频率 |
|---|---|---|---|
| P0 | 时间与日程 | 当前时间、下一个会议 | 分钟级 |
| P1 | 任务与告警 | 待办、构建失败、磁盘告警 | 秒级到分钟级 |
| P2 | 状态与趋势 | 服务器负载、天气、交通 | 分钟级到小时级 |
| P3 | 资讯与摘要 | 新闻、邮件摘要 | 小时级 |
注意一个原则:刷新频率越高,信息越要精简。不要让一块屏幕每隔几秒闪烁一次,那会让副屏变成“注意力干扰器”。
在实际项目里,我推荐用一种更稳妥的判断方式:如果一个信息你“错过 5 分钟也无所谓”,就放到副屏上;如果一个信息“错过 30 秒就出问题”,那是主屏通知的事,不是副屏仪表盘的事。这个取舍标准可以帮助你避免最常见的过度设计。
3. 三种实现路线对比:从零写页面,还是用现成框架
想清楚信息架构之后,接下来要决定技术路线。市面上的方案大致有三类,适用人群和工程成本差别很大。
路线 A:纯网页面板
用 HTML/CSS/JavaScript 写一个全屏网页,通过浏览器在副屏上打开。数据来源可以是静态 JSON、后端 API 或者第三方服务。这是本文重点演示的方案,因为它最可控,不依赖第三方平台,也不受某个开源项目维护状态的影响。
优点:完全可控,前端技术栈通用,可以任意定制布局和刷新逻辑。 缺点:需要自己处理数据采集,工程量从零开始。
路线 B:自托管仪表盘框架
这类开源项目一般能帮你把时间、天气、待办、服务状态等常见模块拼成一张面板,通过配置文件或 UI 添加组件,部分还支持插件机制。适合不想从零写代码、又希望快速搭出一个能用的信息面板的人。
优点:开箱即用,组件丰富。 缺点:定制能力受框架限制,部分项目的响应式适配做得一般,老旧的 1080p 副屏可能显示布局错乱。
路线 C:系统桌面小组件
Windows 的桌面小组件、macOS 的 Widget、手机平板的桌面卡片,本身上手成本最低,但自由度也最低,很难把企业内网的服务状态、自定义接口数据做成统一风格的信息面板。
我的建议是:如果你只是想“稍微利用一下副屏”,从路线 C 开始;如果你希望副屏真正变成信息终端,直接选路线 A。理由很简单——你做这个改造的本质,是想要一个“能接入任意数据源、按你自己的方式呈现”的展示层,只有网页方案能做到这一点。
4. 核心链路设计:数据流才是信息面板的骨架
副屏信息终端的架构,本质上是一条数据流:数据源 -> 采集脚本 -> 数据文件 -> 前端页面 -> 副屏浏览器。
不要一上来就考虑“前端直连数据库”“后端 WebSocket 推送”这种架构。副屏信息面板的场景是“只读展示、弱交互、持续运行”,越简单越稳定。
推荐链路如下:
- 数据源:可以是本机系统状态、远程服务器 API、第三方天气接口、日历订阅、数据库查询结果。
- 采集脚本:用 Python、Shell 或 Go 写一个小脚本,定期轮询数据源,把结果整理成统一格式。
- 数据文件:脚本输出一个静态 JSON 文件,作为前端页面的数据入口。
- 前端页面:一个纯静态 HTML 文件,用 JavaScript 读取 JSON 并渲染成仪表盘布局。
- 副屏浏览器:在副屏上用浏览器全屏打开这个 HTML 文件,并按设定的间隔自动刷新。
这个设计有两个关键优势。
第一个优势是稳定。整条链路里唯一需要持续运行的程序是浏览器,采集脚本只需要定时执行一次,写完 JSON 就退出,不需要常驻后台,也不会因为网络波动直接导致页面崩溃。
第二个优势是安全。静态 JSON 文件可以放在内网目录下,前端页面不直接向外部服务发起跨域请求,敏感数据也不会暴露在公网页面上。
如果你有更复杂的需求,比如多个数据源实时汇合、需要按用户切换显示内容,再考虑引入后端服务和数据库。但对大多数人来说,静态页面 + 定时任务已经能覆盖 80% 的场景。
5. 最小完整示例:30 分钟跑通一个副屏信息面板
下面进入实操环节。这里搭建一套最小可运行的副屏信息面板,包含三个文件:一个数据文件、一个前端页面、一个采集脚本。
5.1 项目结构
info-panel/ ├── data.json ├── index.html └── monitor.sh这套结构在 Windows 和 Linux 上都能跑,采集脚本用 Shell 写是为了避免未装 Python 环境的机器上还要额外安装依赖。如果要用 Python,后面会给出对应版本。
5.2 数据文件:data.json
{ "time": "2024-06-01 09:30:00", "cpu": "23%", "memory": "61%", "disk": "74%", "uptime": "3 days, 04:12", "nextMeeting": "10:00 - 产品评审会" }这个文件由采集脚本定期更新。这里把字段设计成字符串,是为了在页面上直接展示;如果你后续接入告警、趋势图,再把数值型和单位分开,方便前端做格式化。
5.3 前端页面:index.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>副屏信息终端</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: "Segoe UI", "Microsoft YaHei", Arial, sans-serif; background: #0f1419; color: #e6edf3; display: flex; flex-direction: column; height: 100vh; padding: 40px; overflow: hidden; } .header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 36px; } .time { font-size: 72px; font-weight: 700; letter-spacing: 2px; } .date { font-size: 28px; color: #8b949e; } .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; flex: 1; } .card { background: #161b22; border: 1px solid #30363d; border-radius: 16px; padding: 28px; display: flex; flex-direction: column; justify-content: center; } .card .label { font-size: 20px; color: #8b949e; margin-bottom: 12px; } .card .value { font-size: 44px; font-weight: 600; } .meeting { grid-column: span 3; } .meeting .value { font-size: 32px; } .warn { color: #f0883e; } .error { color: #f85149; } </style> </head> <body> <div class="header"> <div class="date" id="date"></div> <div class="time" id="time"></div> </div> <div class="grid"> <div class="card"> <div class="label">CPU 负载</div> <div class="value" id="cpu">--</div> </div> <div class="card"> <div class="label">内存占用</div> <div class="value" id="memory">--</div> </div> <div class="card"> <div class="label">磁盘使用率</div> <div class="value" id="disk">--</div> </div> <div class="card meeting"> <div class="label">下一个会议</div> <div class="value" id="meeting">--</div> </div> </div> <script> async function loadData() { try { const res = await fetch('./data.json', { cache: 'no-store' }); const data = await res.json(); document.getElementById('time').textContent = data.time.split(' ')[1] || ''; document.getElementById('date').textContent = data.time.split(' ')[0] || ''; document.getElementById('cpu').textContent = data.cpu || '--'; document.getElementById('memory').textContent = data.memory || '--'; document.getElementById('disk').textContent = data.disk || '--'; document.getElementById('meeting').textContent = data.nextMeeting || '--'; highlightValue('cpu', data.cpu); highlightValue('memory', data.memory); highlightValue('disk', data.disk); } catch (e) { console.error('数据加载失败:', e); } } function highlightValue(id, value) { const el = document.getElementById(id); if (!value) return; const num = parseFloat(value); if (isNaN(num)) return; if (num >= 90) { el.className = 'value error'; } else if (num >= 75) { el.className = 'value warn'; } else { el.className = 'value'; } } // 初次加载 loadData(); // 每 30 秒刷新一次数据 setInterval(loadData, 30000); </script> </body> </html>这里做了一个关键设计:fetch的cache: 'no-store'能防止浏览器缓存旧的 JSON 文件,使用定时器实现数据刷新,不用重启页面就能拿到最新状态。同时根据数值大小自动改变颜色,给 CPU、内存、磁盘这些指标加上了阈值告警的雏形。
阈值逻辑是:低于 75% 显示默认白色,75%-90% 显示橙色,超过 90% 显示红色。在实际项目中,阈值应该根据你的机器配置来调整,不要照搬。
5.4 采集脚本:monitor.sh
#!/bin/bash # 文件路径:info-panel/monitor.sh # 功能:采集系统状态并写入 data.json,供副屏信息面板展示 DATA_FILE="$(dirname "$0")/data.json" # CPU 使用率(取 1 秒采样) CPU=$(top -bn1 | grep "Cpu(s)" | awk '{printf "%d%%", $2 + $4}') # 内存使用率 MEM_TOTAL=$(free -m | awk '/^Mem:/ {print $2}') MEM_USED=$(free -m | awk '/^Mem:/ {print $3}') MEM_PERCENT=$((MEM_USED * 100 / MEM_TOTAL))% # 磁盘使用率(根分区) DISK=$(df -h / | awk 'NR==2 {print $5}') # 系统运行时长 UPTIME=$(uptime -p | sed 's/up //') # 当前时间 NOW=$(date "+%Y-%m-%d %H:%M:%S") # 下一个会议(示例:从某个接口或本地文件读取) # 这里先用固定值,实际项目可替换成日历 API 或任务管理接口 NEXT_MEETING="10:00 - 产品评审会" cat > "$DATA_FILE" <<EOF { "time": "$NOW", "cpu": "$CPU", "memory": "$MEM_PERCENT", "disk": "$DISK", "uptime": "$UPTIME", "nextMeeting": "$NEXT_MEETING" } EOF脚本执行后,会生成 5.2 节的data.json。核心逻辑是:
- 用
top获取 CPU 使用率,取用户态和系统态之和。 - 用
free计算内存使用率。 - 用
df获取根分区磁盘使用率。 - 用
uptime获取运行时长。
如果你使用 Python 环境,采集脚本逻辑类似,只是换成psutil库,写法上更简洁。但最小方案里,Shell 脚本的好处是无额外依赖,哪怕机器上没有 Python,也能直接跑。
# 文件路径:info-panel/monitor.py # 如果机器有 Python 3,可以用这个版本替代 monitor.sh import json import time import psutil from datetime import datetime data = { "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "cpu": f"{psutil.cpu_percent(interval=1)}%", "memory": f"{psutil.virtual_memory().percent}%", "disk": f"{psutil.disk_usage('/').percent}%", "uptime": time.time() - psutil.boot_time(), "nextMeeting": "10:00 - 产品评审会", } with open("data.json", "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2)5.5 定时刷新:让数据自动更新
手动运行采集脚本只能更新一次,副屏信息终端要求“永不宕机”的数据循环。这一步交给系统定时任务。
Linux / macOS 使用 crontab:
# 每 30 秒执行一次(需要确保脚本有执行权限) * * * * * /path/to/info-panel/monitor.sh * * * * * sleep 30; /path/to/info-panel/monitor.sh注意:cron 的最小粒度是分钟,如果按 30 秒刷新,需要写两行,第二条用sleep 30错开。如果你对实时性要求不高,直接每分钟执行一次也完全够用。
Windows 系统可以用“任务计划程序”,触发器设置为“重复任务,每 1 分钟”,操作选择运行monitor.bat。
到这里,最小可运行的副屏信息面板已经完成。接下来只需要在浏览器里打开index.html,按 F11 全屏,放到副屏上即可。
6. 部署到副屏:浏览器的全屏显示策略
信息面板和数据链路都跑通之后,还有一个容易被忽略的环节——如何让信息面板在副屏上“乖乖待着”。很多方案最后放弃,就是因为浏览器全屏不好控制,或者副屏总是自动熄灭。
6.1 使用浏览器 Kiosk 模式
日常开发时,你可以在副屏打开index.html,按 F11 手动全屏。但如果你想“开机就自动进入面板”,建议使用浏览器的 Kiosk 模式,也就是信息亭模式,让浏览器直接以全屏方式运行,隐藏地址栏、标签页和系统工具栏。
Chrome 启动参数:
chrome.exe --kiosk --app=http://localhost:8080/index.html --window-position=1920,0这里的--window-position=1920,0是按副屏在主屏右侧的场景写的,如果你的副屏在左侧或者上下排列,需要调整坐标。更好的方式是先打开浏览器窗口,拖到副屏位置,再从浏览器菜单里进入全屏。
Edge 启动参数:
msedge.exe --kiosk --app=http://localhost:8080/index.html --window-position=1920,0如果你不需要常驻启动参数,也可以把index.html放到浏览器书签栏,位置拖到第一个,用的时候点一下即可。
6.2 副屏熄屏与休眠处理
副屏信息面板的定位是“持续可见”,那么系统休眠和屏幕熄灭就不能按默认策略来。
Windows 上可以执行:
powercfg /change standby-timeout-ac 0 powercfg /change monitor-timeout-ac 0分别是“接通电源时不进入待机”和“接通电源时显示器不关闭”。如果你担心 OLED 烧屏,或者不想让屏幕一直亮着,可以把休眠策略设为夜间自动关闭,白天保持常亮。
Linux 桌面的电源管理因发行版而异,最基本的方式是设置“永不熄屏”,或使用xset命令:
xset s off xset -dpms6.3 本地服务还是 file:// 直接打开
上面的例子用file://直接打开index.html也能运行,因为fetch加载本地 JSON 在同目录下通常没问题。但更稳妥的做法是起一个极简的本地静态服务,这样既方便局域网内其他设备访问,也能避免浏览器的本地文件安全策略造成干扰。
最简单的静态服务:
# Python 3 用户 cd info-panel python -m http.server 8080 # 或者使用 npx npx serve .然后将浏览器地址指向http://localhost:8080/index.html。在 Windows 下,可以写一个start.bat,开机自动启动静态服务和浏览器:
@echo off cd /d D:\info-panel start "" python -m http.server 8080 timeout /t 2 start "" msedge --kiosk --app=http://localhost:8080/index.html --window-position=1920,0这里有一点要注意:如果你的副屏信息里涉及内网敏感数据,静态服务不要绑定到0.0.0.0,最好只监听127.0.0.1,避免局域网内其他设备直接访问。
7. 进阶扩展:把任意数据源接入信息面板
最小方案跑通后,你会很快发现一个新需求:不能只展示服务器状态,最好把日历、待办、天气、RSS 都放进来。这一节讲如何扩展数据源,同时避免踩坑。
7.1 日历与会议数据
最实用的接入是日历。Google Calendar、Outlook、企业微信日历都提供 API 或订阅链接。最简单的做法是让采集脚本定时拉取日历的 JSON 或 ICS 数据,解析出最近一个会议,写入data.json。
关键点:
- 不要把完整的日历内容都放到页面上,只取最近一个或当天日程摘要即可。
- 认证信息放在采集脚本里,不要出现在前端页面。
- 日历接口的访问失败要能兜底:显示“暂无会议”,而不是一片空白。
7.2 服务监控与告警
如果你有自建的 API 服务或数据库,可以用采集脚本定时探测接口状态:
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health返回 200 表示正常,非 200 或超时视为异常。把状态码和响应时间写入data.json,前端页面可以用红色高亮展示异常服务,实现一个极简告警面板。
需要注意的是,探测接口时一定要设置超时时间,例如:
curl --connect-timeout 3 --max-time 5 -s -o /dev/null -w "%{http_code}" http://localhost:8080/health否则如果某个服务无响应,采集脚本会卡在等待上,导致 data.json 长期不更新。
7.3 第三方天气与资讯
天气和资讯类属于低频数据,不需要每 30 秒拉一次。建议配置更长的刷新间隔,比如每 15 分钟或每小时一次,避免频繁请求第三方接口触发限流。
第三方接口的关键字段需要先验证再写入前端。比如天气接口可能返回晴、多云等中文描述,或clear、cloudy等英文代码,你需要先做好归一化映射再展示,否则副屏上会出现一堆未经处理的原始字符串。
7.4 多数据源汇总的表结构
当数据源变多后,data.json的结构也应该跟着调整。推荐把每个数据源独立成一个模块:
{ "meta": { "updatedAt": "2024-06-01 09:30:00", "sourceCount": 4 }, "system": { "cpu": "23%", "memory": "61%", "disk": "74%" }, "calendar": { "nextMeeting": "10:00 - 产品评审会", "todayCount": 6 }, "services": [ { "name": "api-gateway", "status": 200, "latencyMs": 45 }, { "name": "auth-service", "status": 200, "latencyMs": 132 }, { "name": "report-service", "status": 503, "latencyMs": null } ], "weather": { "temp": 26, "condition": "多云", "humidity": "58%" } }这样前端渲染时,可以按模块独立更新,不需要改动其他部分的逻辑。采集脚本也可以按模块拆分,例如fetch_calendar.sh、fetch_services.sh,每个脚本只负责一个数据源,最后合并成data.json。
8. 常见问题与排查方法
副屏信息面板在运行中会遇到一些典型的“看着小问题,影响很大”的故障。这里整理成表格,方便直接对照排查。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
页面打开后一直显示-- | JSON 文件不存在或格式错误 | 打开浏览器控制台看报错;手动访问 data.json 确认内容 | 先手动运行采集脚本,确认 data.json 是否生成;检查 JSON 是否有尾部逗号 |
| 数据很久不更新 | 定时任务没有生效 | 手动执行一次采集脚本;查看 cron 的日志 | 确认脚本有执行权限;检查 crontab 中路径是否写绝对路径 |
| 浏览器显示旧数据 | 浏览器缓存了旧的 data.json | 查看 Network 面板中是否有 304 状态 | fetch 请求加cache: 'no-store';或给 URL 加时间戳参数 |
| 副屏自动熄屏 | 系统电源策略未修改 | 查看电源设置 | 执行powercfg命令修改显示器超时策略 |
| 字体太小看不清 | 副屏分辨率高,但观看距离远 | 观察副屏实际观看距离 | 增大根字号,卡片标题和数值字号分层,避免只放大某一处 |
| 页面布局错乱 | 不同尺寸副屏导致栅格断裂 | 用浏览器开发者工具切换设备模拟 | 使用clamp()等响应式字体;固定卡片最小宽度并允许换行 |
| 采集脚本偶尔失败 | 网络请求超时或外部接口限流 | 查看脚本输出和日志 | 加超时参数、失败重试、失败时保留上一次的 data.json 而不是写空文件 |
| 多设备同时访问时数据不一致 | 本地静态服务并发能力不足或文件写覆盖 | 检查访问来源 | 静态服务只服务本机场景;如需多人共享,改用真实后端写入 |
| 服务变成横向滚动条 | 某个卡片内容超出一行 | 查看卡片内容长度 | 对长文本做截断,限制单行显示;或调整布局,给长文本更大的卡片范围 |
这里重点提醒一个容易被忽略的问题:采集脚本在失败时,不要生成一个空的或残缺的data.json。很多脚本为了省事,会把 JSON 重定向输出,一旦上游接口异常,直接覆盖成{},副屏就会瞬间变成空白。稳妥的做法是先写临时文件,成功后再原子替换正式文件。
# 先写临时文件,验证成功后再替换 cat > "$DATA_FILE.tmp" <<EOF { ... } EOF if [ -s "$DATA_FILE.tmp" ]; then mv "$DATA_FILE.tmp" "$DATA_FILE" fi这样即使脚本执行到一半失败,旧的data.json依然保留,副屏不会因为数据源抖动而显示异常。
9. 最佳实践与工程建议
当副屏信息面板从“一个小 Demo”变成“每天都要依赖的基础设施”后,它的稳定性、安全性和可维护性就变得很重要。下面这些经验来自实际项目踩坑,按优先级排列。
9.1 敏感数据一律不进前端
很多人的第一版信息面板,会直接把数据库密码、API Token 写在采集脚本里,再渲染到前端页面。这个做法非常危险,因为前端页面是纯静态文件,任何能访问到这个页面的人都能看到这些信息。
正确做法:
- 采集脚本负责所有敏感数据访问。
data.json只暴露展示所需的最小字段。- 静态服务只监听本机或内网,不对外开放。
- 如果团队共享这个信息面板,务必在采集脚本和静态服务之间加一层访问控制。
9.2 告警一定要分层
信息面板上的告警,不要一律用红色闪烁。可以参考监控系统的分级策略:
- 警告(黄色):指标超过 75%,但系统仍可用。
- 严重(红色):指标超过 90%,需要人工介入。
- 恢复(绿色):指标恢复正常。
如果所有异常都用红色闪烁,人眼会产生“告警疲劳”,等到真正严重的问题出现时,反而没人注意了。
9.3 日志与可观测性
采集脚本虽然简单,也要有基本日志。不用引入重型的日志框架,但至少做到以下三点:
- 每次执行记录时间戳和执行结果。
- 失败时输出具体原因(HTTP 状态码、超时、JSON 解析错误)。
- 保留最近 N 条日志,方便排查。
一个简单的做法是追加到一个panel.log文件:
echo "$(date '+%Y-%m-%d %H:%M:%S') monitor.sh executed, cpu=${CPU}, memory=${MEM_PERCENT}" >> panel.log9.4 开机自启与看门狗
副屏信息面板的定位是“持续运行”,所以开机自启几乎是刚需。Windows 可以用“启动”文件夹或“任务计划程序”,Linux 可以用 systemd 服务或桌面环境的“启动应用程序”。
如果你追求更高的稳定性,可以额外写一个简单的看门狗脚本,每隔几分钟检测一次浏览器进程和静态服务进程是否存在,不存在则自动重新拉起。这样比手动重启可靠得多。
9.5 先跑通最小闭环,再叠加功能
最后一个建议,也是最重要的:不要一开始就规划一个“完美的信息面板”,把所有需求都列出来,然后迟迟不开始。
更高效的做法是先跑通一个最小闭环:
- 一台副屏。
- 一个浏览器。
- 一个只显示时间、CPU、内存的 HTML 页面。
- 一个每分钟更新一次的采集脚本。
这个过程会让你真正理解数据流、刷新机制、屏幕部署这些环节,后续再往里面加日历、加告警、加天气,都是顺手的事。如果一上来就想着接入十个数据源,大概率会在第三周放弃。
10. 总结与下一步
副屏改造这件事,技术门槛其实不高,真正的分水岭在于你有没有把它当成一个“小型前端工程”来对待。信息分层要设计,数据流要整理,刷新策略要规划,部署方式要稳定,缺一个环节,最后都会变成“看起来能跑,实际上不想用”。
本文给出的这套方案,核心思想可以概括成一句话:用静态网页作为副屏展示层,用定时采集脚本作为数据源头,两者通过一个 JSON 文件解耦。它的优点是稳定、安全、可定制,而且每一层都可以单独替换。
下一步,你可以从以下方向继续深入:
- 把
data.json换成 PostgreSQL 或 SQLite,做历史趋势图。 - 在采集脚本里接入你的团队日历和 CI/CD 流水线。
- 增加夜间模式,根据时间自动切换深色和浅色主题。
- 如果有多台副屏,可以让不同屏幕展示不同主题的面板。
先动手做,哪怕第一版只有时间、CPU 和内存,也比一块永远显示着壁纸的副屏有意义。跑通之后,你大概率会发现,副屏最值得的用法,不是“多一个窗口”,而是“多一个随时可见的信息入口”。