💐 Sync 2025-11-17 00:10:18

This commit is contained in:
actions-user
2025-11-17 00:10:18 +08:00
parent e8a77828f8
commit e236e70350
63 changed files with 7743 additions and 4888 deletions

View File

@@ -5,331 +5,33 @@
'require rpc';
'require poll';
const translations = {
'zh-cn': {
'Bandix 连接监控': 'Bandix 连接监控',
'正在加载数据...': '正在加载数据...',
'无法获取数据': '无法获取数据',
'连接监控': '连接监控',
'设备连接统计': '设备连接统计',
'全局连接统计': '全局连接统计',
'设备': '设备',
'IP地址': 'IP地址',
'MAC地址': 'MAC地址',
'活跃TCP': '活跃TCP',
'活跃UDP': '活跃UDP',
'已关闭TCP': '已关闭TCP',
'总连接数': '总连接数',
'最后更新': '最后更新',
'总连接数统计': '总连接数统计',
'TCP连接数': 'TCP连接数',
'UDP连接数': 'UDP连接数',
'已建立TCP': '已建立TCP',
'TIME_WAIT TCP': 'TIME_WAIT TCP',
'CLOSE_WAIT TCP': 'CLOSE_WAIT TCP',
'设备总数': '设备总数',
'连接监控未启用': '连接监控未启用',
'请在设置中启用连接监控功能': '请在设置中启用连接监控功能',
'前往设置': '前往设置',
'无数据': '无数据',
'未知设备': '未知设备',
'在线设备': '在线设备',
'从未上线': '从未上线',
'刚刚': '刚刚',
'分钟前': '分钟前',
'小时前': '小时前',
'天前': '天前',
'个月前': '个月前',
'年前': '年前',
'最后上线': '最后上线',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': '列表只显示局域网设备连接,数据可能和总连接数不一致。',
'TCP 状态详情': 'TCP 状态详情'
},
'zh-tw': {
'Bandix 连接监控': 'Bandix 連接監控',
'正在加载数据...': '正在載入資料...',
'无法获取数据': '無法獲取資料',
'连接监控': '連接監控',
'设备连接统计': '設備連接統計',
'全局连接统计': '全局連接統計',
'设备': '設備',
'IP地址': 'IP地址',
'MAC地址': 'MAC地址',
'活跃TCP': '活躍TCP',
'活跃UDP': '活躍UDP',
'已关闭TCP': '已關閉TCP',
'总连接数': '總連接數',
'最后更新': '最後更新',
'总连接数统计': '總連接數統計',
'TCP连接数': 'TCP連接數',
'UDP连接数': 'UDP連接數',
'已建立TCP': '已建立TCP',
'TIME_WAIT TCP': 'TIME_WAIT TCP',
'CLOSE_WAIT TCP': 'CLOSE_WAIT TCP',
'设备总数': '設備總數',
'连接监控未启用': '連接監控未啟用',
'请在设置中启用连接监控功能': '請在設置中啟用連接監控功能',
'前往设置': '前往設置',
'无数据': '無數據',
'未知设备': '未知設備',
'在线设备': '在線設備',
'从未上线': '從未上線',
'刚刚': '剛剛',
'分钟前': '分鐘前',
'小时前': '小時前',
'天前': '天前',
'个月前': '個月前',
'年前': '年前',
'最后上线': '最後上線',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': '列表只顯示局域網設備連接,數據可能和總連接數不一致。',
'TCP 状态详情': 'TCP 狀態詳情'
},
'en': {
'Bandix 连接监控': 'Bandix Connection Monitor',
'正在加载数据...': 'Loading data...',
'无法获取数据': 'Unable to fetch data',
'连接监控': 'Connection Monitor',
'设备连接统计': 'Device Connection Statistics',
'全局连接统计': 'Global Connection Statistics',
'设备': 'Device',
'IP地址': 'IP Address',
'MAC地址': 'MAC Address',
'活跃TCP': 'Active TCP',
'活跃UDP': 'Active UDP',
'已关闭TCP': 'Closed TCP',
'总连接数': 'Total Connections',
'最后更新': 'Last Updated',
'总连接数统计': 'Total Connections',
'TCP连接数': 'TCP Connections',
'UDP连接数': 'UDP Connections',
'已建立TCP': 'Established TCP',
'TIME_WAIT TCP': 'TIME_WAIT TCP',
'CLOSE_WAIT TCP': 'CLOSE_WAIT TCP',
'设备总数': 'Total Devices',
'连接监控未启用': 'Connection Monitor Disabled',
'请在设置中启用连接监控功能': 'Please enable connection monitoring in settings',
'前往设置': 'Go to Settings',
'无数据': 'No Data',
'未知设备': 'Unknown Device',
'在线设备': 'Online Devices',
'从未上线': 'Never Online',
'刚刚': 'Just now',
'分钟前': 'minutes ago',
'小时前': 'hours ago',
'天前': 'days ago',
'个月前': 'months ago',
'年前': 'years ago',
'最后上线': 'Last seen',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': 'List only shows LAN device connections, data may differ from total connections.',
'TCP 状态详情': 'TCP Status Details'
},
'fr': {
'Bandix 连接监控': 'Surveillance de Connexion Bandix',
'正在加载数据...': 'Chargement des données...',
'无法获取数据': 'Impossible de récupérer les données',
'连接监控': 'Surveillance des Connexions',
'设备连接统计': 'Statistiques de Connexion des Appareils',
'全局连接统计': 'Statistiques de Connexion Globales',
'设备': 'Appareil',
'IP地址': 'Adresse IP',
'MAC地址': 'Adresse MAC',
'活跃TCP': 'TCP Actif',
'活跃UDP': 'UDP Actif',
'已关闭TCP': 'TCP Fermé',
'总连接数': 'Total des Connexions',
'最后更新': 'Dernière Mise à Jour',
'总连接数统计': 'Total des Connexions',
'TCP连接数': 'Connexions TCP',
'UDP连接数': 'Connexions UDP',
'已建立TCP': 'TCP Établi',
'TIME_WAIT TCP': 'TCP TIME_WAIT',
'CLOSE_WAIT TCP': 'TCP CLOSE_WAIT',
'设备总数': 'Total des Appareils',
'连接监控未启用': 'Surveillance des Connexions Désactivée',
'请在设置中启用连接监控功能': 'Veuillez activer la surveillance des connexions dans les paramètres',
'前往设置': 'Aller aux Paramètres',
'无数据': 'Aucune Donnée',
'未知设备': 'Appareil Inconnu',
'在线设备': 'Appareils En Ligne',
'从未上线': 'Jamais En Ligne',
'刚刚': 'À l\'instant',
'分钟前': 'il y a minutes',
'小时前': 'il y a heures',
'天前': 'il y a jours',
'个月前': 'il y a mois',
'年前': 'il y a années',
'最后上线': 'Dernier Vue',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': 'La liste ne montre que les connexions des appareils LAN, les données peuvent différer du total des connexions.',
'TCP 状态详情': 'Détails du Statut TCP'
},
'ja': {
'Bandix 连接监控': 'Bandix 接続監視',
'正在加载数据...': 'データを読み込み中...',
'无法获取数据': 'データを取得できません',
'连接监控': '接続監視',
'设备连接统计': 'デバイス接続統計',
'全局连接统计': 'グローバル接続統計',
'设备': 'デバイス',
'IP地址': 'IPアドレス',
'MAC地址': 'MACアドレス',
'活跃TCP': 'アクティブTCP',
'活跃UDP': 'アクティブUDP',
'已关闭TCP': 'クローズドTCP',
'总连接数': '総接続数',
'最后更新': '最終更新',
'总连接数统计': '総接続数',
'TCP连接数': 'TCP接続数',
'UDP连接数': 'UDP接続数',
'已建立TCP': 'TCP確立済',
'TIME_WAIT TCP': 'TCP TIME_WAIT',
'CLOSE_WAIT TCP': 'TCP CLOSE_WAIT',
'设备总数': '総デバイス数',
'连接监控未启用': '接続監視が無効',
'请在设置中启用连接监控功能': '設定で接続監視機能を有効にしてください',
'前往设置': '設定に移動',
'无数据': 'データなし',
'未知设备': '不明なデバイス',
'在线设备': 'オンラインデバイス',
'从未上线': '未接続',
'刚刚': 'たった今',
'分钟前': '分前',
'小时前': '時間前',
'天前': '日前',
'个月前': 'ヶ月前',
'年前': '年前',
'最后上线': '最後の接続',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': 'リストはLANデバイスの接続のみを表示し、データは総接続数と異なる場合があります。',
'TCP 状态详情': 'TCP状態詳細'
},
'ru': {
'Bandix 连接监控': 'Мониторинг Соединений Bandix',
'正在加载数据...': 'Загрузка данных...',
'无法获取数据': 'Не удалось получить данные',
'连接监控': 'Мониторинг Соединений',
'设备连接统计': 'Статистика Соединений Устройств',
'全局连接统计': 'Глобальная Статистика Соединений',
'设备': 'Устройство',
'IP地址': 'IP-адрес',
'MAC地址': 'MAC-адрес',
'活跃TCP': 'Активные TCP',
'活跃UDP': 'Активные UDP',
'已关闭TCP': 'Закрытые TCP',
'总连接数': 'Всего Соединений',
'最后更新': 'Последнее Обновление',
'总连接数统计': 'Всего Соединений',
'TCP连接数': 'TCP Соединения',
'UDP连接数': 'UDP Соединения',
'已建立TCP': 'Установленные TCP',
'TIME_WAIT TCP': 'TCP TIME_WAIT',
'CLOSE_WAIT TCP': 'TCP CLOSE_WAIT',
'设备总数': 'Всего Устройств',
'连接监控未启用': 'Мониторинг Соединений Отключен',
'请在设置中启用连接监控功能': 'Пожалуйста, включите мониторинг соединений в настройках',
'前往设置': 'Перейти к Настройкам',
'无数据': 'Нет Данных',
'未知设备': 'Неизвестное Устройство',
'在线设备': 'Устройства Онлайн',
'从未上线': 'Никогда Не Было Онлайн',
'刚刚': 'Только что',
'分钟前': 'минут назад',
'小时前': 'часов назад',
'天前': 'дней назад',
'个月前': 'месяцев назад',
'年前': 'лет назад',
'最后上线': 'Последний раз видели',
'列表只显示局域网设备连接,数据可能和总连接数不一致。': 'Список показывает только соединения LAN-устройств, данные могут отличаться от общего количества соединений.',
'TCP 状态详情': 'Детали Статуса TCP'
}
};
function getTranslation(key, language) {
return translations[language]?.[key] || key;
}
// 获取系统语言
function getSystemLanguage() {
var luciLang = uci.get('luci', 'main', 'lang');
if (luciLang && translations[luciLang]) {
return luciLang;
}
var systemLang = document.documentElement.lang || 'en';
if (translations[systemLang]) {
return systemLang;
}
return 'en';
}
// 检查是否为暗黑模式
function isDarkMode() {
// 首先检查用户设置的主题
var userTheme = uci.get('bandix', 'general', 'theme');
if (userTheme) {
if (userTheme === 'dark') {
return true;
} else if (userTheme === 'light') {
return false;
}
// 如果是 'auto',继续检查系统主题
}
// 获取 LuCI 主题设置
var mediaUrlBase = uci.get('luci', 'main', 'mediaurlbase');
if (mediaUrlBase && mediaUrlBase.toLowerCase().includes('dark')) {
return true;
}
// 如果是 argon 主题,检查 argon 配置
if (mediaUrlBase && mediaUrlBase.toLowerCase().includes('argon')) {
var argonMode = uci.get('argon', '@global[0]', 'mode');
if (argonMode) {
if (argonMode.toLowerCase() === 'dark') {
return true;
} else if (argonMode.toLowerCase() === 'light') {
return false;
}
// 如果是 'normal' 或 'auto',使用浏览器检测系统颜色偏好
if (argonMode.toLowerCase() === 'normal' || argonMode.toLowerCase() === 'auto') {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return true;
}
return false;
}
}
}
// 默认情况下也使用浏览器检测系统颜色偏好
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return true;
}
return false;
}
// 暗色模式检测已改为使用 CSS 媒体查询 @media (prefers-color-scheme: dark)
// 格式化时间戳
function formatTimestamp(timestamp) {
if (!timestamp) return getTranslation('从未上线', getSystemLanguage());
if (!timestamp) return _('Never Online');
var now = Math.floor(Date.now() / 1000);
var diff = now - timestamp;
var language = getSystemLanguage();
if (diff < 60) {
return getTranslation('刚刚', language);
return _('Just now');
} else if (diff < 3600) {
var minutes = Math.floor(diff / 60);
return minutes + ' ' + getTranslation('分钟前', language);
return minutes + ' ' + _('minutes ago');
} else if (diff < 86400) {
var hours = Math.floor(diff / 3600);
return hours + ' ' + getTranslation('小时前', language);
return hours + ' ' + _('hours ago');
} else if (diff < 2592000) {
var days = Math.floor(diff / 86400);
return days + ' ' + getTranslation('天前', language);
return days + ' ' + _('days ago');
} else if (diff < 31536000) {
var months = Math.floor(diff / 2592000);
return months + ' ' + getTranslation('个月前', language);
return months + ' ' + _('months ago');
} else {
var years = Math.floor(diff / 31536000);
return years + ' ' + getTranslation('年前', language);
return years + ' ' + _('years ago');
}
}
@@ -338,7 +40,7 @@ function formatDeviceName(device) {
if (device.hostname && device.hostname !== '') {
return device.hostname;
}
return device.ip_address || device.mac_address || getTranslation('未知设备', getSystemLanguage());
return device.ip_address || device.mac_address || _('Unknown Device');
}
// RPC调用
@@ -360,63 +62,42 @@ return view.extend({
},
render: function (data) {
var language = uci.get('bandix', 'general', 'language');
if (!language || language === 'auto') {
language = getSystemLanguage();
}
var darkMode = isDarkMode();
var connectionEnabled = uci.get('bandix', 'connections', 'enabled') === '1';
// 创建样式
var style = E('style', {}, `
.bandix-connection-container {
margin: 0;
padding: 16px;
background-color: ${darkMode ? '#1a1a1a' : '#f8fafc'};
min-height: calc(100vh - 100px);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
color: ${darkMode ? '#e2e8f0' : '#1f2937'};
border-radius: 8px;
}
.bandix-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.bandix-title {
font-size: 1.5rem;
font-weight: 600;
color: ${darkMode ? '#f1f5f9' : '#1f2937'};
margin: 0;
}
.bandix-badge {
background-color: ${darkMode ? '#2a2a2a' : '#f8fafc'};
border: 1px solid ${darkMode ? '#444444' : '#cbd5e1'};
border-radius: 4px;
padding: 4px 10px;
font-size: 0.875rem;
color: ${darkMode ? '#d0d0d0' : '#475569'};
}
.bandix-alert {
background-color: ${darkMode ? '#2a2a2a' : '#eff6ff'};
border-left: 3px solid ${darkMode ? '#3b82f6' : '#2563eb'};
border-radius: 4px;
padding: 10px 12px;
margin-bottom: 16px;
display: flex;
align-items: center;
gap: 10px;
color: ${darkMode ? '#d0d0d0' : '#1e293b'};
font-size: 0.875rem;
}
.bandix-alert-icon {
color: ${darkMode ? '#60a5fa' : '#2563eb'};
font-size: 0.875rem;
font-weight: 700;
width: 18px;
@@ -424,72 +105,62 @@ return view.extend({
display: flex;
align-items: center;
justify-content: center;
border: 2px solid currentColor;
border-radius: 50%;
flex-shrink: 0;
}
.bandix-card {
background-color: ${darkMode ? '#2a2a2a' : 'white'};
border-radius: 8px;
border: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
box-shadow: 0 2px 8px rgba(0, 0, 0, ${darkMode ? '0.3' : '0.08'});
margin-bottom: 24px;
overflow: hidden;
}
.bandix-card-header {
padding: 16px;
border-bottom: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
background-color: ${darkMode ? '#2a2a2a' : '#f8fafc'};
}
.bandix-card-title {
font-size: 1.125rem;
font-weight: 600;
color: ${darkMode ? '#f1f5f9' : '#1f2937'};
margin: 0;
display: flex;
align-items: center;
gap: 8px;
}
.bandix-card-body {
padding: 0;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
margin-bottom: 24px;
margin-top: 0;
}
.stats-card {
background-color: ${darkMode ? '#2a2a2a' : 'white'};
border-radius: 8px;
padding: 20px;
border: 1px solid ${darkMode ? '#444444' : '#e2e8f0'};
box-shadow: 0 2px 8px rgba(0, 0, 0, ${darkMode ? '0.3' : '0.08'});
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
.bandix-connection-container > .cbi-section:first-of-type {
margin-top: 0;
}
.bandix-connection-container > .cbi-section:last-of-type {
margin-bottom: 0;
}
.stats-card-title {
font-size: 0.875rem;
font-weight: 600;
color: ${darkMode ? '#94a3b8' : '#64748b'};
opacity: 0.7;
margin: 0 0 12px 0;
text-transform: uppercase;
letter-spacing: 0.025em;
}
.stats-grid .cbi-section {
padding: 16px;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
transition: box-shadow 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}
.stats-grid .cbi-section:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
transform: translateY(-2px);
}
@media (prefers-color-scheme: dark) {
.stats-grid .cbi-section {
border-color: rgba(255, 255, 255, 0.15);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.stats-grid .cbi-section:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
}
}
.stats-card-main-value {
font-size: 2.25rem;
font-weight: 700;
color: ${darkMode ? '#f1f5f9' : '#1f2937'};
margin: 0 0 8px 0;
line-height: 1;
}
@@ -510,28 +181,23 @@ return view.extend({
}
.stats-detail-label {
color: ${darkMode ? '#9ca3af' : '#6b7280'};
opacity: 0.7;
font-weight: 500;
}
.stats-detail-value {
font-weight: 600;
color: ${darkMode ? '#e2e8f0' : '#374151'};
}
.bandix-table {
width: 100%;
border-collapse: collapse;
background-color: transparent;
table-layout: fixed;
}
.bandix-table th {
background-color: ${darkMode ? '#2a2a2a' : '#f8fafc'};
padding: 12px 16px;
text-align: left;
font-weight: 600;
color: ${darkMode ? '#d0d0d0' : '#475569'};
border: none;
font-size: 0.875rem;
white-space: nowrap;
@@ -545,11 +211,9 @@ return view.extend({
.bandix-table td {
padding: 12px 16px;
border-bottom: 1px solid ${darkMode ? '#333333' : '#f1f5f9'};
vertical-align: middle;
word-break: break-word;
overflow-wrap: break-word;
color: ${darkMode ? '#d0d0d0' : '#334155'};
}
@@ -581,7 +245,6 @@ return view.extend({
.device-name {
font-weight: 600;
color: ${darkMode ? '#f1f5f9' : '#1f2937'};
display: flex;
align-items: center;
gap: 8px;
@@ -589,12 +252,12 @@ return view.extend({
}
.device-ip {
color: ${darkMode ? '#94a3b8' : '#6b7280'};
opacity: 0.7;
font-size: 0.875rem;
}
.device-mac {
color: ${darkMode ? '#64748b' : '#9ca3af'};
opacity: 0.6;
font-size: 0.75rem;
}
@@ -637,43 +300,18 @@ return view.extend({
.tcp-status-value {
font-weight: 600;
color: ${darkMode ? '#e2e8f0' : '#374151'};
}
.loading-state {
text-align: center;
padding: 40px;
color: ${darkMode ? '#94a3b8' : '#6b7280'};
opacity: 0.7;
font-style: italic;
}
.error-state {
text-align: center;
padding: 40px;
color: ${darkMode ? '#f87171' : '#ef4444'};
}
.btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
border-radius: 4px;
font-size: 0.875rem;
font-weight: 500;
text-decoration: none;
border: none;
cursor: pointer;
transition: all 0.15s ease;
}
.btn-primary {
background-color: #3b82f6;
color: white;
}
.btn-primary:hover {
background-color: #2563eb;
}
`);
document.head.appendChild(style);
@@ -682,28 +320,27 @@ return view.extend({
// 页面标题
var header = E('div', { 'class': 'bandix-header' }, [
E('h1', { 'class': 'bandix-title' }, getTranslation('Bandix 连接监控', language))
E('h1', { 'class': 'bandix-title' }, _('Bandix Connection Monitor'))
]);
container.appendChild(header);
// 检查连接监控是否启用
if (!connectionEnabled) {
var alertDiv = E('div', { 'class': 'bandix-alert' }, [
E('span', { 'class': 'bandix-alert-icon' }, '!'),
E('div', {}, [
E('strong', {}, getTranslation('连接监控未启用', language)),
E('strong', {}, _('Connection Monitor Disabled')),
E('p', { 'style': 'margin: 4px 0 0 0;' },
getTranslation('请在设置中启用连接监控功能', language))
_('Please enable connection monitoring in settings'))
])
]);
container.appendChild(alertDiv);
var settingsCard = E('div', { 'class': 'bandix-card' }, [
E('div', { 'class': 'bandix-card-body', 'style': 'text-align: center;' }, [
var settingsCard = E('div', { 'class': 'cbi-section' }, [
E('div', { 'style': 'text-align: center; padding: 16px;' }, [
E('a', {
'href': '/cgi-bin/luci/admin/network/bandix/settings',
'class': 'btn btn-primary'
}, getTranslation('前往设置', language))
'class': 'cbi-button cbi-button-positive'
}, _('Go to Settings'))
])
]);
container.appendChild(settingsCard);
@@ -712,19 +349,18 @@ return view.extend({
// 添加提示信息
var infoAlert = E('div', { 'class': 'bandix-alert' }, [
E('span', { 'class': 'bandix-alert-icon' }, '!'),
E('span', {}, getTranslation('列表只显示局域网设备连接,数据可能和总连接数不一致。', language))
E('span', {}, _('List only shows LAN device connections, data may differ from total connections.'))
]);
container.appendChild(infoAlert);
// 全局统计卡片
var statsGrid = E('div', { 'class': 'stats-grid' }, [
E('div', { 'class': 'stats-card' }, [
E('div', { 'class': 'stats-card-title' }, getTranslation('总连接数统计', language)),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'stats-card-title' }, _('Total Connections')),
E('div', { 'class': 'stats-card-main-value', 'id': 'total-connections' }, '-')
]),
E('div', { 'class': 'stats-card' }, [
E('div', { 'class': 'stats-card-title' }, getTranslation('TCP连接数', language)),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'stats-card-title' }, _('TCP Connections')),
E('div', { 'class': 'stats-card-main-value', 'id': 'tcp-connections' }, '-'),
E('div', { 'class': 'stats-card-details' }, [
E('div', { 'class': 'stats-detail-row' }, [
@@ -741,25 +377,26 @@ return view.extend({
])
])
]),
E('div', { 'class': 'stats-card' }, [
E('div', { 'class': 'stats-card-title' }, getTranslation('UDP连接数', language)),
E('div', { 'class': 'cbi-section' }, [
E('div', { 'class': 'stats-card-title' }, _('UDP Connections')),
E('div', { 'class': 'stats-card-main-value', 'id': 'udp-connections' }, '-')
])
]);
container.appendChild(statsGrid);
// 设备连接统计表格
var deviceCard = E('div', { 'class': 'bandix-card' }, [
E('div', { 'class': 'bandix-card-body' }, [
var deviceCard = E('div', { 'class': 'cbi-section' }, [
E('h3', {}, _('Device Connection Statistics')),
E('div', {}, [
E('div', { 'id': 'device-table-container' }, [
E('table', { 'class': 'bandix-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', {}, getTranslation('设备', language)),
E('th', {}, _('Device')),
E('th', {}, 'TCP'),
E('th', {}, 'UDP'),
E('th', {}, getTranslation('TCP 状态详情', language)),
E('th', {}, getTranslation('总连接数', language))
E('th', {}, _('TCP Status Details')),
E('th', {}, _('Total Connections'))
])
]),
E('tbody', {})
@@ -788,18 +425,18 @@ return view.extend({
if (!devices || devices.length === 0) {
container.innerHTML = '';
container.appendChild(E('div', { 'class': 'loading-state' },
getTranslation('无数据', language)));
_('No Data')));
return;
}
var table = E('table', { 'class': 'bandix-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', {}, getTranslation('设备', language)),
E('th', {}, _('Device')),
E('th', {}, 'TCP'),
E('th', {}, 'UDP'),
E('th', {}, getTranslation('TCP 状态详情', language)),
E('th', {}, getTranslation('总连接数', language))
E('th', {}, _('TCP Status Details')),
E('th', {}, _('Total Connections'))
])
]),
E('tbody', {}, devices.map(function (device) {
@@ -855,11 +492,11 @@ return view.extend({
updateGlobalStats(result.data.global_stats);
updateDeviceTable(result.data.devices);
} else {
showError(getTranslation('无法获取数据', language));
showError(_('Unable to fetch data'));
}
}).catch(function (error) {
console.error('Failed to load connection data:', error);
showError(getTranslation('无法获取数据', language));
showError(_('Unable to fetch data'));
});
}
@@ -869,6 +506,61 @@ return view.extend({
// 立即执行一次,不等待轮询
updateConnectionData();
// 自动适应主题背景色和文字颜色的函数
function applyThemeColors() {
try {
var mainElement = document.querySelector('.main') || document.body;
var computedStyle = window.getComputedStyle(mainElement);
var bgColor = computedStyle.backgroundColor;
// 如果父元素有背景色,应用到容器和卡片
if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
var containerEl = document.querySelector('.bandix-connection-container');
if (containerEl) {
containerEl.style.backgroundColor = bgColor;
}
// 应用到表格表头
var tableHeaders = document.querySelectorAll('.bandix-table th');
tableHeaders.forEach(function(th) {
th.style.backgroundColor = bgColor;
});
}
// 检测文字颜色并应用
var textColor = computedStyle.color;
if (textColor && textColor !== 'rgba(0, 0, 0, 0)') {
var containerEl = document.querySelector('.bandix-connection-container');
if (containerEl) {
containerEl.style.color = textColor;
}
}
} catch (e) {
// 如果检测失败,使用默认值
console.log('Theme adaptation:', e);
}
}
// 初始应用主题颜色
setTimeout(applyThemeColors, 100);
// 监听 DOM 变化,自动应用到新创建的元素
if (typeof MutationObserver !== 'undefined') {
var observer = new MutationObserver(function(mutations) {
applyThemeColors();
});
setTimeout(function() {
var container = document.querySelector('.bandix-connection-container');
if (container) {
observer.observe(container, {
childList: true,
subtree: true
});
}
}, 200);
}
return container;
}
});