CF-Server-Monitor 探针面板的 Egern iOS 主屏小组件。 配色与指标口径沿用主题 CFSM-Theme-LuminaPlus。
支持三个主屏尺寸,一个脚本全包:
| 尺寸 | 内容 |
|---|---|
| 小 | 单台机器:旗帜 + 名称 + 在线点 + 更新时间、CPU / 内存 / 磁盘三条进度条、延迟与丢包、实时上下行 |
| 中 | 汇总条(在线数、离线数、全站实时速率)+ 5 行节点(CPU、内存、延迟、丢包) |
| 大 | 标题 + 三块汇总(在线数 / 实时速率 / 累计流量)+ 9 行节点(多一列磁盘)+ 离线名单 |
工具 → 脚本 → 点 +:
| 字段 | 填写内容 |
|---|---|
| 名称 | cfsm-status |
| 类型 | 选 通用 |
| 文件位置 | 选 远程,填下面那条链接 |
| 环境变量 | API_BASE = 你的面板地址 |
链接:
https://raw.githubusercontent.com/volcano-1025/cfsm-egern-widget/main/cfsm-status.js
API_BASE 只写 origin —— https://status.example.com 这样,不要带结尾斜杠,
也不要带 /admin 之类的路径。填错最直接的表现就是卡片上写「返回的不是 JSON」。
分析 标签页 → 点左上角按钮进入 小组件画廊 → 点 +:
| 字段 | 填写内容 |
|---|---|
| 名称 | 服务器状态(随便起,这是待会在主屏上要选的名字) |
| 脚本名称 | 选第 1 步创建的 cfsm-status |
保存后小组件会出现在画廊里并自动运行 —— 在画廊里就能直接看到渲染结果, 不用先加到主屏。这一步能把「脚本有问题」和「主屏没选对」两类问题分开。
- 长按主屏幕空白处,点击左上角 +
- 搜索 Egern,选择小组件尺寸(小 / 中 / 大都支持)
- 添加后长按小组件 → 编辑小组件 → 选择「服务器状态」
第 3 小步最容易漏:Egern 在主屏上只是一个壳,不选具体哪个小组件就是一片空白。
脚本和小组件两处都能填环境变量,两边会合并。所以:公共的(API_BASE、CARRIER)
填在脚本上只填一次,每个小组件各自不同的(NODE、TITLE、ROWS)填在那个小组件上。
全部可填的环境变量:
| key | 默认 | 说明 |
|---|---|---|
API_BASE |
必填 | 后端地址,只写 origin,不带路径与结尾斜杠。例 https://status.example.com |
NODE |
空 | 小尺寸显示哪台机器。三级匹配:id 全等 → 名称全等(忽略大小写)→ 名称包含。留空则取排序里的第一台 |
NODES |
空 | 中/大尺寸固定显示哪几台,逗号分隔,按写的顺序排。匹配规则同 NODE,写错的会被跳过 |
GROUP |
空 | 没写 NODES 时,只看某个分组(后台的「服务器分组」) |
TITLE |
服务器状态 |
大尺寸左上角标题 |
CARRIER |
auto |
延迟与丢包看哪条线路:ct/电信、cu/联通、cm/移动、bd。auto 在三网里取延迟最低的一条 |
LOSS_WINDOW |
hour |
丢包按哪个口径算:hour 取最近一小时的均值,now 换回「最后一次探测」的瞬时值 |
SORT |
order |
没写 NODES 时的排序。order 跟随后台的「服务器排序」;health 改成离线优先、其次 CPU 从高到低 |
BACKGROUND |
system |
背景:system 交给系统材质、glass 压一层灰色渐变、solid 不透明主题底色 |
LATENCY_STYLE |
text |
延迟数值的画法:text 数字染成延迟色;chip 延迟色当底、数字用正文色(更清楚但更花) |
ROWS |
中 5 / 大 9 | 列表最多显示几行 |
REFRESH |
1 |
期望的刷新间隔(分钟)。iOS 有刷新预算,实际间隔通常被系统拉长,写小了也不会更快 |
DEBUG |
空 | 填 1 时改渲染一棵最小的排查树(只有一个多行文本),用来分辨「取数没成功」还是「某个布局结构没渲染出来」 |
没写 NODES 时列表跟随后台的服务器排序(sort_order);后台没排过序(全是 0)就保持后端
下发的顺序。想让出问题的机器自己冒头,用 SORT = health 换成「离线优先、其次 CPU 从高到低」。
后台设为隐藏的机器一律不显示。小尺寸没写 NODE 时取的也是这个排序里的第一台。
CARRIER 点名某条线路后就只认那一条,那条没数据就显示 —,不会偷偷回退到别条 ——
写着「电信」却显示联通的数才是真的误导。小尺寸会把线路名标在延迟左边,
大尺寸标在标题栏图例的末尾。
远程脚本按 update_interval(默认 86400 秒,一天)自动重新拉取。想马上拿到新版本,
去 工具 → 脚本 里对它手动更新一次。
也可以直接写配置文件(效果完全一样)
习惯改 YAML 的话,上面两步等价于:
scriptings:
- generic:
name: cfsm-status
script_url: https://raw.githubusercontent.com/volcano-1025/cfsm-egern-widget/main/cfsm-status.js
env:
API_BASE: "https://status.example.com"
widgets:
- name: 服务器状态
script_name: cfsm-status配置里已经有 scriptings: 或 widgets: 的话,只把 - 开头的条目并进已有的那一段,
别把顶层字段名再写一遍 —— YAML 里同一个键出现两次,后面那个会把前面整段顶掉。
先看小组件画廊里那一块渲染成什么样 —— 画廊里就是真机的渲染结果,主屏上看到的一模一样。 失败原因会直接写在卡片上:
| 现象 | 原因 | 怎么办 |
|---|---|---|
| 主屏一片空白,但画廊里是好的 | 主屏上的 Egern 壳没绑定具体小组件 | 长按小组件 → 编辑小组件 → 选「服务器状态」 |
| 画廊的 + 里选不到脚本 | 第 1 步的脚本没建成,或类型没选 通用 | 回 工具 → 脚本 检查名称与类型 |
| 未配置 API_BASE | 环境变量没读到 | 检查 API_BASE 的拼写(全大写),以及是填在脚本还是这个小组件上 |
| 无法连接 xxx | 域名不通或超时 | 用手机浏览器开一下 https://你的地址/api/servers,确认能出 JSON |
| 返回的不是 JSON | API_BASE 写错了 |
只写 origin,不要带 / 结尾、不要带 /admin 之类的路径 |
| 站点未公开 | 后台关了公开访问 | 小组件不支持,见「限制」 |
| 站点已开启人机验证 | 后台开了全局 Turnstile | 小组件不支持,见「限制」 |
| 未找到节点 xxx | NODE 没匹配上 |
填后台里的机器 id,或名称的一段(不区分大小写) |
| 最后一行缺一截 | 机型比参考尺寸矮 | 把 ROWS 调小一档 |
还是定位不了,给那个小组件的环境变量加一条 DEBUG = 1:它会改渲染一棵最小的排查树
(只有一段纯文本,列出 family、后端域名、拿到几台机器,以及一小时丢包窗口拿到几格 ——
写着「窗口 0 格」就是后端版本太低或者没探测这台,丢包会回落到瞬时值)。
能出文字说明取数和渲染都通、问题在版式;还是空白说明脚本压根没跑起来,
回第 1、2 步检查。
- 只支持公开站点。 站点如果关掉了公开访问,或在后台开了全局 Turnstile 人机验证, 小组件拿不到数据(那份验证凭证只能在浏览器里解人机验证才能拿到,脚本没法绕)。 这两种情况小组件会直接把原因写在卡片上。
- 只支持单个后端。 多站部署请为每个后端各加一个 widget 条目。
- 延迟按 60 / 100 / 160 / 200 ms 分档上色,没有数据时显示
—。 线路的探测目标由后台配置,公开接口不下发,小组件也就无从显示。 - 丢包默认是最近一小时的均值,不是最后一次探测的结果。
/api/servers除了瞬时值还带一份 一小时的探测窗口(30 格、每 2 分钟一格),小组件就地取平均 —— 不多发任何请求, 也不碰历史接口。所以小组件上的丢包和面板上那个瞬时数值经常对不上:一次抖动能让瞬时值跳到 100% 再跳回 0%,一小时均值不会。想看瞬时值就把LOSS_WINDOW设成now。- 窗口是 Workers 2.8.3 Beta2 起才下发的字段。后端版本低于这个、或者这台机器窗口里 没有可用格子时,自动回落到瞬时值(不会显示成「没有数据」)。
- 没值的格子不算进分母:「这两分钟没探测到」和「这两分钟没丢包」不是一回事, 拿 0 补进去会把丢包率冲淡。
- 后端为了凑够 30 格,会把最近的一次采样复制到缺的格子上(没有距离上限),于是刚加进来 几分钟的机器窗口里也会有「一整个小时的数据」。这里照主题的做法把连续 4 格以上逐字节 完全相同的段整段丢掉 —— 真探测做不到四条线路的延迟和丢包同时一模一样。 整段都是复印件时回落到瞬时值。
- 丢包不足 1% 保留一位小数(0.4% 和「一个都没掉」不是一回事)。
配色逐值复刻主题的连续热力渐变(
lossHeatColor→heatRamp(pct, [1,3,5,10], 20)): 0% 是绿色,1% 转黄绿,5% 转金,10% 转橙,30% 以上封顶红;只有「没有样本」才是灰的。 整条线路全丢包时延迟为空、丢包 100%,这时候仍会把丢包显示出来。 - 延迟配色的深色档位逐值等于主题
tokens.css的--latency-*,浅色同色相压深一档。 主题那几档(#9fe339/#cbd83a)是画在深色卡片和色带上的黄绿,直接当文字色摆在浅色 小组件上根本读不出来。这不是自作主张:主题自己的--latency-critical就是浅深两套值 (浅#dc2626/ 深#f47067),这里只是把同一个做法延伸到另外几档。 - 进度条颜色沿用主题:蓝=CPU、紫=内存、橙=磁盘(大尺寸标题栏有图例)。
- 做不出原生小组件那种真透明。 真机验证过:Egern 自己铺了一层不透明的容器底,我们给的
颜色只能压在它上面 —— 连
BACKGROUND: "clear"(全透明)出来也还是一块浅灰,透不出壁纸。 DSL 也没有模糊原语,真正的模糊只有系统能提供。所以默认是system(什么都不铺, 交给系统材质,最干净);glass只是一层灰色渐变,换个质感而已,不是毛玻璃。 - 每一行都必须定高。 Egern 会把多出来的竖直空间平摊给没定高的子元素:小组件在 Mac /
iPad 上比 iPhone 高,一个没定高的行会独吞整块空档,把它下面的内容全挤到底部。
代价是行数超了会被裁掉而不是压缩:默认行数按 iPhone 14 Pro 那档留了余量,
如果你的机型看到最后一行缺一截,把
ROWS调小一档即可。 - 每次刷新只发一个请求
GET {API_BASE}/api/servers,不碰历史接口 —— 逐节点查历史会让后端 D1 读行翻几十倍。
npm install
npm test # 纯函数 + DSL 结构校验
npm run lint
npm run preview # 生成 preview-{small,medium,large,errors}.htmlnpm run preview 把小组件的 DSL 翻成等尺寸的 HTML,浅深色各画一份,用来在本机调版式。
它是近似预览,不是模拟器:字体度量与 WidgetKit 不同,minScale 的自动缩字也模拟不了,
只用来抓「名字被挤断、某列没对齐、某块被压成 0 宽、深色下看不清」这类结构问题。
cfsm-status.js 必须保持单文件、无依赖——Egern 是按 script_url 远程加载它的,没有打包步骤。
文件里的具名导出只给测试用,Egern 只取 export default。
test/dsl-schema.js 是 Egern DSL 的属性白名单,逐条抄自
官方文档。脚本是没有类型检查的纯 JS,
写错键名 Egern 会静默忽略、真机上只表现为「样式没生效」,这份白名单是唯一能当场抓住手滑的东西。
加新属性前先确认文档里有,再往白名单里补。