mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
🌴 Sync 2026-10-30 02:13:56
This commit is contained in:
1 parent
8d20d896c0
commit
57d68d2cec
34 files changed
+1383
-304
No files matched your search
@@ -33,9 +33,51 @@ var ICONS = {
|
||||
refresh: '<path d="M20 11a8 8 0 1 0-2.3 6.3"/><path d="M20 4v7h-7"/>',
|
||||
pulse: '<path d="M2 12h4l2.5-6 3.5 12 2.5-6H22"/>',
|
||||
chevron: '<path d="M6 9l6 6 6-6"/>',
|
||||
shield: '<path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6z"/>'
|
||||
shield: '<path d="M12 3l7 3v6c0 4-3 7-7 9-4-2-7-5-7-9V6z"/>',
|
||||
/* 运营商兜底 glyph:wan 卡映射不到品牌 logo 时用它们占位
|
||||
(与状态页同一套 24 格线稿;视图之间不共享模块,故此处自带一份) */
|
||||
tel: '<path d="M12 9v12"/><circle cx="12" cy="5" r="2"/><path d="M8.6 8.4a5 5 0 0 1 6.8 0"/><path d="M6 5.8a8.4 8.4 0 0 1 12 0"/>',
|
||||
uni: '<circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8"/><path d="M7 8l4 8"/><path d="M17 8l-4 8"/>',
|
||||
cmcc: '<rect x="7" y="3" width="10" height="18" rx="2"/><path d="M11 18h2"/>',
|
||||
cernet: '<path d="M3 9.5 12 5l9 4.5-9 4.5z"/><path d="M7 11.5V16c0 1.2 2.2 2.2 5 2.2s5-1 5-2.2v-4.5"/>',
|
||||
other: '<circle cx="12" cy="12" r="7"/><path d="M12 5v14"/>'
|
||||
};
|
||||
|
||||
/* wan 卡的 isp 源码 → glyph(与状态页 GLYPH_FOR 同源) */
|
||||
var GLYPH_FOR = {
|
||||
chinatelecom: 'tel', chinanet: 'tel', telecom: 'tel',
|
||||
unicom_cnc: 'uni', unicom: 'uni',
|
||||
cmcc: 'cmcc', mobile: 'cmcc',
|
||||
cernet: 'cernet'
|
||||
};
|
||||
|
||||
/* 品牌 logo:与状态页用的是同一组 PNG(同一路径、同一文件名)。
|
||||
wan 卡按 linecheck JSON 里的 isp 字段归属映射;映射不到就走 GLYPH_FOR/占位。 */
|
||||
var BRAND_LOGO = {
|
||||
chinatelecom: 'logo-chinatelecom.png',
|
||||
chinanet: 'logo-chinatelecom.png',
|
||||
telecom: 'logo-chinatelecom.png',
|
||||
unicom_cnc: 'logo-unicom.png',
|
||||
unicom: 'logo-unicom.png',
|
||||
cmcc: 'logo-mobile.png',
|
||||
mobile: 'logo-mobile.png'
|
||||
};
|
||||
|
||||
var HEAD_ICO = 44;
|
||||
|
||||
function brandLogo(src, size) {
|
||||
var file = BRAND_LOGO[src];
|
||||
if (!file)
|
||||
return null;
|
||||
var img = document.createElement('img');
|
||||
img.src = L.resource('isp-split/logos/' + file);
|
||||
img.alt = src;
|
||||
img.width = size || HEAD_ICO;
|
||||
img.height = size || HEAD_ICO;
|
||||
img.className = 'isp-brand-logo';
|
||||
return img;
|
||||
}
|
||||
|
||||
function svgIcon(name, size) {
|
||||
var span = document.createElement('span');
|
||||
span.className = 'isp-ico';
|
||||
@@ -68,8 +110,12 @@ function fmtAge(sec) {
|
||||
}
|
||||
|
||||
function fmtMs(v) {
|
||||
if (v === null || v === undefined || v === '' || v === 0)
|
||||
/* F-24b:null = 未测/失败,显示“—”;"<1" 与历史 0 都显示 "<1ms"。
|
||||
0 不再作为“没测到”的哨兵(亚毫秒 DNS 曾经被四舍五入成 0)。 */
|
||||
if (v === null || v === undefined || v === '')
|
||||
return '—';
|
||||
if (v === 0 || v === '<1')
|
||||
return '<1ms';
|
||||
return v + 'ms';
|
||||
}
|
||||
|
||||
@@ -427,6 +473,14 @@ return view.extend({
|
||||
var lat = w.latency || {};
|
||||
var geo = w.geo || {};
|
||||
var http = w.http || {};
|
||||
/* F-23:exit_probe 是 shell 侧逐 URL 记录的探测明细。有明细但
|
||||
exit_ip 为空 => 回显源不可达/返回格式不符;连明细都没有 =>
|
||||
没有发起探测(curl 缺失/未配置),文案保持“可能未真正出网”。
|
||||
所有 JSON 字段只作为 E() 的文本子项,绝不拼进 HTML 解析路径。 */
|
||||
var ep = Array.isArray(w.exit_probe) ? w.exit_probe : [];
|
||||
var exitText = w.exit_ip || (ep.length
|
||||
? _('回显源不可达(建议更换 LINE_CHECK_ECHO_URLS)')
|
||||
: _('未取到(可能未真正出网)'));
|
||||
var detail = E('div', { 'class': 'lc-detail', 'hidden': '' });
|
||||
|
||||
var toggle = E('button', {
|
||||
@@ -457,6 +511,12 @@ return view.extend({
|
||||
sc.grade === 'C' ? 'var(--isp-warn)' : 'var(--isp-bad)')
|
||||
}, [
|
||||
E('div', { 'class': 'lc-head' }, [
|
||||
/* D2:与状态页同一套卡头——44px 左置。
|
||||
wan 卡按 isp 归属取品牌 logo;自定义 ISP / 未识别(isp 为空)
|
||||
走 GLYPH_FOR 的线稿 glyph,同一 44px 盒子,卡头高度不变。 */
|
||||
E('span', { 'class': 'lc-head-ico' }, [
|
||||
brandLogo(w.isp) || svgIcon(GLYPH_FOR[w.isp] || 'pulse', HEAD_ICO)
|
||||
]),
|
||||
E('div', { 'class': 'lc-title' }, [
|
||||
E('span', { 'class': 'lc-name' }, [ w.iface || '?' ]),
|
||||
E('span', { 'class': 'lc-dev' }, [ w.device || '' ]),
|
||||
@@ -477,7 +537,7 @@ return view.extend({
|
||||
E('span', { 'class': 'lc-tag is-muted' }, [ classText(w.ip_class) ])
|
||||
]),
|
||||
row(_('出口 IP'), [
|
||||
E('span', {}, [ w.exit_ip || _('未取到(可能未真正出网)') ]),
|
||||
E('span', {}, [ exitText ]),
|
||||
multi
|
||||
]),
|
||||
row(_('运营商'), [ w.isp_label || _('未知') ]),
|
||||
|
||||
@@ -35,7 +35,13 @@ var ICONS = {
|
||||
uni: '<circle cx="6" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="12" cy="18" r="2"/><path d="M8 6h8"/><path d="M7 8l4 8"/><path d="M17 8l-4 8"/>',
|
||||
cmcc: '<rect x="7" y="3" width="10" height="18" rx="2"/><path d="M11 18h2"/>',
|
||||
cernet: '<path d="M3 9.5 12 5l9 4.5-9 4.5z"/><path d="M7 11.5V16c0 1.2 2.2 2.2 5 2.2s5-1 5-2.2v-4.5"/>',
|
||||
other: '<circle cx="12" cy="12" r="7"/><path d="M12 5v14"/>'
|
||||
other: '<circle cx="12" cy="12" r="7"/><path d="M12 5v14"/>',
|
||||
/* 兜底流量卡的身份 glyph:地球 + 经纬线("未归属任何运营商"的那部分流量)。
|
||||
与上面一族同为 24 格 stroke 线稿(stroke-width 1.8、round 收口),
|
||||
44px 下线条不会糊;颜色走 currentColor,深浅主题都不用另做一套。 */
|
||||
net: '<circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17"/>' +
|
||||
'<path d="M12 3.5c2.4 2.4 3.8 5.4 3.8 8.5s-1.4 6.1-3.8 8.5"/>' +
|
||||
'<path d="M12 3.5C9.6 5.9 8.2 8.9 8.2 12s1.4 6.1 3.8 8.5"/>'
|
||||
};
|
||||
|
||||
var GLYPH_FOR = {
|
||||
@@ -45,17 +51,22 @@ var GLYPH_FOR = {
|
||||
cernet: 'cernet'
|
||||
};
|
||||
|
||||
/* 品牌 logo(运营商官方标志,fill 型多色 SVG,静态文件按请求加载) */
|
||||
/* 品牌 logo(运营商官方风格标志,192×192 透明底 PNG,静态文件按请求加载)。
|
||||
0.3.1 起换图不换名:文件名仍是 logo-<运营商>,只把扩展名从 .svg 改成 .png。
|
||||
PNG 是位图,深浅两个主题共用一份即可(透明底天然跟随背景)。 */
|
||||
var BRAND_LOGO = {
|
||||
chinatelecom: 'logo-chinatelecom.svg',
|
||||
chinanet: 'logo-chinatelecom.svg',
|
||||
telecom: 'logo-chinatelecom.svg',
|
||||
unicom_cnc: 'logo-unicom.svg',
|
||||
unicom: 'logo-unicom.svg',
|
||||
cmcc: 'logo-mobile.svg',
|
||||
mobile: 'logo-mobile.svg'
|
||||
chinatelecom: 'logo-chinatelecom.png',
|
||||
chinanet: 'logo-chinatelecom.png',
|
||||
telecom: 'logo-chinatelecom.png',
|
||||
unicom_cnc: 'logo-unicom.png',
|
||||
unicom: 'logo-unicom.png',
|
||||
cmcc: 'logo-mobile.png',
|
||||
mobile: 'logo-mobile.png'
|
||||
};
|
||||
|
||||
/* 卡头图标统一 44px:logo 与「无 logo 的 glyph 占位」同尺寸,视觉同构 */
|
||||
var HEAD_ICO = 44;
|
||||
|
||||
function brandLogo(src, size) {
|
||||
var file = BRAND_LOGO[src];
|
||||
if (!file)
|
||||
@@ -63,8 +74,8 @@ function brandLogo(src, size) {
|
||||
var img = document.createElement('img');
|
||||
img.src = L.resource('isp-split/logos/' + file);
|
||||
img.alt = src;
|
||||
img.width = size || 20;
|
||||
img.height = size || 20;
|
||||
img.width = size || HEAD_ICO;
|
||||
img.height = size || HEAD_ICO;
|
||||
img.className = 'isp-brand-logo';
|
||||
return img;
|
||||
}
|
||||
@@ -360,6 +371,14 @@ return view.extend({
|
||||
return false;
|
||||
if (/^\s*#/.test(String(r.set || '')) || /^\s*#/.test(String(r.src || '')))
|
||||
return false;
|
||||
/* D1-3:教育网(cernet)退出状态页,纯 UI 退场。
|
||||
后端数据行照旧保留(status --json / 诊断 / 导出都不受影响),
|
||||
只是这一版不把它算进运营商网格:cernet 用户量小,指标常年为空,
|
||||
混在电信/联通/移动里只会稀释「一眼看三家」的信息密度。
|
||||
set 名与 src 一起判:ISP_TABLE 里 cernet 的集合名可以改,
|
||||
src 改不了。 */
|
||||
if (r.src === 'cernet' || r.set === 'isp_cernet')
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -369,7 +388,6 @@ return view.extend({
|
||||
? _('读取状态失败:') + this.statusError
|
||||
: _('没有启用的运营商。检查 /etc/isp-split.conf 里的 ISP_TABLE。')
|
||||
]));
|
||||
return;
|
||||
}
|
||||
|
||||
var maxPackets = 0;
|
||||
@@ -401,8 +419,13 @@ return view.extend({
|
||||
'style': '--isp-accent: ' + accent
|
||||
}, [
|
||||
E('div', { 'class': 'isp-card-head' }, [
|
||||
E('span', { 'class': 'isp-op-name' }, [ r.label || r.src ]),
|
||||
E('span', { 'class': 'isp-op-ico' }, [ brandLogo(r.src, 20) || svgIcon(GLYPH_FOR[r.src] || 'other', 20) ])
|
||||
/* 方案 B:logo 44px 左置 + 运营商名。
|
||||
没有品牌 logo 的来源(自定义源 / other)走同一尺寸的 glyph 占位,
|
||||
两张卡并排时卡头高度与基线一致,不会一张高一卡矮。 */
|
||||
E('span', { 'class': 'isp-op-ico' }, [
|
||||
brandLogo(r.src) || svgIcon(GLYPH_FOR[r.src] || 'other', HEAD_ICO)
|
||||
]),
|
||||
E('span', { 'class': 'isp-op-name' }, [ r.label || r.src ])
|
||||
]),
|
||||
E('div', {}, [
|
||||
E('span', { 'class': 'isp-big' }, [ r.exists ? fmtNum(packets) : '—' ]),
|
||||
@@ -430,6 +453,22 @@ return view.extend({
|
||||
}, [ '—' ])
|
||||
]));
|
||||
});
|
||||
|
||||
/* D1-4:兜底流量并入同一张运营商网格,成为「第 4 张卡」。
|
||||
桌面四列(.isp-cards 是 repeat(4)):三家运营商 + 兜底正好一行四格;
|
||||
ISP_TABLE 多开运营商时按四列继续换行,兜底始终排在最后,不会被挤到
|
||||
另一行只剩一半宽。卡头与运营商卡同构:44px glyph + 名称。
|
||||
内容由 paintFallback() 写进 #isp-fallback(paintOps 之后调用)。 */
|
||||
box.appendChild(E('article', {
|
||||
'class': 'isp-card isp-card-op isp-card-fb',
|
||||
'style': '--isp-accent: var(--isp-accent-other)'
|
||||
}, [
|
||||
E('div', { 'class': 'isp-card-head' }, [
|
||||
E('span', { 'class': 'isp-op-ico' }, [ svgIcon('net', HEAD_ICO) ]),
|
||||
E('span', { 'class': 'isp-op-name' }, [ _('兜底流量') ])
|
||||
]),
|
||||
E('div', { 'id': 'isp-fallback' })
|
||||
]));
|
||||
},
|
||||
|
||||
/* ---------------- 双线健康 ---------------- */
|
||||
@@ -485,7 +524,11 @@ return view.extend({
|
||||
box.appendChild(list);
|
||||
},
|
||||
|
||||
/* ---------------- 兜底流量 ---------------- */
|
||||
/* ---------------- 兜底流量(第 4 张运营商卡的主体) ----------------
|
||||
口径与 0.3.0 完全一致:未命中任何运营商集合的连接数(首包)与流量。
|
||||
卡头在 paintOps() 里画(44px glyph + 名称),这里只负责主体,
|
||||
字号/间距与运营商卡的 isp-big / isp-op-sub 同一套类名,因此
|
||||
两张卡的数字基线和单位位置自然对齐。 */
|
||||
|
||||
paintFallback: function() {
|
||||
var box = document.getElementById('isp-fallback');
|
||||
@@ -714,18 +757,15 @@ return view.extend({
|
||||
E('div', { 'id': 'isp-load-error', 'class': 'isp-err', 'style': 'display:none' }),
|
||||
E('div', { 'id': 'isp-cards', 'class': 'isp-cards' }),
|
||||
|
||||
E('div', { 'class': 'isp-grid-2' }, [
|
||||
/* 兜底流量不再是独立大卡:它已经并入顶部运营商网格的第 4 格
|
||||
(见 paintOps)。这里腾出来的位置让双线健康 / 数据源健康度 /
|
||||
数据时间排成一行三格(isp-grid-3,断点 1100→2 列、820→1 列),
|
||||
页面从「2+2+2」变成「4 张运营商 + 3 张明细」,视线更顺。 */
|
||||
E('div', { 'class': 'isp-grid-3' }, [
|
||||
E('section', { 'class': 'isp-card' }, [
|
||||
E('h3', {}, [ _('双线健康') ]),
|
||||
E('div', { 'id': 'isp-lines' })
|
||||
]),
|
||||
E('section', { 'class': 'isp-card' }, [
|
||||
E('h3', {}, [ _('兜底流量') ]),
|
||||
E('div', { 'id': 'isp-fallback' })
|
||||
])
|
||||
]),
|
||||
|
||||
E('div', { 'class': 'isp-grid-2' }, [
|
||||
E('section', { 'class': 'isp-card' }, [
|
||||
E('h3', {}, [ _('数据源健康度') ]),
|
||||
E('div', { 'id': 'isp-sources' })
|
||||
|
||||
Reference in new issue
Block a user