Update On Mon Feb 16 19:58:17 CET 2026

This commit is contained in:
github-action[bot]
2026-02-16 19:58:18 +01:00
parent d1b46b3195
commit ed7124baba
238 changed files with 3092 additions and 913 deletions
+175 -24
View File
@@ -7,38 +7,63 @@
</p>
</header>
<section ref="section" :class="{ 'modal-card-body': true }">
<b-field :label="$tc('log.refreshInterval')">
<b-select v-model="intervalTime" @input="changeInterval">
<option
v-for="candidate in intervalCandidate"
:key="candidate"
:value="candidate"
>
{{ `${candidate} ${$tc("log.seconds")}` }}
</option>
</b-select>
</b-field>
<b-field label="Logs" style="margin-bottom: 2rem">
<div class="log-title">{{ $t("log.logsLabel") }}</div>
<div class="log-content" tabindex="0" @keydown="handleLogKeydown">
<RecycleScroller
ref="logScroller"
v-slot="{ item }"
v-slot="{ item, index }"
class="log-scroller"
:items="items"
:items="filteredItems"
:item-size="itemSize"
:grid-items="1"
:buffer="1000"
>
<hightlight-log class="text" :text="item.text"></hightlight-log>
<div class="log-row">
<span class="log-line-number">{{ index + 1 }}</span>
<hightlight-log class="text" :text="item.text"></hightlight-log>
</div>
</RecycleScroller>
</b-field>
<b-field>
<b-switch v-model="autoScoll" @input="changeScoll">
{{ $tc("log.autoScoll") }}
</b-switch>
</b-field>
</div>
<div class="log-footer">
<div class="log-footer-item">
<div class="log-footer-label">{{ $tc("log.refreshInterval") }}</div>
<div class="log-footer-control">
<b-select v-model="intervalTime" @input="changeInterval">
<option
v-for="candidate in intervalCandidate"
:key="candidate"
:value="candidate"
>
{{ `${candidate} ${$tc("log.seconds")}` }}
</option>
</b-select>
</div>
</div>
<div class="log-footer-item">
<div class="log-footer-label">{{ $tc("log.category") }}</div>
<div class="log-footer-control">
<b-select v-model="levelFilter">
<option
v-for="option in levelOptions"
:key="option.value"
:value="option.value"
>
{{ $t(option.label) }}
</option>
</b-select>
</div>
</div>
<div class="log-footer-item">
<div class="log-footer-label">{{ $tc("log.autoScoll") }}</div>
<div class="log-footer-control">
<b-switch v-model="autoScoll" @input="changeScoll" />
</div>
</div>
</div>
</section>
</div>
</template>
<script>
import HightlightLog from "@/components/highlightLog";
export default {
@@ -53,8 +78,26 @@ export default {
intervalCandidate: [2, 5, 10, 15],
itemSize: 28,
autoScoll: true,
levelFilter: "all",
levelOptions: [
{ value: "all", label: "log.categories.all" },
{ value: "error", label: "log.categories.error" },
{ value: "warn", label: "log.categories.warn" },
{ value: "info", label: "log.categories.info" },
{ value: "debug", label: "log.categories.debug" },
{ value: "trace", label: "log.categories.trace" },
{ value: "other", label: "log.categories.other" },
],
};
},
computed: {
filteredItems() {
if (this.levelFilter === "all") {
return this.items;
}
return this.items.filter((item) => item.level === this.levelFilter);
},
},
created() {
this.autoScoll = !(localStorage.getItem("log.autoScoll") === "false");
@@ -74,12 +117,63 @@ export default {
clearInterval(this.intervalId);
},
methods: {
handleLogKeydown(event) {
const scroller = this.$refs.logScroller;
const el = scroller && scroller.$el ? scroller.$el : null;
if (!el) {
return;
}
const pageStep = Math.max(1, Math.floor(el.clientHeight * 0.9));
switch (event.key) {
case "Home":
el.scrollTop = 0;
event.preventDefault();
break;
case "End":
el.scrollTop = el.scrollHeight;
event.preventDefault();
break;
case "PageUp":
el.scrollTop = Math.max(0, el.scrollTop - pageStep);
event.preventDefault();
break;
case "PageDown":
el.scrollTop = Math.min(el.scrollHeight, el.scrollTop + pageStep);
event.preventDefault();
break;
default:
break;
}
},
detectLevel(text) {
const lower = text.toLowerCase();
if (lower.includes("[e]") || lower.includes(" error ")) {
return "error";
}
if (lower.includes("[w]") || lower.includes(" warn")) {
return "warn";
}
if (lower.includes("[d]") || lower.includes(" debug")) {
return "debug";
}
if (lower.includes("[t]") || lower.includes(" trace")) {
return "trace";
}
if (lower.includes("[i]") || lower.includes(" info")) {
return "info";
}
return "other";
},
updateLog(logs) {
if (logs.data.length && logs.data.length !== 0) {
const baseIndex = this.items.length;
const items = logs.data
.split("\n")
.map((x, i) => ({ text: x, id: baseIndex + i }));
.map((x, i) => ({
text: x,
id: baseIndex + i,
level: this.detectLevel(x),
}));
if (this.endOfLine) {
this.items = this.items.concat(items);
} else {
@@ -88,8 +182,8 @@ export default {
}
this.endOfLine = items[items.length - 1].text.endsWith("\n");
this.currentSkip += new Blob([logs.data]).size;
if (this.autoScoll) {
this.$refs.logScroller.scrollToItem(this.items.length - 1);
if (this.autoScoll && this.filteredItems.length > 0) {
this.$refs.logScroller.scrollToItem(this.filteredItems.length - 1);
}
}
},
@@ -109,13 +203,70 @@ export default {
},
};
</script>
<style scoped>
.text {
font-size: 16px;
line-height: 30px;
white-space: nowrap;
}
.log-title {
font-weight: 600;
margin-bottom: 0.75rem;
}
.log-content {
margin-bottom: 1.5rem;
}
.log-row {
display: flex;
align-items: center;
gap: 12px;
}
.log-line-number {
min-width: 3.5rem;
text-align: right;
color: #9aa4b2;
font-size: 14px;
user-select: none;
}
.log-footer {
display: flex;
align-items: flex-start;
justify-content: flex-start;
gap: 1.5rem;
}
.log-footer-item {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0.5rem;
min-width: 160px;
}
.log-footer-label {
font-weight: 600;
min-height: 1.5rem;
}
.log-footer-control ::v-deep .control,
.log-footer-control ::v-deep .select,
.log-footer-control ::v-deep select {
width: 100%;
}
.log-footer-control ::v-deep .control {
min-height: 40px;
display: flex;
align-items: center;
}
</style>
<style lang="scss">
.log-scroller {
height: 50vh;
+42 -2
View File
@@ -79,7 +79,7 @@
</template>
</b-field>
<b-field v-show="transparentType == 'gvisor_tun' || transparentType == 'system_tun'" label-position="on-border">
<b-field v-show="tunEnabled" label-position="on-border">
<template slot="label">
{{ $t("setting.tunMode") }}
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.tunMode')" position="is-right">
@@ -93,7 +93,7 @@
</b-select>
</b-field>
<b-field v-show="transparentType == 'gvisor_tun' || transparentType == 'system_tun'" label-position="on-border">
<b-field v-show="tunEnabled" label-position="on-border">
<template slot="label">
{{ $t("setting.tunIPv6") }}
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.tunIPv6')" position="is-right">
@@ -107,6 +107,22 @@
</b-select>
</b-field>
<b-field v-show="tunEnabled" label-position="on-border">
<template slot="label">StrictRoute</template>
<b-select v-model="tunStrictRoute" expanded>
<option :value="true">{{ $t("setting.options.enabled") }}</option>
<option :value="false">{{ $t("setting.options.disabled") }}</option>
</b-select>
</b-field>
<b-field v-show="tunEnabled" label-position="on-border">
<template slot="label">AutoRoute</template>
<b-select v-model="tunAutoRoute" expanded>
<option :value="true">{{ $t("setting.options.enabled") }}</option>
<option :value="false">{{ $t("setting.options.disabled") }}</option>
</b-select>
</b-field>
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.pacMode") }}
@@ -201,6 +217,19 @@
</b-select>
</b-field>
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.logLevel") }}
</template>
<b-select v-model="logLevel" expanded>
<option value="trace">{{ $t("setting.options.trace") }}</option>
<option value="debug">{{ $t("setting.options.debug") }}</option>
<option value="info">{{ $t("setting.options.info") }}</option>
<option value="warn">{{ $t("setting.options.warn") }}</option>
<option value="error">{{ $t("setting.options.error") }}</option>
</b-select>
</b-field>
<b-field label-position="on-border">
<template slot="label">
{{ $t("setting.inboundSniffing") }}
@@ -323,12 +352,15 @@ export default {
data: () => ({
proxyModeWhenSubscribe: "direct",
tcpFastOpen: "default",
logLevel: "info",
muxOn: "no",
mux: "8",
transparent: "close",
transparentType: "tproxy",
tunFakeIP: true,
tunIPv6: false,
tunStrictRoute: false,
tunAutoRoute: true,
ipforward: false,
portSharing: false,
dnsForceMode: false,
@@ -366,6 +398,11 @@ export default {
}
return toInt(port);
},
tunEnabled() {
const isTunType =
this.transparentType === "gvisor_tun" || this.transparentType === "system_tun";
return this.transparent !== "close" && isTunType;
},
},
watch: {
antipollution(val) {
@@ -431,6 +468,7 @@ export default {
),
pacMode: this.pacMode,
tcpFastOpen: this.tcpFastOpen,
logLevel: this.logLevel,
inboundSniffing: this.inboundSniffing,
muxOn: this.muxOn,
mux: parseInt(this.mux),
@@ -438,6 +476,8 @@ export default {
transparentType: this.transparentType,
tunFakeIP: this.tunFakeIP,
tunIPv6: this.tunIPv6,
tunStrictRoute: this.tunStrictRoute,
tunAutoRoute: this.tunAutoRoute,
ipforward: this.ipforward,
portSharing: this.portSharing,
routeOnly: this.routeOnly,
+17
View File
@@ -112,6 +112,7 @@ export default {
transparentType: "Transparent Proxy/System Proxy Implementation",
tunMode: "TUN Mode",
tunIPv6: "TUN IPv6",
logLevel: "Log Level",
pacMode: "Traffic Splitting Mode of Rule Port",
preventDnsSpoofing: "Prevent DNS Spoofing",
specialMode: "Special Mode",
@@ -124,6 +125,11 @@ export default {
concurrency: "Concurrency",
inboundSniffing: "Sniffing",
options: {
trace: "Trace",
debug: "Debug",
info: "Info",
warn: "Warn",
error: "Error",
global: "Do not Split Traffic",
direct: "Direct",
pac: "Depend on Rule Port",
@@ -331,9 +337,20 @@ export default {
},
log: {
logModalTitle: "View logs",
logsLabel: "Logs",
refreshInterval: "Refresh Interval",
seconds: "seconds",
autoScoll: "Auto Scroll",
category: "Category",
categories: {
all: "All",
error: "Error",
warn: "Warn",
info: "Info",
debug: "Debug",
trace: "Trace",
other: "Other",
},
},
tproxyWhiteIpGroups: {
title: "White IP Groups",
+18
View File
@@ -104,6 +104,7 @@ export default {
setting: {
transparentProxy: "Transparent Proxy/System Proxy",
transparentType: "Transparent Proxy/System Proxy Implementation",
logLevel: "Log Level",
pacMode: "Traffic Splitting Mode of Rule Port",
preventDnsSpoofing: "جلوگیری از هک DNS",
specialMode: "حالت ویژه",
@@ -115,6 +116,11 @@ export default {
portSharingOn: "به اشتراک گذاری پورت",
concurrency: "همزمانی",
options: {
trace: "Trace",
debug: "Debug",
info: "Info",
warn: "Warn",
error: "Error",
global: "عدم تقسیم ترافیک",
direct: "Direct",
pac: "بسته به پورت تصمیم گیری شود.",
@@ -313,7 +319,19 @@ export default {
},
log: {
logModalTitle: "دیدن لاگ ها",
logsLabel: "لاگ ها",
refreshInterval: "Refresh Interval",
seconds: "ثانیه",
autoScoll: "Auto Scroll",
category: "Category",
categories: {
all: "All",
error: "Error",
warn: "Warn",
info: "Info",
debug: "Debug",
trace: "Trace",
other: "Other",
},
},
};
+17
View File
@@ -104,6 +104,7 @@ export default {
setting: {
transparentProxy: "Proxy Transparente/Proxy do Sistema",
transparentType: "Implementação do Proxy Transparente/Proxy do Sistema",
logLevel: "Nível de Log",
pacMode: "Modo de Divisão de Tráfego da Porta de Regra",
preventDnsSpoofing: "Prevenir Falsificação de DNS",
specialMode: "Modo Especial",
@@ -115,6 +116,11 @@ export default {
portSharingOn: "Compartilhamento de Porta",
concurrency: "Concorrência",
options: {
trace: "Trace",
debug: "Debug",
info: "Info",
warn: "Aviso",
error: "Erro",
global: "Não Dividir Tráfego",
direct: "Direto",
pac: "Depende da Porta de Regra",
@@ -319,8 +325,19 @@ export default {
},
log: {
logModalTitle: "Visualizar logs",
logsLabel: "Logs",
refreshInterval: "Intervalo de atualização",
seconds: "segundos",
autoScoll: "Rolagem Automática",
category: "Categoria",
categories: {
all: "Todos",
error: "Erro",
warn: "Aviso",
info: "Info",
debug: "Debug",
trace: "Trace",
other: "Outros",
},
},
};
+17
View File
@@ -107,6 +107,7 @@ export default {
setting: {
transparentProxy: "Прозрачный прокси/Системный прокси",
transparentType: "Реализация прозрачного прокси/Системного прокси",
logLevel: "Уровень журнала",
pacMode: "Режим разделения трафика на порте с правилами",
preventDnsSpoofing: "Предотвратить DNS-спуфинг",
specialMode: "Специальный режим",
@@ -119,6 +120,11 @@ export default {
concurrency: "Параллелизм",
inboundSniffing: "Сниффер",
options: {
trace: "Trace",
debug: "Debug",
info: "Info",
warn: "Warn",
error: "Error",
global: "Не разделять трафик",
direct: "Напрямую",
pac: "Зависит от порта правил",
@@ -321,9 +327,20 @@ export default {
},
log: {
logModalTitle: "Просмотр журнала",
logsLabel: "Журнал",
refreshInterval: "Интервал обновления",
seconds: "секунд",
autoScoll: "Авто-пролистывание",
category: "Категория",
categories: {
all: "Все",
error: "Ошибка",
warn: "Предупреждение",
info: "Инфо",
debug: "Debug",
trace: "Trace",
other: "Другое",
},
},
domainsExcluded: {
title: "Исключённые домены",
+17
View File
@@ -112,6 +112,7 @@ export default {
transparentType: "透明代理/系统代理实现方式",
tunMode: "TUN模式",
tunIPv6: "TUN IPv6",
logLevel: "日志等级",
pacMode: "规则端口的分流模式",
preventDnsSpoofing: "防止DNS污染",
specialMode: "特殊模式",
@@ -123,6 +124,11 @@ export default {
portSharingOn: "开启端口分享",
concurrency: "最大并发数",
options: {
trace: "跟踪",
debug: "调试",
info: "信息",
warn: "警告",
error: "错误",
global: "不进行分流",
direct: "直连模式",
pac: "跟随规则端口",
@@ -333,9 +339,20 @@ export default {
},
log: {
logModalTitle: "查看日志",
logsLabel: "日志",
refreshInterval: "刷新间隔",
seconds: "秒",
autoScoll: "自动滚动",
category: "分类",
categories: {
all: "全部",
error: "错误",
warn: "警告",
info: "信息",
debug: "调试",
trace: "跟踪",
other: "其他",
},
},
tproxyWhiteIpGroups: {