diff --git a/luci-app-bandix/Makefile b/luci-app-bandix/Makefile index 1903e55..cc9e98f 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.0 +PKG_VERSION:=0.9.1 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 6051ebe..8453edb 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 @@ -375,27 +375,27 @@ return view.extend({ .bandix-table th:nth-child(1), .bandix-table td:nth-child(1) { - width: 25%; + width: 27%; } .bandix-table th:nth-child(2), .bandix-table td:nth-child(2) { - width: 20%; + width: 22%; } .bandix-table th:nth-child(3), .bandix-table td:nth-child(3) { - width: 20%; + width: 22%; } .bandix-table th:nth-child(4), .bandix-table td:nth-child(4) { - width: 25%; + width: 12.5%; } .bandix-table th:nth-child(5), .bandix-table td:nth-child(5) { - width: 10%; + width: 16.5%; } .schedule-rules-info { @@ -1352,6 +1352,82 @@ return view.extend({ .history-tooltip .ht-kpi.up .ht-k-value { color: #f97316; } .history-tooltip .ht-divider { height: 1px; background-color: currentColor; opacity: 0.3; margin: 8px 0; } .history-tooltip .ht-section-title { font-weight: 600; font-size: 0.75rem; opacity: 0.7; margin: 4px 0 6px 0; } + + /* Schedule Rules Tooltip */ + .schedule-rules-tooltip { + position: fixed; + display: none; + width: 360px; + max-width: 90vw; + box-sizing: border-box; + padding: 12px; + z-index: 10000; + pointer-events: none; + font-size: 0.8125rem; + line-height: 1.5; + background-color: rgba(255, 255, 255, 0.98); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + color: #1f2937; + } + + @media (prefers-color-scheme: dark) { + .schedule-rules-tooltip { + background-color: rgba(30, 30, 30, 0.98); + border-color: rgba(255, 255, 255, 0.2); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); + color: #e5e7eb; + } + } + + .schedule-rules-tooltip .srt-title { + font-weight: 700; + margin-bottom: 8px; + font-size: 0.875rem; + } + + .schedule-rules-tooltip .srt-rule-item { + padding: 8px 0; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + } + + @media (prefers-color-scheme: dark) { + .schedule-rules-tooltip .srt-rule-item { + border-bottom-color: rgba(255, 255, 255, 0.15); + } + } + + .schedule-rules-tooltip .srt-rule-item:last-child { + border-bottom: none; + } + + .schedule-rules-tooltip .srt-rule-time { + font-weight: 600; + margin-bottom: 4px; + font-size: 0.75rem; + } + + .schedule-rules-tooltip .srt-rule-days { + font-size: 0.75rem; + font-weight: 500; + opacity: 0.7; + margin-bottom: 4px; + } + + .schedule-rules-tooltip .srt-rule-limits { + font-size: 0.875rem; + font-weight: 600; + opacity: 0.8; + } + + .schedule-rules-tooltip .srt-rule-limits .srt-arrow { + font-size: 0.75rem; + font-weight: bold; + } + + .schedule-rules-info { + } `); document.head.appendChild(style); @@ -1444,6 +1520,59 @@ return view.extend({ ]) ]); + // 创建全局的 Schedule Rules Tooltip 元素 + var scheduleRulesTooltip = E('div', { 'class': 'schedule-rules-tooltip', 'id': 'schedule-rules-tooltip' }); + document.body.appendChild(scheduleRulesTooltip); + + // 构建规则列表的 HTML(用于 tooltip) + function buildScheduleRulesTooltipHtml(allRules, activeRules, speedUnit) { + if (!allRules || allRules.length === 0) { + return ''; + } + + var lines = []; + lines.push('
' + _('Schedule Rules') + ' (' + allRules.length + ')
'); + + allRules.forEach(function(rule, index) { + var startTime = rule.time_slot && rule.time_slot.start ? rule.time_slot.start : ''; + var endTime = rule.time_slot && rule.time_slot.end ? rule.time_slot.end : ''; + var days = rule.time_slot && rule.time_slot.days ? rule.time_slot.days : []; + + var dayNames = { + 1: _('Mon'), + 2: _('Tue'), + 3: _('Wed'), + 4: _('Thu'), + 5: _('Fri'), + 6: _('Sat'), + 7: _('Sun') + }; + var daysText = days.length > 0 ? days.map(function(d) { return dayNames[d] || d; }).join(', ') : '-'; + + var uploadLimit = rule.wide_tx_rate_limit || 0; + var downloadLimit = rule.wide_rx_rate_limit || 0; + + // 使用 isRuleActive 函数检查规则是否激活 + var isActive = isRuleActive(rule); + + // 箭头固定颜色(橙色和青色),样式与 WAN 字段一致 + var uploadLimitText = '' + (uploadLimit > 0 ? formatByterate(uploadLimit, speedUnit) : _('Unlimited')); + var downloadLimitText = '' + (downloadLimit > 0 ? formatByterate(downloadLimit, speedUnit) : _('Unlimited')); + + var activeMark = isActive ? '' : ''; + + lines.push( + '
' + + '
' + activeMark + startTime + ' - ' + endTime + '
' + + '
' + daysText + '
' + + '
' + uploadLimitText + ' ' + downloadLimitText + '
' + + '
' + ); + }); + + return lines.join(''); + } + // 设备信息模式切换 var deviceModeButtons = view.querySelectorAll('.device-mode-btn'); @@ -2256,6 +2385,80 @@ return view.extend({ }); } + // 合并多个生效规则的限制值 + // 返回合并后的上传和下载限制(取所有规则中非零的最小值) + function mergeActiveRulesLimits(activeRules) { + if (!activeRules || activeRules.length === 0) { + return { uploadLimit: 0, downloadLimit: 0 }; + } + + var uploadLimits = []; + var downloadLimits = []; + + activeRules.forEach(function(rule) { + var uploadLimit = rule.wide_tx_rate_limit || 0; + var downloadLimit = rule.wide_rx_rate_limit || 0; + + // 只收集非零的限制值 + if (uploadLimit > 0) { + uploadLimits.push(uploadLimit); + } + if (downloadLimit > 0) { + downloadLimits.push(downloadLimit); + } + }); + + // 取最小值(如果有多个规则都有限制,取最严格的限制) + var mergedUploadLimit = uploadLimits.length > 0 ? Math.min.apply(Math, uploadLimits) : 0; + var mergedDownloadLimit = downloadLimits.length > 0 ? Math.min.apply(Math, downloadLimits) : 0; + + return { + uploadLimit: mergedUploadLimit, + downloadLimit: mergedDownloadLimit + }; + } + + // 获取多个规则的时间段显示文本 + // 如果所有规则的时间段相同,显示时间段;如果不同,显示"多个时间段" + function getTimeSlotDisplayText(activeRules) { + if (!activeRules || activeRules.length === 0) { + return ''; + } + + if (activeRules.length === 1) { + // 单个规则,直接显示时间段 + var rule = activeRules[0]; + var startTime = rule.time_slot && rule.time_slot.start ? rule.time_slot.start : ''; + var endTime = rule.time_slot && rule.time_slot.end ? rule.time_slot.end : ''; + return startTime + '-' + endTime; + } + + // 多个规则,检查时间段是否相同 + var firstRule = activeRules[0]; + var firstStartTime = firstRule.time_slot && firstRule.time_slot.start ? firstRule.time_slot.start : ''; + var firstEndTime = firstRule.time_slot && firstRule.time_slot.end ? firstRule.time_slot.end : ''; + + var allSame = true; + for (var i = 1; i < activeRules.length; i++) { + var rule = activeRules[i]; + var startTime = rule.time_slot && rule.time_slot.start ? rule.time_slot.start : ''; + var endTime = rule.time_slot && rule.time_slot.end ? rule.time_slot.end : ''; + + if (startTime !== firstStartTime || endTime !== firstEndTime) { + allSame = false; + break; + } + } + + if (allSame) { + // 所有规则时间段相同,显示时间段和规则数量 + return firstStartTime + '-' + firstEndTime + ' (' + activeRules.length + ' ' + _('rules') + ')'; + } else { + // 时间段不同,显示"多个时间段" + return _('Multiple time slots') + ' (' + activeRules.length + ' ' + _('rules') + ')'; + } + } + // 排序状态管理 var currentSortBy = localStorage.getItem('bandix_sort_by') || 'online'; // 默认按在线状态排序 var currentSortOrder = localStorage.getItem('bandix_sort_order') === 'true'; // false = 降序, true = 升序 @@ -3781,39 +3984,36 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { if (allDeviceRules.length === 0) { rulesInfo.appendChild(E('div', { 'style': 'font-size: 0.75rem; opacity: 0.6;' }, '-')); } else { - // 显示规则数量 - rulesInfo.appendChild(E('div', { - 'style': 'font-size: 0.75rem; font-weight: 600; margin-bottom: 4px;' - }, allDeviceRules.length + ' ' + (allDeviceRules.length === 1 ? _('rule') : _('rules')))); - // 显示当前生效的规则 if (activeRules.length > 0) { - var activeRule = activeRules[0]; // 显示第一个生效的规则 - var startTime = activeRule.time_slot && activeRule.time_slot.start ? activeRule.time_slot.start : ''; - var endTime = activeRule.time_slot && activeRule.time_slot.end ? activeRule.time_slot.end : ''; - - var uploadLimit = activeRule.wide_tx_rate_limit || 0; - var downloadLimit = activeRule.wide_rx_rate_limit || 0; - - // 时间段和限速值放在同一行 - var timeSlotText = startTime + '-' + endTime; - var limitsText = []; - // 即使限速是0也显示 - limitsText.push('↑' + (uploadLimit > 0 ? formatByterate(uploadLimit, speedUnit) : _('Unlimited'))); - limitsText.push('↓' + (downloadLimit > 0 ? formatByterate(downloadLimit, speedUnit) : _('Unlimited'))); + // 合并多个规则的限制值 + var mergedLimits = mergeActiveRulesLimits(activeRules); + var uploadLimit = mergedLimits.uploadLimit; + var downloadLimit = mergedLimits.downloadLimit; + // 显示规则数量 rulesInfo.appendChild(E('div', { - 'style': 'font-size: 0.75rem; color: #10b981; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;' - }, [ - E('span', {}, '● ' + timeSlotText), - E('span', { 'style': 'opacity: 0.8; font-size: 0.7rem;' }, limitsText.join(' ')) - ])); + 'style': 'font-size: 0.75rem; font-weight: 600; margin-bottom: 4px;' + }, activeRules.length + ' ' + (activeRules.length === 1 ? _('rule') : _('rules')))); - if (activeRules.length > 1) { - rulesInfo.appendChild(E('div', { - 'style': 'font-size: 0.7rem; opacity: 0.6; margin-top: 2px;' - }, '+' + (activeRules.length - 1) + ' ' + _('more'))); - } + // 显示限速值(箭头固定颜色,文字默认颜色) + var limitsContainer = E('div', { + 'style': 'font-size: 0.75rem; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;' + }); + + // 上传限速(橙色箭头) + var uploadSpan = E('span', {}); + uploadSpan.appendChild(E('span', { 'style': 'color: #f97316;' }, '↑')); + uploadSpan.appendChild(document.createTextNode(uploadLimit > 0 ? formatByterate(uploadLimit, speedUnit) : _('Unlimited'))); + limitsContainer.appendChild(uploadSpan); + + // 下载限速(青色箭头) + var downloadSpan = E('span', {}); + downloadSpan.appendChild(E('span', { 'style': 'color: #06b6d4;' }, '↓')); + downloadSpan.appendChild(document.createTextNode(downloadLimit > 0 ? formatByterate(downloadLimit, speedUnit) : _('Unlimited'))); + limitsContainer.appendChild(downloadSpan); + + rulesInfo.appendChild(limitsContainer); } else { rulesInfo.appendChild(E('div', { 'style': 'font-size: 0.75rem; opacity: 0.5;' @@ -3821,6 +4021,125 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { } } + // PC 端添加鼠标悬浮事件(显示所有规则)- 只要有规则就绑定事件 + var screenWidth = window.innerWidth || document.documentElement.clientWidth; + if (screenWidth > 768 && allDeviceRules.length > 0) { + rulesInfo.onmouseenter = function(evt) { + var tooltip = document.getElementById('schedule-rules-tooltip'); + if (!tooltip) return; + + var html = buildScheduleRulesTooltipHtml(allDeviceRules, activeRules, speedUnit); + if (!html) return; + + tooltip.innerHTML = html; + + // 应用主题颜色 + try { + var cbiSection = document.querySelector('.cbi-section'); + var targetElement = cbiSection || document.querySelector('.main') || document.body; + var computedStyle = window.getComputedStyle(targetElement); + var bgColor = computedStyle.backgroundColor; + var textColor = computedStyle.color; + + if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') { + var rgbaMatch = bgColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/); + if (rgbaMatch) { + var r = parseInt(rgbaMatch[1]); + var g = parseInt(rgbaMatch[2]); + var b = parseInt(rgbaMatch[3]); + var alpha = rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1; + if (alpha < 0.95) { + tooltip.style.backgroundColor = 'rgb(' + r + ', ' + g + ', ' + b + ')'; + } else { + tooltip.style.backgroundColor = bgColor; + } + } else { + tooltip.style.backgroundColor = bgColor; + } + } + + if (textColor && textColor !== 'rgba(0, 0, 0, 0)') { + tooltip.style.color = textColor; + } + } catch(e) {} + + // 先隐藏,设置内容后再显示以计算尺寸 + tooltip.style.display = 'block'; + tooltip.style.visibility = 'hidden'; + tooltip.style.left = '-9999px'; + tooltip.style.top = '-9999px'; + + // 强制浏览器计算尺寸 + var tw = tooltip.offsetWidth || 0; + var th = tooltip.offsetHeight || 0; + + if (tw === 0 || th === 0) { + tooltip.style.display = 'none'; + return; + } + + tooltip.style.visibility = 'visible'; + + var padding = 12; + var maxX = window.innerWidth - 4; + var maxY = window.innerHeight - 4; + + var rect = evt.currentTarget.getBoundingClientRect(); + var cx = rect.left + rect.width / 2; + var cy = rect.top + rect.height / 2; + + // 计算位置:优先显示在右侧,如果空间不足则显示在左侧 + var baseX = cx + padding; + var baseY = cy - th / 2; + + if (baseX + tw > maxX) { + baseX = cx - tw - padding; + } + + if (baseY < 4) baseY = 4; + if (baseY + th > maxY) baseY = maxY - th - 4; + + tooltip.style.left = baseX + 'px'; + tooltip.style.top = baseY + 'px'; + }; + + rulesInfo.onmouseleave = function() { + var tooltip = document.getElementById('schedule-rules-tooltip'); + if (tooltip) { + tooltip.style.display = 'none'; + tooltip.style.visibility = 'visible'; + } + }; + + rulesInfo.onmousemove = function(evt) { + var tooltip = document.getElementById('schedule-rules-tooltip'); + if (!tooltip || tooltip.style.display === 'none') return; + + var tw = tooltip.offsetWidth || 0; + var th = tooltip.offsetHeight || 0; + var padding = 12; + var maxX = window.innerWidth - 4; + var maxY = window.innerHeight - 4; + + var rect = evt.currentTarget.getBoundingClientRect(); + var cx = rect.left + rect.width / 2; + var cy = rect.top + rect.height / 2; + + var baseX = cx + padding; + var baseY = cy - th / 2; + + if (baseX + tw > maxX) { + baseX = cx - tw - padding; + } + + if (baseY < 4) baseY = 4; + if (baseY + th > maxY) baseY = maxY - th - 4; + + tooltip.style.left = baseX + 'px'; + tooltip.style.top = baseY + 'px'; + }; + } + return E('td', {}, rulesInfo); })(), @@ -3889,41 +4208,25 @@ function downsampleForMobile(data, labels, upSeries, downSeries, maxPoints) { var rulesContent = E('div', { 'class': 'device-card-rules-content' }); - // 规则数量 - rulesContent.appendChild(E('div', { - 'class': 'device-card-rules-count' - }, allDeviceRules.length + ' ' + (allDeviceRules.length === 1 ? _('rule') : _('rules')))); - if (activeRules.length > 0) { - var activeRule = activeRules[0]; - var startTime = activeRule.time_slot && activeRule.time_slot.start ? activeRule.time_slot.start : ''; - var endTime = activeRule.time_slot && activeRule.time_slot.end ? activeRule.time_slot.end : ''; + // 合并多个规则的限制值 + var mergedLimits = mergeActiveRulesLimits(activeRules); + var uploadLimit = mergedLimits.uploadLimit; + var downloadLimit = mergedLimits.downloadLimit; - var uploadLimit = activeRule.wide_tx_rate_limit || 0; - var downloadLimit = activeRule.wide_rx_rate_limit || 0; + // 显示规则数量 + rulesContent.appendChild(E('div', { + 'class': 'device-card-rules-count' + }, activeRules.length + ' ' + (activeRules.length === 1 ? _('rule') : _('rules')))); - // 时间段和限速值放在同一行 - var timeSlotText = startTime + '-' + endTime; + // 显示限速值 var limitsText = []; - // 即使限速是0也显示 limitsText.push('↑' + (uploadLimit > 0 ? formatByterate(uploadLimit, speedUnit) : _('Unlimited'))); limitsText.push('↓' + (downloadLimit > 0 ? formatByterate(downloadLimit, speedUnit) : _('Unlimited'))); - // 生效规则的时间段和限速值 - var activeTimeInfo = E('div', { + rulesContent.appendChild(E('div', { 'class': 'device-card-rules-active-time' - }, [ - E('span', {}, '● ' + timeSlotText), - E('span', { 'style': 'opacity: 0.8; font-size: 0.7rem; margin-left: 8px;' }, limitsText.join(' ')) - ]); - - if (activeRules.length > 1) { - activeTimeInfo.appendChild(E('div', { - 'class': 'device-card-rules-more' - }, '+' + (activeRules.length - 1) + ' ' + _('more'))); - } - - rulesContent.appendChild(activeTimeInfo); + }, limitsText.join(' '))); } else { rulesContent.appendChild(E('div', { 'class': 'device-card-rules-inactive' diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index a73b113..e46862f 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -83,6 +83,7 @@ function index() entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true entry({"admin", "services", appname, "get_node"}, call("get_node")).leaf = true + entry({"admin", "services", appname, "save_node_order"}, call("save_node_order")).leaf = true entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true entry({"admin", "services", appname, "subscribe_del_node"}, call("subscribe_del_node")).leaf = true entry({"admin", "services", appname, "subscribe_del_all"}, call("subscribe_del_all")).leaf = true @@ -591,13 +592,12 @@ function delete_select_nodes() end end - function get_node() local id = http.formvalue("id") local result = {} local show_node_info = api.uci_get_type("global_other", "show_node_info", "0") - function add_is_ipv6_key(o) + local function add_is_ipv6_key(o) if o and o.address and show_node_info == "1" then local f = api.get_ipv6_full(o.address) if f ~= "" then @@ -611,14 +611,35 @@ function get_node() result = uci:get_all(appname, id) add_is_ipv6_key(result) else + local default_nodes = {} + local other_nodes = {} uci:foreach(appname, "nodes", function(t) add_is_ipv6_key(t) - result[#result + 1] = t + if not t.group or t.group == "" then + default_nodes[#default_nodes + 1] = t + else + other_nodes[#other_nodes + 1] = t + end end) + for i = 1, #default_nodes do result[#result + 1] = default_nodes[i] end + for i = 1, #other_nodes do result[#result + 1] = other_nodes[i] end end http_write_json(result) end +function save_node_order() + local ids = http.formvalue("ids") or "" + local new_order = {} + for id in ids:gmatch("([^,]+)") do + new_order[#new_order + 1] = id + end + for idx, name in ipairs(new_order) do + luci.sys.call(string.format("uci -q reorder %s.%s=%d", appname, name, idx - 1)) + end + api.sh_uci_commit(appname) + http_write_json({ status = "ok" }) +end + function update_rules() local update = http.formvalue("update") luci.sys.call("lua /usr/share/passwall/rule_update.lua log '" .. update .. "' > /dev/null 2>&1 &") 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 79b5c51..f8f16e7 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 @@ -210,19 +210,28 @@ table td, .table .td { document.getElementById("set_node_name").innerHTML = ""; } - function _cbi_row_top(id) { - //此函数已经损坏,等待修复或其他解决方案。 - var dom = document.getElementById("cbi-passwall-" + id); - if (dom) { - var trs = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row"); - if (trs && trs.length > 0) { - for (var i = 0; i < trs.length; i++) { - var up = dom.getElementsByClassName("cbi-button-up"); - if (up) { - cbi_row_swap(up[0], true, 'cbi.sts.passwall.nodes'); - } - } + function row_swap(btn, up) { + const row = btn.closest("tr"); + if (!row) return; + const parent = row.parentNode; + if (up) { + const prev = row.previousElementSibling; + if (prev && !prev.classList.contains("cbi-section-table-titles")) { + parent.insertBefore(row, prev); } + } else { + const next = row.nextElementSibling; + if (next) parent.insertBefore(next, row); + } + } + + function row_top(btn) { + const row = btn.closest("tr"); + if (!row) return; + const parent = row.parentNode; + let firstDataRow = parent.querySelector("tr:not(.cbi-section-table-titles)"); + if (firstDataRow && firstDataRow !== row) { + parent.insertBefore(row, firstDataRow); } } @@ -305,6 +314,39 @@ table td, .table .td { return { address: address, port: port }; } + function save_current_page_order(group) { + var table = document.getElementById("cbi-passwall-nodes-" + group + "-table"); + if (!table) { + alert("<%:No table!%>"); + return; + } + var rows = table.querySelectorAll("tr.cbi-section-table-row"); + if (!rows || rows.length === 0) { + alert("<%:No nodes!%>"); + return; + } + var btn = document.getElementById("save_order_btn_" + group); + if (btn) btn.disabled = true; + var ids = []; + rows.forEach(function(row) { + var id = row.id.replace("cbi-passwall-", ""); + ids.push(id); + }); + XHR.get('<%=api.url("save_node_order")%>', { + group: group, + ids: ids.join(",") + }, + function(x, result) { + if (btn) btn.disabled = false; + if (x && x.status === 200) { + alert("<%:Saved current page order successfully.%>"); + } else { + alert("<%:Save failed!%>"); + } + } + ); + } + //获取当前使用的节点 function get_now_use_node() { XHR.get('<%=api.url("get_now_use_node")%>', null, @@ -522,6 +564,7 @@ table td, .table .td {
+
@@ -537,11 +580,12 @@ table td, .table .td { {{url_test}}
- - + + + /{{id}}'" alt="<%:Edit%>" title="<%:Edit%>">
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 5469b5a..f846428 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -421,6 +421,12 @@ msgstr "节点备注" msgid "Add Mode" msgstr "添加方式" +msgid "Save Order" +msgstr "保存当前顺序" + +msgid "Saved current page order successfully." +msgstr "保存当前页面顺序成功。" + msgid "Type" msgstr "类型" diff --git a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index cf7c84d..d6e9c10 100755 --- a/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -760,13 +760,16 @@ local function processData(szType, content) -- 未指定peer(sni)默认使用remote addr result.tls_host = params.peer or params.sni end - if params.allowInsecure then + params.allowinsecure = params.allowinsecure or params.insecure + if params.allowinsecure then -- 处理 insecure 参数 if params.allowinsecure == "1" or params.allowinsecure == "0" then - result.insecure = params.allowInsecure + result.insecure = params.allowinsecure else result.insecure = string.lower(params.allowinsecure) == "true" and "1" or "0" end + else + result.insecure = "0" end if params.tfo then -- 处理 fast open 参数