From a08dd0ccf0d860156969be280cd680cdd91051d8 Mon Sep 17 00:00:00 2001 From: actions-user Date: Mon, 1 Dec 2025 00:10:48 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=9E=20Sync=202025-12-01=2000:10:48?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luci-app-bandix/Makefile | 2 +- .../resources/view/bandix/index.js | 473 +++++++++++++++--- .../resources/view/bandix/settings.js | 99 +++- luci-app-bandix/po/es/bandix.po | 63 +++ luci-app-bandix/po/fr/bandix.po | 65 ++- luci-app-bandix/po/id/bandix.po | 63 +++ luci-app-bandix/po/ja/bandix.po | 63 +++ luci-app-bandix/po/pl/bandix.po | 63 +++ luci-app-bandix/po/ru/bandix.po | 65 ++- luci-app-bandix/po/th/bandix.po | 63 +++ luci-app-bandix/po/zh_Hans/bandix.po | 65 ++- luci-app-bandix/po/zh_Hant/bandix.po | 65 ++- .../root/usr/libexec/rpcd/luci.bandix | 208 +++++++- .../usr/share/rpcd/acl.d/luci-app-bandix.json | 14 +- .../view/passwall/node_list/node_list.htm | 165 ++++-- luci-theme-aurora/.dev/src/media/main.css | 120 +---- luci-theme-aurora/Makefile | 4 +- .../htdocs/luci-static/aurora/main.css | 2 +- luci-theme-kucat/Makefile | 4 +- .../htdocs/luci-static/kucat/css/style.css | 152 ++++-- .../ucode/template/themes/kucat/header.ut | 2 +- openwrt-bandix/Makefile | 6 +- 22 files changed, 1542 insertions(+), 284 deletions(-) diff --git a/luci-app-bandix/Makefile b/luci-app-bandix/Makefile index cc9e98f..33659d3 100644 --- a/luci-app-bandix/Makefile +++ b/luci-app-bandix/Makefile @@ -10,7 +10,7 @@ LUCI_DEPENDS:=+luci-base +luci-lib-jsonc +curl +bandix PKG_MAINTAINER:=timsaya -PKG_VERSION:=0.9.1 +PKG_VERSION:=0.10.0 PKG_RELEASE:=1 include $(TOPDIR)/feeds/luci/luci.mk diff --git a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js index 39ccdf3..02eff18 100644 --- a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js +++ b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js @@ -148,6 +148,27 @@ var callGetMetrics = rpc.declare({ expect: {} }); +var callGetMetricsDay = rpc.declare({ + object: 'luci.bandix', + method: 'getMetricsDay', + params: ['mac'], + expect: {} +}); + +var callGetMetricsWeek = rpc.declare({ + object: 'luci.bandix', + method: 'getMetricsWeek', + params: ['mac'], + expect: {} +}); + +var callGetMetricsMonth = rpc.declare({ + object: 'luci.bandix', + method: 'getMetricsMonth', + params: ['mac'], + expect: {} +}); + // 定时限速 RPC var callGetScheduleLimits = rpc.declare({ object: 'luci.bandix', @@ -1017,6 +1038,94 @@ return view.extend({ display: flex; align-items: center; justify-content: space-between; + margin-bottom: 16px; + } + .history-header-left { + display: flex; + align-items: center; + gap: 16px; + } + .history-tabs { + display: inline-flex; + background-color: rgba(0, 0, 0, 0.04); + border-radius: 8px; + padding: 3px; + gap: 2px; + } + @media (prefers-color-scheme: dark) { + .history-tabs { + background-color: rgba(255, 255, 255, 0.08); + } + } + .history-tab { + padding: 6px 16px; + text-align: center; + cursor: pointer; + border: none; + background: transparent; + font-size: 0.8125rem; + font-weight: 500; + color: rgba(0, 0, 0, 0.65); + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + border-radius: 6px; + white-space: nowrap; + position: relative; + } + @media (prefers-color-scheme: dark) { + .history-tab { + color: rgba(255, 255, 255, 0.65); + } + } + .history-tab:hover:not(.active) { + color: rgba(0, 0, 0, 0.85); + background-color: rgba(0, 0, 0, 0.06); + } + @media (prefers-color-scheme: dark) { + .history-tab:hover:not(.active) { + color: rgba(255, 255, 255, 0.85); + background-color: rgba(255, 255, 255, 0.12); + } + } + .history-tab.active { + background-color: #ffffff; + color: #3b82f6; + font-weight: 600; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08); + } + @media (prefers-color-scheme: dark) { + .history-tab.active { + background-color: rgba(59, 130, 246, 0.15); + color: #60a5fa; + box-shadow: 0 0 0 1px rgba(59, 130, 246, 0.3); + } + } + @media (max-width: 768px) { + .history-header { + flex-direction: column; + align-items: flex-start; + gap: 12px; + } + .history-header-left { + width: 100%; + flex-direction: column; + align-items: flex-start; + gap: 12px; + } + .history-tabs { + width: 100%; + padding: 2px; + } + .history-tab { + flex: 1; + padding: 8px 6px; + font-size: 0.75rem; + } + /* 移动端只显示 Realtime tab */ + .history-tab[data-range="day"], + .history-tab[data-range="week"], + .history-tab[data-range="month"] { + display: none !important; + } } .history-controls { display: flex; @@ -1034,7 +1143,6 @@ return view.extend({ position: relative; } .history-legend { - margin-left: auto; display: flex; align-items: center; gap: 12px; @@ -1452,10 +1560,19 @@ return view.extend({ // 统计卡片 E('div', { 'class': 'stats-grid', 'id': 'stats-grid' }), - // 历史趋势卡片(无时间范围筛选) + // 历史趋势卡片(带时间范围 tab 切换) E('div', { 'class': 'cbi-section', 'id': 'history-card' }, [ - E('h3', { 'class': 'history-header', 'style': 'display: flex; align-items: center; justify-content: space-between;' }, [ - E('span', {}, _('Traffic History')), + E('div', { 'class': 'history-header' }, [ + E('div', { 'class': 'history-header-left' }, [ + // E('h3', { 'style': 'margin: 0; font-size: 1rem; font-weight: 600;' }, _('Traffic History')), + // 时间范围 Tab 切换 + E('div', { 'class': 'history-tabs' }, [ + E('button', { 'class': 'history-tab active', 'data-range': 'realtime', 'id': 'history-tab-realtime' }, _('Realtime')), + E('button', { 'class': 'history-tab', 'data-range': 'day', 'id': 'history-tab-day' }, _('Day')), + E('button', { 'class': 'history-tab', 'data-range': 'week', 'id': 'history-tab-week' }, _('Week')), + E('button', { 'class': 'history-tab', 'data-range': 'month', 'id': 'history-tab-month' }, _('Month')) + ]) + ]), E('div', { 'class': 'history-legend' }, [ E('div', { 'class': 'legend-item' }, [ E('span', { 'class': 'legend-dot legend-up' }), @@ -2525,14 +2642,109 @@ return view.extend({ } function getTypeKeys(type) { + // 对于非实时时间范围(day/week/month),只有 WAN 数据 + if (currentTimeRange !== 'realtime') { + // 所有类型都使用 WAN 数据 + return { up: 'wide_tx_rate', down: 'wide_rx_rate' }; + } + if (type === 'lan') return { up: 'local_tx_rate', down: 'local_rx_rate' }; if (type === 'wan') return { up: 'wide_tx_rate', down: 'wide_rx_rate' }; return { up: 'total_tx_rate', down: 'total_rx_rate' }; } + // 当前选择的时间范围 + var currentTimeRange = localStorage.getItem('bandix_time_range') || 'realtime'; + function fetchMetricsData(mac) { + // 根据选择的时间范围调用不同的接口 + var range = currentTimeRange; + var callFunction; + + switch (range) { + case 'day': + callFunction = callGetMetricsDay; + break; + case 'week': + callFunction = callGetMetricsWeek; + break; + case 'month': + callFunction = callGetMetricsMonth; + break; + case 'realtime': + default: + callFunction = callGetMetrics; + break; + } + // 通过 ubus RPC 获取,避免跨域与鉴权问题 - return callGetMetrics(mac || '').then(function (res) { return res || { metrics: [] }; }); + return callFunction(mac || '').then(function (res) { return res || { metrics: [] }; }); + } + + // 将数组数组格式转换为对象数组格式(实时数据格式:13个字段) + // 输入格式: [[ts_ms, total_rx_rate, total_tx_rate, local_rx_rate, local_tx_rate, wide_rx_rate, wide_tx_rate, total_rx_bytes, total_tx_bytes, local_rx_bytes, local_tx_bytes, wide_rx_bytes, wide_tx_bytes], ...] + // 输出格式: [{ts_ms, total_rx_rate, total_tx_rate, ...}, ...] + function convertMetricsArrayToObjects(metricsArray) { + if (!Array.isArray(metricsArray)) { + return []; + } + + return metricsArray.map(function(arr) { + // 检查数据格式:如果是15个字段,说明是 day/week/month 格式 + if (arr.length >= 15) { + // day/week/month 格式:使用 P95 作为主要显示值 + return { + ts_ms: arr[0] || 0, + // 使用 P95 作为主要速率显示(最有价值的指标) + wide_rx_rate: arr[5] || 0, // wide_rx_rate_p95 + wide_tx_rate: arr[11] || 0, // wide_tx_rate_p95 + // 保存所有统计信息供 tooltip 使用 + wide_rx_rate_avg: arr[1] || 0, + wide_rx_rate_max: arr[2] || 0, + wide_rx_rate_min: arr[3] || 0, + wide_rx_rate_p90: arr[4] || 0, + wide_rx_rate_p95: arr[5] || 0, + wide_rx_rate_p99: arr[6] || 0, + wide_tx_rate_avg: arr[7] || 0, + wide_tx_rate_max: arr[8] || 0, + wide_tx_rate_min: arr[9] || 0, + wide_tx_rate_p90: arr[10] || 0, + wide_tx_rate_p95: arr[11] || 0, + wide_tx_rate_p99: arr[12] || 0, + wide_rx_bytes: arr[13] || 0, + wide_tx_bytes: arr[14] || 0, + // 标记这是聚合数据 + is_aggregated: true, + // 为了兼容性,设置其他字段(day/week/month 只有 WAN 数据) + total_rx_rate: arr[5] || 0, // 使用 P95 + total_tx_rate: arr[11] || 0, // 使用 P95 + local_rx_rate: 0, + local_tx_rate: 0, + total_rx_bytes: arr[13] || 0, + total_tx_bytes: arr[14] || 0, + local_rx_bytes: 0, + local_tx_bytes: 0 + }; + } else { + // 实时数据格式(13个字段) + return { + ts_ms: arr[0] || 0, + total_rx_rate: arr[1] || 0, + total_tx_rate: arr[2] || 0, + local_rx_rate: arr[3] || 0, + local_tx_rate: arr[4] || 0, + wide_rx_rate: arr[5] || 0, + wide_tx_rate: arr[6] || 0, + total_rx_bytes: arr[7] || 0, + total_tx_bytes: arr[8] || 0, + local_rx_bytes: arr[9] || 0, + local_tx_bytes: arr[10] || 0, + wide_rx_bytes: arr[11] || 0, + wide_tx_bytes: arr[12] || 0, + is_aggregated: false + }; + } + }).filter(function(item) { return item !== null; }); } // 辅助函数:使用当前缩放设置绘制图表 @@ -2777,6 +2989,18 @@ return view.extend({ var ss = ('' + d.getSeconds()).padStart(2, '0'); return hh + ':' + mm + ':' + ss; } + + // 完整日期时间格式(用于聚合数据) + function msToFullDateTimeLabel(ts) { + var d = new Date(ts); + var year = d.getFullYear(); + var month = ('' + (d.getMonth() + 1)).padStart(2, '0'); + var day = ('' + d.getDate()).padStart(2, '0'); + var hh = ('' + d.getHours()).padStart(2, '0'); + var mm = ('' + d.getMinutes()).padStart(2, '0'); + var ss = ('' + d.getSeconds()).padStart(2, '0'); + return year + '-' + month + '-' + day + ' ' + hh + ':' + mm + ':' + ss; + } function buildTooltipHtml(point) { if (!point) return ''; @@ -2784,6 +3008,7 @@ return view.extend({ var typeSel = (typeof document !== 'undefined' ? document.getElementById('history-type-select') : null); var selType = (typeSel && typeSel.value) ? typeSel.value : 'total'; var speedUnit = uci.get('bandix', 'traffic', 'speed_unit') || 'bytes'; + var isAggregated = point.is_aggregated || false; function row(label, val) { lines.push('
' + label + '' + val + '
'); @@ -2815,64 +3040,99 @@ return view.extend({ return { up: 'total_tx_bytes', down: 'total_rx_bytes' }; } - lines.push('
' + msToTimeLabel(point.ts_ms) + '
'); - - // 若选择了设备,显示设备信息 - try { - var macSel = (typeof document !== 'undefined' ? document.getElementById('history-device-select') : null); - var macVal = (macSel && macSel.value) ? macSel.value : ''; - if (macVal && Array.isArray(latestDevices)) { - var dev = latestDevices.find(function(d){ return d.mac === macVal; }); - if (dev) { - var ipv6Info = ''; - var lanIPv6 = filterLanIPv6(dev.ipv6_addresses); - if (lanIPv6.length > 0) { - ipv6Info = ' | IPv6: ' + lanIPv6.join(', '); - } - var devLabel = (dev.hostname || '-') + (dev.ip ? ' (' + dev.ip + ')' : '') + (dev.mac ? ' [' + dev.mac + ']' : '') + ipv6Info; - lines.push('
' + _('Device') + ': ' + devLabel + '
'); - } + // 标题:聚合数据显示完整日期时间,实时数据只显示时间 + if (isAggregated) { + lines.push('
' + msToFullDateTimeLabel(point.ts_ms) + '
'); + var rangeLabel = currentTimeRange === 'day' ? _('Daily') : + currentTimeRange === 'week' ? _('Weekly') : + currentTimeRange === 'month' ? _('Monthly') : ''; + if (rangeLabel) { + lines.push('
' + rangeLabel + ' ' + _('Statistics') + '
'); } - } catch (e) {} + } else { + lines.push('
' + msToTimeLabel(point.ts_ms) + '
'); + } // 关键信息:选中类型的上下行速率(大号显示) var kpiLabels = labelsFor(selType); var kpiRateKeys = rateKeysFor(selType); - lines.push( - '
' + - '
' + - '
' + kpiLabels.up + '
' + - '
' + rateValue(kpiRateKeys.up) + '
' + - '
' + - '
' + - '
' + kpiLabels.down + '
' + - '
' + rateValue(kpiRateKeys.down) + '
' + - '
' + - '
' - ); + + if (isAggregated) { + // 聚合数据:显示 P95 值(主要指标) + lines.push( + '
' + + '
' + + '
' + _('WAN Upload') + ' (P95)
' + + '
' + formatByterate(point.wide_tx_rate_p95 || 0, speedUnit) + '
' + + '
' + + '
' + + '
' + _('WAN Download') + ' (P95)
' + + '
' + formatByterate(point.wide_rx_rate_p95 || 0, speedUnit) + '
' + + '
' + + '
' + ); + + // 详细统计信息 + lines.push('
'); + lines.push('
' + _('Upload Statistics') + '
'); + row(_('Average'), formatByterate(point.wide_tx_rate_avg || 0, speedUnit)); + row(_('Maximum'), formatByterate(point.wide_tx_rate_max || 0, speedUnit)); + row(_('Minimum'), formatByterate(point.wide_tx_rate_min || 0, speedUnit)); + row('P90', formatByterate(point.wide_tx_rate_p90 || 0, speedUnit)); + row('P95', formatByterate(point.wide_tx_rate_p95 || 0, speedUnit)); + row('P99', formatByterate(point.wide_tx_rate_p99 || 0, speedUnit)); + + lines.push('
' + _('Download Statistics') + '
'); + row(_('Average'), formatByterate(point.wide_rx_rate_avg || 0, speedUnit)); + row(_('Maximum'), formatByterate(point.wide_rx_rate_max || 0, speedUnit)); + row(_('Minimum'), formatByterate(point.wide_rx_rate_min || 0, speedUnit)); + row('P90', formatByterate(point.wide_rx_rate_p90 || 0, speedUnit)); + row('P95', formatByterate(point.wide_rx_rate_p95 || 0, speedUnit)); + row('P99', formatByterate(point.wide_rx_rate_p99 || 0, speedUnit)); + + // 累计流量(只显示 WAN) + lines.push('
'); + lines.push('
' + _('Cumulative Traffic') + '
'); + row(_('WAN Uploaded'), bytesValue('wide_tx_bytes')); + row(_('WAN Downloaded'), bytesValue('wide_rx_bytes')); + } else { + // 实时数据:显示实时速率 + lines.push( + '
' + + '
' + + '
' + kpiLabels.up + '
' + + '
' + rateValue(kpiRateKeys.up) + '
' + + '
' + + '
' + + '
' + kpiLabels.down + '
' + + '
' + rateValue(kpiRateKeys.down) + '
' + + '
' + + '
' + ); - // 次要信息:其余类型的速率(精简展示) - var otherTypes = ['total', 'lan', 'wan'].filter(function (t) { return t !== selType; }); - if (otherTypes.length) { - lines.push('
' + _('Other Rates') + '
'); - otherTypes.forEach(function (t) { - var lbs = labelsFor(t); - var ks = rateKeysFor(t); - row(lbs.up, rateValue(ks.up)); - row(lbs.down, rateValue(ks.down)); - }); + // 次要信息:其余类型的速率(精简展示) + var otherTypes = ['total', 'lan', 'wan'].filter(function (t) { return t !== selType; }); + if (otherTypes.length) { + lines.push('
' + _('Other Rates') + '
'); + otherTypes.forEach(function (t) { + var lbs = labelsFor(t); + var ks = rateKeysFor(t); + row(lbs.up, rateValue(ks.up)); + row(lbs.down, rateValue(ks.down)); + }); + } + + // 累计:区分LAN 流量与公网 + lines.push('
'); + lines.push('
' + _('Cumulative') + '
'); + row(_('Total Uploaded'), bytesValue('total_tx_bytes')); + row(_('Total Downloaded'), bytesValue('total_rx_bytes')); + row(_('LAN Uploaded'), bytesValue('local_tx_bytes')); + row(_('LAN Downloaded'), bytesValue('local_rx_bytes')); + row(_('WAN Uploaded'), bytesValue('wide_tx_bytes')); + row(_('WAN Downloaded'), bytesValue('wide_rx_bytes')); } - // 累计:区分LAN 流量与公网 - lines.push('
'); - lines.push('
' + _('Cumulative') + '
'); - row(_('Total Uploaded'), bytesValue('total_tx_bytes')); - row(_('Total Downloaded'), bytesValue('total_rx_bytes')); - row(_('LAN Uploaded'), bytesValue('local_tx_bytes')); - row(_('LAN Downloaded'), bytesValue('local_rx_bytes')); - row(_('WAN Uploaded'), bytesValue('wide_tx_bytes')); - row(_('WAN Downloaded'), bytesValue('wide_rx_bytes')); - return lines.join(''); } @@ -3236,7 +3496,9 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { return fetchMetricsData(mac).then(function (res) { - var data = Array.isArray(res && res.metrics) ? res.metrics.slice() : []; + // 将数组数组格式转换为对象数组格式 + var rawMetrics = res && res.metrics ? res.metrics : []; + var data = convertMetricsArrayToObjects(rawMetrics); lastHistoryData = data; var retentionBadge = document.getElementById('history-retention'); @@ -3603,14 +3865,99 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { }); } - // 历史趋势:事件绑定 - (function initHistoryControls() { + // 历史趋势:事件绑定(延迟执行以确保 DOM 已加载) + function initHistoryControls() { var typeSel = document.getElementById('history-type-select'); var devSel = document.getElementById('history-device-select'); if (typeSel) typeSel.value = 'total'; // 初始化缩放倍率显示 updateZoomLevelDisplay(); + + // Tab 切换事件处理 + var tabButtons = document.querySelectorAll('.history-tab'); + + // 确保找到了 tab 按钮 + if (tabButtons.length === 0) { + console.warn('History tab buttons not found, retrying...'); + setTimeout(initHistoryControls, 100); + return; + } + + tabButtons.forEach(function(btn) { + btn.addEventListener('click', function() { + var range = this.getAttribute('data-range'); + + // 更新当前选择的时间范围 + currentTimeRange = range; + localStorage.setItem('bandix_time_range', range); + + // 更新 tab 状态 + tabButtons.forEach(function(b) { + b.classList.remove('active'); + }); + this.classList.add('active'); + + // 对于非实时时间范围,禁用 LAN 和 Total 选项(因为只有 WAN 数据) + if (range !== 'realtime') { + if (typeSel) { + // 如果当前选择的是 LAN 或 Total,切换到 WAN + if (typeSel.value === 'lan' || typeSel.value === 'total') { + typeSel.value = 'wan'; + } + // 禁用 LAN 和 Total 选项 + var lanOption = typeSel.querySelector('option[value="lan"]'); + var totalOption = typeSel.querySelector('option[value="total"]'); + if (lanOption) lanOption.disabled = true; + if (totalOption) totalOption.disabled = true; + } + } else { + // 实时模式下,启用所有选项 + if (typeSel) { + var lanOption = typeSel.querySelector('option[value="lan"]'); + var totalOption = typeSel.querySelector('option[value="total"]'); + if (lanOption) lanOption.disabled = false; + if (totalOption) totalOption.disabled = false; + } + } + + // 刷新历史数据 + refreshHistory(); + }); + }); + + // 恢复之前选择的时间范围 + var savedRange = localStorage.getItem('bandix_time_range') || 'realtime'; + + // 移动端强制使用 realtime + var screenWidth = window.innerWidth || document.documentElement.clientWidth; + var isMobileScreen = screenWidth <= 768; + if (isMobileScreen) { + savedRange = 'realtime'; + currentTimeRange = 'realtime'; + localStorage.setItem('bandix_time_range', 'realtime'); + } else { + currentTimeRange = savedRange; + } + + tabButtons.forEach(function(btn) { + if (btn.getAttribute('data-range') === savedRange) { + btn.classList.add('active'); + // 触发一次点击以应用选项禁用逻辑 + if (savedRange !== 'realtime' && typeSel) { + var lanOption = typeSel.querySelector('option[value="lan"]'); + var totalOption = typeSel.querySelector('option[value="total"]'); + if (lanOption) lanOption.disabled = true; + if (totalOption) totalOption.disabled = true; + if (typeSel.value === 'lan' || typeSel.value === 'total') { + typeSel.value = 'wan'; + } + } + } else { + btn.classList.remove('active'); + } + }); + function onFilterChange() { refreshHistory(); // 同步刷新表格(立即生效,不等轮询) @@ -3626,12 +3973,16 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { // 首次加载 refreshHistory(); - })(); + } + + // 延迟执行以确保 DOM 已加载 + setTimeout(initHistoryControls, 0); - // 历史趋势轮询(每1秒) + // 历史趋势轮询(实时数据每1秒,其他时间范围每30秒) + // 使用 poll.add 但根据时间范围动态调整 poll.add(function () { return refreshHistory(); - },1); + }, 1); diff --git a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js index 54f1258..66042fc 100644 --- a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js +++ b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/settings.js @@ -3,11 +3,24 @@ 'require form'; 'require ui'; 'require uci'; -'require fs'; +'require rpc'; // 暗色模式检测已改为使用 CSS 媒体查询 @media (prefers-color-scheme: dark) +// 声明 RPC 调用方法 +var callClearData = rpc.declare({ + object: 'luci.bandix', + method: 'clearData', + expect: { } +}); + +var callRestartService = rpc.declare({ + object: 'luci.bandix', + method: 'restartService', + expect: { } +}); + return view.extend({ load: function () { return Promise.all([ @@ -108,14 +121,78 @@ return view.extend({ return uci.get('bandix', section_id, 'data_dir') || '/usr/share/bandix'; }; - // 添加意见反馈信息 - o = s.option(form.DummyValue, 'feedback_info', _('Feedback')); - o.href = 'https://github.com/timsaya'; - o.cfgvalue = function () { - return 'https://github.com/timsaya'; - }; + // 添加意见反馈信息 + o = s.option(form.DummyValue, 'feedback_info', _('Feedback')); + o.href = 'https://github.com/timsaya'; + o.cfgvalue = function () { + return 'https://github.com/timsaya'; + }; - // 2. 流量监控设置部分 (traffic) + // 添加清空数据按钮 + o = s.option(form.Button, 'clear_data', _('Clear Traffic Data')); + o.inputtitle = _('Clear Traffic Data'); + o.inputstyle = 'reset'; + o.onclick = function () { + return ui.showModal(_('Clear Traffic Data'), [ + E('p', _('Are you sure you want to clear all traffic data? This action cannot be undone.')), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-negative', + 'click': function () { + ui.hideModal(); + return callClearData() + .then(function (result) { + if (result && !result.success) { + ui.addNotification(null, E('p', _('Failed to clear traffic data: ') + (result.error || 'Unknown error')), 'error'); + } + }) + .catch(function (err) { + ui.addNotification(null, E('p', _('Failed to clear traffic data: ') + err.message), 'error'); + }); + } + }, _('Confirm')) + ]) + ]); + }; + + // 添加重启服务按钮 + o = s.option(form.Button, 'restart_service', _('Restart Service')); + o.inputtitle = _('Restart Bandix Service'); + o.inputstyle = 'apply'; + o.onclick = function () { + return ui.showModal(_('Restart Service'), [ + E('p', _('Are you sure you want to restart the Bandix service?')), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': ui.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'click': function () { + ui.hideModal(); + return callRestartService() + .then(function (result) { + if (result && !result.success) { + ui.addNotification(null, E('p', _('Failed to restart service: ') + (result.error || 'Unknown error')), 'error'); + } + }) + .catch(function (err) { + ui.addNotification(null, E('p', _('Failed to restart service: ') + err.message), 'error'); + }); + } + }, _('Confirm')) + ]) + ]); + }; + + // 2. 流量监控设置部分 (traffic) s = m.section(form.NamedSection, 'traffic', 'traffic', _('Traffic Monitor Settings')); s.description = _('Configure traffic monitoring related parameters'); s.addremove = false; @@ -147,6 +224,7 @@ return view.extend({ o.default = '0'; o.rmempty = false; + // 添加数据 flush 间隔(秒) o = s.option(form.ListValue, 'traffic_flush_interval_seconds', _('Data Flush Interval'), _('Set the interval for flushing data to disk')); @@ -166,13 +244,10 @@ return view.extend({ // 添加历史流量周期(秒) o = s.option(form.ListValue, 'traffic_retention_seconds', _('Traffic History Period'), _('10 minutes interval uses about 60 KB per device')); - o.value('60', _('1 minute')); - o.value('300', _('5 minutes')); o.value('600', _('10 minutes')); o.value('900', _('15 minutes')); - o.value('1200', _('20 minutes')); - o.value('1500', _('25 minutes')); o.value('1800', _('30 minutes')); + o.value('3600', _('1 hour')); o.default = '600'; o.rmempty = false; diff --git a/luci-app-bandix/po/es/bandix.po b/luci-app-bandix/po/es/bandix.po index e965242..ff28dee 100644 --- a/luci-app-bandix/po/es/bandix.po +++ b/luci-app-bandix/po/es/bandix.po @@ -841,3 +841,66 @@ msgstr "Sin regla activa" msgid "Schedule Rules" msgstr "Reglas de limitación programada" + +msgid "Upload Statistics" +msgstr "Estadísticas de subida" + +msgid "Download Statistics" +msgstr "Estadísticas de descarga" + +msgid "Cumulative Traffic" +msgstr "Tráfico acumulado" + +msgid "Daily" +msgstr "Diario" + +msgid "Weekly" +msgstr "Semanal" + +msgid "Monthly" +msgstr "Mensual" + +msgid "Statistics" +msgstr "Estadísticas" + +msgid "Average" +msgstr "Promedio" + +msgid "Maximum" +msgstr "Máximo" + +msgid "Minimum" +msgstr "Mínimo" + +msgid "WAN Upload" +msgstr "Subida WAN" + +msgid "WAN Download" +msgstr "Descarga WAN" + +msgid "WAN Uploaded" +msgstr "Subido WAN" + +msgid "WAN Downloaded" +msgstr "Descargado WAN" + +msgid "Clear Traffic Data" +msgstr "Borrar datos de tráfico" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "¿Está seguro de que desea borrar todos los datos de tráfico? Esta acción no se puede deshacer." + +msgid "Failed to clear traffic data: " +msgstr "Error al borrar los datos de tráfico: " + +msgid "Restart Service" +msgstr "Reiniciar servicio" + +msgid "Restart Bandix Service" +msgstr "Reiniciar servicio Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "¿Está seguro de que desea reiniciar el servicio Bandix?" + +msgid "Failed to restart service: " +msgstr "Error al reiniciar el servicio: " diff --git a/luci-app-bandix/po/fr/bandix.po b/luci-app-bandix/po/fr/bandix.po index 658f76c..796bbc6 100644 --- a/luci-app-bandix/po/fr/bandix.po +++ b/luci-app-bandix/po/fr/bandix.po @@ -840,4 +840,67 @@ msgid "No active rule" msgstr "Aucune règle active" msgid "Schedule Rules" -msgstr "Règles de limitation programmée" \ No newline at end of file +msgstr "Règles de limitation programmée" + +msgid "Upload Statistics" +msgstr "Statistiques d'envoi" + +msgid "Download Statistics" +msgstr "Statistiques de téléchargement" + +msgid "Cumulative Traffic" +msgstr "Trafic cumulé" + +msgid "Daily" +msgstr "Quotidien" + +msgid "Weekly" +msgstr "Hebdomadaire" + +msgid "Monthly" +msgstr "Mensuel" + +msgid "Statistics" +msgstr "Statistiques" + +msgid "Average" +msgstr "Moyenne" + +msgid "Maximum" +msgstr "Maximum" + +msgid "Minimum" +msgstr "Minimum" + +msgid "WAN Upload" +msgstr "Envoi WAN" + +msgid "WAN Download" +msgstr "Téléchargement WAN" + +msgid "WAN Uploaded" +msgstr "Envoyé WAN" + +msgid "WAN Downloaded" +msgstr "Téléchargé WAN" + +msgid "Clear Traffic Data" +msgstr "Effacer les données de trafic" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "Êtes-vous sûr de vouloir effacer toutes les données de trafic ? Cette action est irréversible." + +msgid "Failed to clear traffic data: " +msgstr "Échec de l'effacement des données de trafic : " + +msgid "Restart Service" +msgstr "Redémarrer le service" + +msgid "Restart Bandix Service" +msgstr "Redémarrer le service Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "Êtes-vous sûr de vouloir redémarrer le service Bandix ?" + +msgid "Failed to restart service: " +msgstr "Échec du redémarrage du service : " \ No newline at end of file diff --git a/luci-app-bandix/po/id/bandix.po b/luci-app-bandix/po/id/bandix.po index 0c70d35..293f29d 100644 --- a/luci-app-bandix/po/id/bandix.po +++ b/luci-app-bandix/po/id/bandix.po @@ -841,3 +841,66 @@ msgstr "Tidak ada aturan aktif" msgid "Schedule Rules" msgstr "Aturan pembatasan terjadwal" + +msgid "Upload Statistics" +msgstr "Statistik unggahan" + +msgid "Download Statistics" +msgstr "Statistik unduhan" + +msgid "Cumulative Traffic" +msgstr "Lalu lintas kumulatif" + +msgid "Daily" +msgstr "Harian" + +msgid "Weekly" +msgstr "Mingguan" + +msgid "Monthly" +msgstr "Bulanan" + +msgid "Statistics" +msgstr "Statistik" + +msgid "Average" +msgstr "Rata-rata" + +msgid "Maximum" +msgstr "Maksimum" + +msgid "Minimum" +msgstr "Minimum" + +msgid "WAN Upload" +msgstr "Unggahan WAN" + +msgid "WAN Download" +msgstr "Unduhan WAN" + +msgid "WAN Uploaded" +msgstr "Diunggah WAN" + +msgid "WAN Downloaded" +msgstr "Diunduh WAN" + +msgid "Clear Traffic Data" +msgstr "Hapus Data Lalu Lintas" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "Apakah Anda yakin ingin menghapus semua data lalu lintas? Tindakan ini tidak dapat dibatalkan." + +msgid "Failed to clear traffic data: " +msgstr "Gagal menghapus data lalu lintas: " + +msgid "Restart Service" +msgstr "Mulai Ulang Layanan" + +msgid "Restart Bandix Service" +msgstr "Mulai Ulang Layanan Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "Apakah Anda yakin ingin memulai ulang layanan Bandix?" + +msgid "Failed to restart service: " +msgstr "Gagal memulai ulang layanan: " diff --git a/luci-app-bandix/po/ja/bandix.po b/luci-app-bandix/po/ja/bandix.po index 7a1c54b..8b5abc4 100644 --- a/luci-app-bandix/po/ja/bandix.po +++ b/luci-app-bandix/po/ja/bandix.po @@ -841,3 +841,66 @@ msgstr "アクティブなルールなし" msgid "Schedule Rules" msgstr "スケジュール制限ルール" + +msgid "Upload Statistics" +msgstr "アップロード統計" + +msgid "Download Statistics" +msgstr "ダウンロード統計" + +msgid "Cumulative Traffic" +msgstr "累積トラフィック" + +msgid "Daily" +msgstr "日次" + +msgid "Weekly" +msgstr "週次" + +msgid "Monthly" +msgstr "月次" + +msgid "Statistics" +msgstr "統計" + +msgid "Average" +msgstr "平均" + +msgid "Maximum" +msgstr "最大" + +msgid "Minimum" +msgstr "最小" + +msgid "WAN Upload" +msgstr "WAN アップロード" + +msgid "WAN Download" +msgstr "WAN ダウンロード" + +msgid "WAN Uploaded" +msgstr "WAN アップロード量" + +msgid "WAN Downloaded" +msgstr "WAN ダウンロード量" + +msgid "Clear Traffic Data" +msgstr "トラフィックデータを削除" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "すべてのトラフィックデータを削除してもよろしいですか?この操作は元に戻せません。" + +msgid "Failed to clear traffic data: " +msgstr "トラフィックデータの削除に失敗しました:" + +msgid "Restart Service" +msgstr "サービス再起動" + +msgid "Restart Bandix Service" +msgstr "Bandix サービスを再起動" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "Bandix サービスを再起動してもよろしいですか?" + +msgid "Failed to restart service: " +msgstr "サービスの再起動に失敗しました:" diff --git a/luci-app-bandix/po/pl/bandix.po b/luci-app-bandix/po/pl/bandix.po index 5abe740..491fd3c 100644 --- a/luci-app-bandix/po/pl/bandix.po +++ b/luci-app-bandix/po/pl/bandix.po @@ -842,3 +842,66 @@ msgstr "Brak aktywnej reguły" msgid "Schedule Rules" msgstr "Reguły limitu czasu" +msgid "Upload Statistics" +msgstr "Statystyki wysyłania" + +msgid "Download Statistics" +msgstr "Statystyki pobierania" + +msgid "Cumulative Traffic" +msgstr "Skumulowany ruch" + +msgid "Daily" +msgstr "Dzienny" + +msgid "Weekly" +msgstr "Tygodniowy" + +msgid "Monthly" +msgstr "Miesięczny" + +msgid "Statistics" +msgstr "Statystyki" + +msgid "Average" +msgstr "Średnia" + +msgid "Maximum" +msgstr "Maksimum" + +msgid "Minimum" +msgstr "Minimum" + +msgid "WAN Upload" +msgstr "Wysyłanie WAN" + +msgid "WAN Download" +msgstr "Pobieranie WAN" + +msgid "WAN Uploaded" +msgstr "Wysłano WAN" + +msgid "WAN Downloaded" +msgstr "Pobrano WAN" + +msgid "Clear Traffic Data" +msgstr "Wyczyść dane ruchu" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "Czy na pewno chcesz wyczyścić wszystkie dane ruchu? Tej operacji nie można cofnąć." + +msgid "Failed to clear traffic data: " +msgstr "Nie udało się wyczyścić danych ruchu: " + +msgid "Restart Service" +msgstr "Uruchom ponownie usługę" + +msgid "Restart Bandix Service" +msgstr "Uruchom ponownie usługę Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "Czy na pewno chcesz uruchomić ponownie usługę Bandix?" + +msgid "Failed to restart service: " +msgstr "Nie udało się uruchomić ponownie usługi: " + diff --git a/luci-app-bandix/po/ru/bandix.po b/luci-app-bandix/po/ru/bandix.po index 29401e5..697a002 100644 --- a/luci-app-bandix/po/ru/bandix.po +++ b/luci-app-bandix/po/ru/bandix.po @@ -840,4 +840,67 @@ msgid "No active rule" msgstr "Нет активных правил" msgid "Schedule Rules" -msgstr "Правила ограничения по расписанию" \ No newline at end of file +msgstr "Правила ограничения по расписанию" + +msgid "Upload Statistics" +msgstr "Статистика отправки" + +msgid "Download Statistics" +msgstr "Статистика загрузки" + +msgid "Cumulative Traffic" +msgstr "Накопительный трафик" + +msgid "Daily" +msgstr "Ежедневно" + +msgid "Weekly" +msgstr "Еженедельно" + +msgid "Monthly" +msgstr "Ежемесячно" + +msgid "Statistics" +msgstr "Статистика" + +msgid "Average" +msgstr "Среднее" + +msgid "Maximum" +msgstr "Максимум" + +msgid "Minimum" +msgstr "Минимум" + +msgid "WAN Upload" +msgstr "Отправка WAN" + +msgid "WAN Download" +msgstr "Загрузка WAN" + +msgid "WAN Uploaded" +msgstr "Отправлено WAN" + +msgid "WAN Downloaded" +msgstr "Загружено WAN" + +msgid "Clear Traffic Data" +msgstr "Очистить данные трафика" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "Вы уверены, что хотите очистить все данные трафика? Это действие нельзя отменить." + +msgid "Failed to clear traffic data: " +msgstr "Не удалось очистить данные трафика: " + +msgid "Restart Service" +msgstr "Перезапустить службу" + +msgid "Restart Bandix Service" +msgstr "Перезапустить службу Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "Вы уверены, что хотите перезапустить службу Bandix?" + +msgid "Failed to restart service: " +msgstr "Не удалось перезапустить службу: " \ No newline at end of file diff --git a/luci-app-bandix/po/th/bandix.po b/luci-app-bandix/po/th/bandix.po index aed52d4..68af5d0 100644 --- a/luci-app-bandix/po/th/bandix.po +++ b/luci-app-bandix/po/th/bandix.po @@ -841,3 +841,66 @@ msgstr "ไม่มีกฎที่ใช้งาน" msgid "Schedule Rules" msgstr "กฎการจำกัดอัตราแบบกำหนดเวลา" + +msgid "Upload Statistics" +msgstr "สถิติการอัปโหลด" + +msgid "Download Statistics" +msgstr "สถิติการดาวน์โหลด" + +msgid "Cumulative Traffic" +msgstr "ปริมาณการใช้งานสะสม" + +msgid "Daily" +msgstr "รายวัน" + +msgid "Weekly" +msgstr "รายสัปดาห์" + +msgid "Monthly" +msgstr "รายเดือน" + +msgid "Statistics" +msgstr "สถิติ" + +msgid "Average" +msgstr "ค่าเฉลี่ย" + +msgid "Maximum" +msgstr "สูงสุด" + +msgid "Minimum" +msgstr "ต่ำสุด" + +msgid "WAN Upload" +msgstr "อัปโหลด WAN" + +msgid "WAN Download" +msgstr "ดาวน์โหลด WAN" + +msgid "WAN Uploaded" +msgstr "อัปโหลด WAN แล้ว" + +msgid "WAN Downloaded" +msgstr "ดาวน์โหลด WAN แล้ว" + +msgid "Clear Traffic Data" +msgstr "ลบข้อมูลทราฟฟิก" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "คุณแน่ใจหรือไม่ว่าต้องการลบข้อมูลทราฟฟิกทั้งหมด? การกระทำนี้ไม่สามารถยกเลิกได้" + +msgid "Failed to clear traffic data: " +msgstr "ล้มเหลวในการลบข้อมูลทราฟฟิก: " + +msgid "Restart Service" +msgstr "รีสตาร์ทบริการ" + +msgid "Restart Bandix Service" +msgstr "รีสตาร์ทบริการ Bandix" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "คุณแน่ใจหรือไม่ว่าต้องการรีสตาร์ทบริการ Bandix?" + +msgid "Failed to restart service: " +msgstr "ล้มเหลวในการรีสตาร์ทบริการ: " diff --git a/luci-app-bandix/po/zh_Hans/bandix.po b/luci-app-bandix/po/zh_Hans/bandix.po index 42859e0..369a9d9 100644 --- a/luci-app-bandix/po/zh_Hans/bandix.po +++ b/luci-app-bandix/po/zh_Hans/bandix.po @@ -840,4 +840,67 @@ msgid "No active rule" msgstr "无生效规则" msgid "Schedule Rules" -msgstr "定时限速规则" \ No newline at end of file +msgstr "定时限速规则" + +msgid "Upload Statistics" +msgstr "上传统计" + +msgid "Download Statistics" +msgstr "下载统计" + +msgid "Cumulative Traffic" +msgstr "累计流量" + +msgid "Daily" +msgstr "每日" + +msgid "Weekly" +msgstr "每周" + +msgid "Monthly" +msgstr "每月" + +msgid "Statistics" +msgstr "统计" + +msgid "Average" +msgstr "平均值" + +msgid "Maximum" +msgstr "最大值" + +msgid "Minimum" +msgstr "最小值" + +msgid "WAN Upload" +msgstr "WAN 上传" + +msgid "WAN Download" +msgstr "WAN 下载" + +msgid "WAN Uploaded" +msgstr "WAN 上传量" + +msgid "WAN Downloaded" +msgstr "WAN 下载量" + +msgid "Clear Traffic Data" +msgstr "删除流量数据" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "确定要清除所有流量数据吗?此操作无法撤销。" + +msgid "Failed to clear traffic data: " +msgstr "清除流量数据失败:" + +msgid "Restart Service" +msgstr "重启服务" + +msgid "Restart Bandix Service" +msgstr "重启 Bandix 服务" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "确定要重启 Bandix 服务吗?" + +msgid "Failed to restart service: " +msgstr "重启服务失败:" \ No newline at end of file diff --git a/luci-app-bandix/po/zh_Hant/bandix.po b/luci-app-bandix/po/zh_Hant/bandix.po index ec598d2..f34822c 100644 --- a/luci-app-bandix/po/zh_Hant/bandix.po +++ b/luci-app-bandix/po/zh_Hant/bandix.po @@ -840,4 +840,67 @@ msgid "No active rule" msgstr "無生效規則" msgid "Schedule Rules" -msgstr "定時限速規則" \ No newline at end of file +msgstr "定時限速規則" + +msgid "Upload Statistics" +msgstr "上傳統計" + +msgid "Download Statistics" +msgstr "下載統計" + +msgid "Cumulative Traffic" +msgstr "累計流量" + +msgid "Daily" +msgstr "每日" + +msgid "Weekly" +msgstr "每週" + +msgid "Monthly" +msgstr "每月" + +msgid "Statistics" +msgstr "統計" + +msgid "Average" +msgstr "平均值" + +msgid "Maximum" +msgstr "最大值" + +msgid "Minimum" +msgstr "最小值" + +msgid "WAN Upload" +msgstr "WAN 上傳" + +msgid "WAN Download" +msgstr "WAN 下載" + +msgid "WAN Uploaded" +msgstr "WAN 上傳量" + +msgid "WAN Downloaded" +msgstr "WAN 下載量" + +msgid "Clear Traffic Data" +msgstr "刪除流量數據" + +msgid "Are you sure you want to clear all traffic data? This action cannot be undone." +msgstr "確定要清除所有流量數據嗎?此操作無法撤銷。" + +msgid "Failed to clear traffic data: " +msgstr "清除流量數據失敗:" + +msgid "Restart Service" +msgstr "重啟服務" + +msgid "Restart Bandix Service" +msgstr "重啟 Bandix 服務" + +msgid "Are you sure you want to restart the Bandix service?" +msgstr "確定要重啟 Bandix 服務嗎?" + +msgid "Failed to restart service: " +msgstr "重啟服務失敗:" \ No newline at end of file diff --git a/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix b/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix index 4459919..144d13a 100755 --- a/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix +++ b/luci-app-bandix/root/usr/libexec/rpcd/luci.bandix @@ -9,6 +9,9 @@ readonly BANDIX_API_BASE="http://127.0.0.1:$BANDIX_PORT" readonly BANDIX_DEVICES_API="$BANDIX_API_BASE/api/traffic/devices" readonly BANDIX_LIMITS_API="$BANDIX_API_BASE/api/traffic/limits" readonly BANDIX_METRICS_API="$BANDIX_API_BASE/api/traffic/metrics" +readonly BANDIX_METRICS_DAY_API="$BANDIX_API_BASE/api/traffic/metrics/day" +readonly BANDIX_METRICS_WEEK_API="$BANDIX_API_BASE/api/traffic/metrics/week" +readonly BANDIX_METRICS_MONTH_API="$BANDIX_API_BASE/api/traffic/metrics/month" readonly BANDIX_CONNECTION_API="$BANDIX_API_BASE/api/connection/devices" readonly BANDIX_DNS_QUERIES_API="$BANDIX_API_BASE/api/dns/queries" readonly BANDIX_DNS_STATS_API="$BANDIX_API_BASE/api/dns/stats" @@ -99,6 +102,90 @@ get_metrics() { fi } +# 获取日指标(可选MAC) +get_metrics_day() { + local mac="$1" + local url="$BANDIX_METRICS_DAY_API" + if [ -n "$mac" ]; then + # 转义MAC + local mac_escaped=$(echo "$mac" | sed 's/\//\\\//g') + url="$url?mac=$mac_escaped" + fi + + local api_result=$(curl -s --connect-timeout 2 --max-time 10 "$url" 2>/dev/null) + local curl_exit_code=$? + + if [ $curl_exit_code -ne 0 ] || [ -z "$api_result" ]; then + echo '{"retention_seconds":86400,"mac":"","metrics":[]}' + return + fi + + # 使用 jsonfilter 提取 data 部分 + local data_part=$(echo "$api_result" | jsonfilter -e '$.data' 2>/dev/null) + if [ -n "$data_part" ]; then + echo "$data_part" + return + else + echo '{"retention_seconds":86400,"mac":"","metrics":[]}' + fi +} + +# 获取周指标(可选MAC) +get_metrics_week() { + local mac="$1" + local url="$BANDIX_METRICS_WEEK_API" + if [ -n "$mac" ]; then + # 转义MAC + local mac_escaped=$(echo "$mac" | sed 's/\//\\\//g') + url="$url?mac=$mac_escaped" + fi + + local api_result=$(curl -s --connect-timeout 2 --max-time 10 "$url" 2>/dev/null) + local curl_exit_code=$? + + if [ $curl_exit_code -ne 0 ] || [ -z "$api_result" ]; then + echo '{"retention_seconds":604800,"mac":"","metrics":[]}' + return + fi + + # 使用 jsonfilter 提取 data 部分 + local data_part=$(echo "$api_result" | jsonfilter -e '$.data' 2>/dev/null) + if [ -n "$data_part" ]; then + echo "$data_part" + return + else + echo '{"retention_seconds":604800,"mac":"","metrics":[]}' + fi +} + +# 获取月指标(可选MAC) +get_metrics_month() { + local mac="$1" + local url="$BANDIX_METRICS_MONTH_API" + if [ -n "$mac" ]; then + # 转义MAC + local mac_escaped=$(echo "$mac" | sed 's/\//\\\//g') + url="$url?mac=$mac_escaped" + fi + + local api_result=$(curl -s --connect-timeout 2 --max-time 10 "$url" 2>/dev/null) + local curl_exit_code=$? + + if [ $curl_exit_code -ne 0 ] || [ -z "$api_result" ]; then + echo '{"retention_seconds":2592000,"mac":"","metrics":[]}' + return + fi + + # 使用 jsonfilter 提取 data 部分 + local data_part=$(echo "$api_result" | jsonfilter -e '$.data' 2>/dev/null) + if [ -n "$data_part" ]; then + echo "$data_part" + return + else + echo '{"retention_seconds":2592000,"mac":"","metrics":[]}' + fi +} + # 设置设备主机名绑定 set_device_hostname() { local mac="$1" @@ -367,6 +454,39 @@ delete_schedule_limit() { fi } +# 清空数据 +clear_data() { + local data_dir=$(uci get bandix.general.data_dir 2>/dev/null || echo "/usr/share/bandix") + local metrics_dir="$data_dir/metrics" + + # 检查目录是否存在 + if [ ! -d "$metrics_dir" ]; then + make_error "Metrics directory does not exist" + return + fi + + # 删除 metrics 目录下的所有文件 + rm -rf "$metrics_dir"/* 2>/dev/null + + if [ $? -eq 0 ]; then + make_success "Data cleared successfully" + else + make_error "Failed to clear data" + fi +} + +# 重启服务 +restart_service() { + # 执行服务重启 + /etc/init.d/bandix restart >/dev/null 2>&1 + + if [ $? -eq 0 ]; then + make_success "Service restarted successfully" + else + make_error "Failed to restart service" + fi +} + case "$1" in list) json_init @@ -377,6 +497,18 @@ case "$1" in json_add_string "mac" json_close_object + json_add_object "getMetricsDay" + json_add_string "mac" + json_close_object + + json_add_object "getMetricsWeek" + json_add_string "mac" + json_close_object + + json_add_object "getMetricsMonth" + json_add_string "mac" + json_close_object + json_add_object "setHostname" json_add_string "mac" json_add_string "hostname" @@ -410,16 +542,22 @@ case "$1" in json_add_int "wide_tx_rate_limit" json_close_object - json_add_object "deleteScheduleLimit" - json_add_string "mac" - json_add_string "start_time" - json_add_string "end_time" - json_add_string "days" - json_close_object - - json_dump - json_cleanup - ;; + json_add_object "deleteScheduleLimit" + json_add_string "mac" + json_add_string "start_time" + json_add_string "end_time" + json_add_string "days" + json_close_object + + json_add_object "clearData" + json_close_object + + json_add_object "restartService" + json_close_object + + json_dump + json_cleanup + ;; call) case "$2" in getStatus) @@ -447,6 +585,48 @@ case "$1" in fi get_metrics "$mac" ;; + getMetricsDay) + mac="" + input="" + if read -t 1 -r input; then + : + fi + if [ -n "$input" ]; then + mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)" + [ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)" + else + [ -n "$3" ] && mac="$3" + fi + get_metrics_day "$mac" + ;; + getMetricsWeek) + mac="" + input="" + if read -t 1 -r input; then + : + fi + if [ -n "$input" ]; then + mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)" + [ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)" + else + [ -n "$3" ] && mac="$3" + fi + get_metrics_week "$mac" + ;; + getMetricsMonth) + mac="" + input="" + if read -t 1 -r input; then + : + fi + if [ -n "$input" ]; then + mac="$(echo "$input" | jsonfilter -e '$[0]' 2>/dev/null)" + [ -z "$mac" ] && mac="$(echo "$input" | jsonfilter -e '$.mac' 2>/dev/null)" + else + [ -n "$3" ] && mac="$3" + fi + get_metrics_month "$mac" + ;; setHostname) # logger "luci.bandix: setHostname called" @@ -638,6 +818,14 @@ case "$1" in make_error "No input received" fi ;; + clearData) + # logger "luci.bandix: clearData called" + clear_data + ;; + restartService) + # logger "luci.bandix: restartService called" + restart_service + ;; esac ;; esac diff --git a/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json b/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json index 7cb6cd8..453abdc 100644 --- a/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json +++ b/luci-app-bandix/root/usr/share/rpcd/acl.d/luci-app-bandix.json @@ -6,13 +6,18 @@ "luci.bandix": [ "getStatus", "getMetrics", + "getMetricsDay", + "getMetricsWeek", + "getMetricsMonth", "getConnection", "setHostname", "getDnsQueries", "getDnsStats", "getScheduleLimits", "setScheduleLimit", - "deleteScheduleLimit" + "deleteScheduleLimit", + "clearData", + "restartService" ] }, "uci": [ @@ -24,13 +29,18 @@ "luci.bandix": [ "getStatus", "getMetrics", + "getMetricsDay", + "getMetricsWeek", + "getMetricsMonth", "getConnection", "setHostname", "getDnsQueries", "getDnsStats", "getScheduleLimits", "setScheduleLimit", - "deleteScheduleLimit" + "deleteScheduleLimit", + "clearData", + "restartService" ] }, "uci": [ diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm index c8a27c2..b0787f8 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_list/node_list.htm @@ -1,7 +1,7 @@ <% local api = require "luci.passwall.api" -%> - +