mirror of
https://github.com/bolucat/Archive.git
synced 2025-12-24 13:28:37 +08:00
Update On Thu Nov 6 19:42:18 CET 2025
This commit is contained in:
@@ -3,66 +3,37 @@
|
||||
<b-navbar ref="navs" fixed-top shadow type="is-light">
|
||||
<template slot="brand">
|
||||
<b-navbar-item href="/">
|
||||
<img
|
||||
src="@/assets/img/logo2.png"
|
||||
alt="v2rayA"
|
||||
class="logo no-select"
|
||||
/>
|
||||
<img src="@/assets/img/logo2.png" alt="v2rayA" class="logo no-select" />
|
||||
</b-navbar-item>
|
||||
<b-navbar-item tag="div">
|
||||
<b-tag
|
||||
id="statusTag"
|
||||
class="pointerTag"
|
||||
:type="statusMap[runningState.running]"
|
||||
@mouseenter.native="handleOnStatusMouseEnter"
|
||||
@mouseleave.native="handleOnStatusMouseLeave"
|
||||
@click.native="handleClickStatus"
|
||||
>{{ coverStatusText ? coverStatusText : runningState.running }}
|
||||
<b-tag id="statusTag" class="pointerTag" :type="statusMap[runningState.running]"
|
||||
@mouseenter.native="handleOnStatusMouseEnter" @mouseleave.native="handleOnStatusMouseLeave"
|
||||
@click.native="handleClickStatus">{{ coverStatusText ? coverStatusText : runningState.running }}
|
||||
</b-tag>
|
||||
</b-navbar-item>
|
||||
<b-navbar-item tag="div">
|
||||
<b-dropdown
|
||||
v-if="updateOutboundDropdown"
|
||||
:triggers="isMobile ? ['click'] : ['click', 'hover']"
|
||||
aria-role="list"
|
||||
:close-on-click="false"
|
||||
@mouseenter.native="handleOutboundDropdownActiveChange"
|
||||
@active-change="handleOutboundDropdownActiveChange"
|
||||
>
|
||||
<b-dropdown v-if="updateOutboundDropdown" :triggers="isMobile ? ['click'] : ['click', 'hover']"
|
||||
aria-role="list" :close-on-click="false" @mouseenter.native="handleOutboundDropdownActiveChange"
|
||||
@active-change="handleOutboundDropdownActiveChange">
|
||||
<template #trigger>
|
||||
<b-tag class="pointerTag" type="is-info" icon-right="menu-down"
|
||||
>{{ outboundName.toUpperCase() }}
|
||||
<b-tag class="pointerTag" type="is-info" icon-right="menu-down">{{ outboundName.toUpperCase() }}
|
||||
</b-tag>
|
||||
</template>
|
||||
|
||||
<b-dropdown-item
|
||||
v-for="outbound in outbounds"
|
||||
:key="outbound"
|
||||
aria-role="listitem"
|
||||
<b-dropdown-item v-for="outbound in outbounds" :key="outbound" aria-role="listitem"
|
||||
class="is-flex padding-right-1rem justify-content-space-between outbound-dropdown"
|
||||
@mouseenter.native="handleOnOutboundMouseEnter(outbound)"
|
||||
@mouseleave.native="handleOnOutboundMouseLeave"
|
||||
@click="outboundName = outbound"
|
||||
><p class="is-relative is-fullwidth">
|
||||
@mouseenter.native="handleOnOutboundMouseEnter(outbound)" @mouseleave.native="handleOnOutboundMouseLeave"
|
||||
@click="outboundName = outbound">
|
||||
<p class="is-relative is-fullwidth">
|
||||
<span>{{ outboundNameDecorator(outbound) }}</span>
|
||||
<span>
|
||||
<i
|
||||
v-show="isMobile || outboundDropdownHover[outbound]"
|
||||
class="iconfont icon-setting outbound-setting"
|
||||
@click="handleClickOutboundSetting($event, outbound)"
|
||||
></i
|
||||
></span></p
|
||||
></b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
aria-role="listitem"
|
||||
class="is-flex padding-right-1rem"
|
||||
separator
|
||||
></b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
aria-role="listitem"
|
||||
class="is-flex padding-right-1rem"
|
||||
@click="handleAddOutbound"
|
||||
>{{ $t("operations.addOutbound") }}
|
||||
<i v-show="isMobile || outboundDropdownHover[outbound]" class="iconfont icon-setting outbound-setting"
|
||||
@click="handleClickOutboundSetting($event, outbound)"></i></span>
|
||||
</p>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item aria-role="listitem" class="is-flex padding-right-1rem" separator></b-dropdown-item>
|
||||
<b-dropdown-item aria-role="listitem" class="is-flex padding-right-1rem" @click="handleAddOutbound">{{
|
||||
$t("operations.addOutbound") }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</b-navbar-item>
|
||||
@@ -86,74 +57,34 @@
|
||||
<i class="iconfont icon-info" style="font-size: 1.25em"></i>
|
||||
{{ $t("common.log") }}
|
||||
</b-navbar-item>
|
||||
<b-dropdown
|
||||
position="is-bottom-left"
|
||||
aria-role="menu"
|
||||
style="margin-right: 10px"
|
||||
class="menudropdown"
|
||||
>
|
||||
<b-dropdown position="is-bottom-left" aria-role="menu" style="margin-right: 10px" class="menudropdown">
|
||||
<a slot="trigger" class="navbar-item" role="button">
|
||||
<span class="no-select">{{ username }}</span>
|
||||
<i
|
||||
class="iconfont icon-caret-down"
|
||||
style="position: relative; top: 1px; left: 2px"
|
||||
></i>
|
||||
<i class="iconfont icon-caret-down" style="position: relative; top: 1px; left: 2px"></i>
|
||||
</a>
|
||||
<b-dropdown-item
|
||||
custom
|
||||
aria-role="menuitem"
|
||||
v-html="$t('common.loggedAs', { username })"
|
||||
>
|
||||
<b-dropdown-item custom aria-role="menuitem" v-html="$t('common.loggedAs', { username })">
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
custom
|
||||
aria-role="menuitem"
|
||||
class="is-flex"
|
||||
style="
|
||||
<b-dropdown-item custom aria-role="menuitem" class="is-flex" style="
|
||||
box-sizing: content-box;
|
||||
height: 16px;
|
||||
width: 60px;
|
||||
justify-content: space-between;
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-for="lang of langs"
|
||||
:key="lang.flag"
|
||||
:src="require(`@/assets/img/flags/flag_${lang.flag}.svg`)"
|
||||
:alt="lang.alt"
|
||||
style="height: 100%; flex-shrink: 0; cursor: pointer"
|
||||
@click="handleClickLang(lang.flag)"
|
||||
/>
|
||||
">
|
||||
<img v-for="lang of langs" :key="lang.flag" :src="require(`@/assets/img/flags/flag_${lang.flag}.svg`)"
|
||||
:alt="lang.alt" style="height: 100%; flex-shrink: 0; cursor: pointer"
|
||||
@click="handleClickLang(lang.flag)" />
|
||||
</b-dropdown-item>
|
||||
<hr class="dropdown-divider" />
|
||||
<b-dropdown-item
|
||||
value="logout"
|
||||
aria-role="menuitem"
|
||||
class="no-select"
|
||||
@click="handleClickLogout"
|
||||
>
|
||||
<i
|
||||
class="iconfont icon-logout"
|
||||
style="position: relative; top: 1px"
|
||||
></i>
|
||||
<b-dropdown-item value="logout" aria-role="menuitem" class="no-select" @click="handleClickLogout">
|
||||
<i class="iconfont icon-logout" style="position: relative; top: 1px"></i>
|
||||
{{ $t("operations.logout") }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</template>
|
||||
</b-navbar>
|
||||
<node
|
||||
v-model="runningState"
|
||||
:outbound="outboundName"
|
||||
:observatory="observatory"
|
||||
/>
|
||||
<b-modal
|
||||
:active.sync="showCustomPorts"
|
||||
has-modal-card
|
||||
trap-focus
|
||||
aria-role="dialog"
|
||||
aria-modal
|
||||
class="modal-custom-ports"
|
||||
>
|
||||
<node v-model="runningState" :outbound="outboundName" :observatory="observatory" />
|
||||
<b-modal :active.sync="showCustomPorts" has-modal-card trap-focus aria-role="dialog" aria-modal
|
||||
class="modal-custom-ports">
|
||||
<ModalCustomAddress @close="showCustomPorts = false" />
|
||||
</b-modal>
|
||||
<div id="login"></div>
|
||||
@@ -297,9 +228,8 @@ export default {
|
||||
if (u.protocol === "https") {
|
||||
protocol = "wss";
|
||||
}
|
||||
url = `${protocol}://${u.host}:${
|
||||
u.port
|
||||
}/api/message?Authorization=${encodeURIComponent(localStorage["token"])}`;
|
||||
url = `${protocol}://${u.host}:${u.port
|
||||
}/api/message?Authorization=${encodeURIComponent(localStorage["token"])}`;
|
||||
if (this.ws) {
|
||||
// console.log("ws close");
|
||||
this.ws.close();
|
||||
@@ -343,9 +273,8 @@ export default {
|
||||
if (
|
||||
typeof this.runningState.outboundToServerName[outbound] === "number"
|
||||
) {
|
||||
return `${outbound} - ${this.$t("common.loadBalance")} (${
|
||||
this.runningState.outboundToServerName[outbound]
|
||||
})`;
|
||||
return `${outbound} - ${this.$t("common.loadBalance")} (${this.runningState.outboundToServerName[outbound]
|
||||
})`;
|
||||
} else {
|
||||
return `${outbound} - ${this.runningState.outboundToServerName[outbound]}`;
|
||||
}
|
||||
@@ -519,6 +448,7 @@ export default {
|
||||
handleClickStatus() {
|
||||
if (this.runningState.running === this.$t("common.notRunning")) {
|
||||
let cancel;
|
||||
let loading = this.$buefy.loading.open();
|
||||
waitingConnected(
|
||||
this.$axios({
|
||||
url: apiRoot + "/v2ray",
|
||||
@@ -541,6 +471,8 @@ export default {
|
||||
queue: false,
|
||||
});
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close();
|
||||
}),
|
||||
3 * 1000,
|
||||
cancel
|
||||
|
||||
@@ -4,52 +4,26 @@
|
||||
<p class="modal-card-title">{{ $t("common.setting") }}</p>
|
||||
</header>
|
||||
<section class="modal-card-body rules">
|
||||
<b-field
|
||||
label="GFWList"
|
||||
horizontal
|
||||
custom-class="modal-setting-label"
|
||||
style="position: relative"
|
||||
><span>{{ $t("common.latest") }}:</span>
|
||||
<a
|
||||
href="https://github.com/v2rayA/dist-v2ray-rules-dat/releases"
|
||||
target="_blank"
|
||||
class="is-link"
|
||||
>{{ remoteGFWListVersion }}</a
|
||||
><span>{{ $t("common.local") }}:</span>
|
||||
<b-tooltip
|
||||
v-if="dayjs(localGFWListVersion).isAfter(dayjs(remoteGFWListVersion))"
|
||||
:label="$t('setting.messages.gfwlist')"
|
||||
position="is-bottom"
|
||||
type="is-danger"
|
||||
dashed
|
||||
multilined
|
||||
animated
|
||||
>
|
||||
<b-field label="GFWList" horizontal custom-class="modal-setting-label" style="position: relative"><span>{{
|
||||
$t("common.latest") }}:</span>
|
||||
<a href="https://github.com/v2rayA/dist-v2ray-rules-dat/releases" target="_blank" class="is-link">{{
|
||||
remoteGFWListVersion }}</a><span>{{ $t("common.local") }}:</span>
|
||||
<b-tooltip v-if="dayjs(localGFWListVersion).isAfter(dayjs(remoteGFWListVersion))"
|
||||
:label="$t('setting.messages.gfwlist')" position="is-bottom" type="is-danger" dashed multilined animated>
|
||||
{{ localGFWListVersion ? localGFWListVersion : $t("common.none") }}
|
||||
</b-tooltip>
|
||||
<span v-else>{{ localGFWListVersion ? localGFWListVersion : $t("common.none") }}</span>
|
||||
<b-button
|
||||
size="is-small"
|
||||
style="position: relative; top: -2px; text-decoration: none; font-weight: bold"
|
||||
@click="handleClickUpdateGFWList"
|
||||
>{{ $t("operations.update") }}
|
||||
<b-button size="is-small" style="position: relative; top: -2px; text-decoration: none; font-weight: bold"
|
||||
@click="handleClickUpdateGFWList">{{ $t("operations.update") }}
|
||||
</b-button>
|
||||
</b-field>
|
||||
<hr class="dropdown-divider" style="margin: 1.25rem 0 1.25rem" />
|
||||
<b-field label-position="on-border" class="with-icon-alert">
|
||||
<template slot="label">
|
||||
{{ $t("setting.transparentProxy") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.transparentProxy')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.transparentProxy')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="transparent" expanded>
|
||||
@@ -69,59 +43,48 @@
|
||||
{{ $t("setting.options.sameAsPacMode") }}
|
||||
</option>
|
||||
</b-select>
|
||||
<b-checkbox-button
|
||||
v-show="!lite"
|
||||
v-model="ipforward"
|
||||
:native-value="true"
|
||||
style="position: relative; left: -1px"
|
||||
>{{ $t("setting.ipForwardOn") }}
|
||||
<b-checkbox-button v-show="!lite" v-model="ipforward" :native-value="true"
|
||||
style="position: relative; left: -1px">{{
|
||||
$t("setting.ipForwardOn") }}
|
||||
</b-checkbox-button>
|
||||
<b-checkbox-button
|
||||
v-model="portSharing"
|
||||
:native-value="true"
|
||||
style="position: relative; left: -1px"
|
||||
>{{ $t("setting.portSharingOn") }}
|
||||
<b-checkbox-button v-model="portSharing" :native-value="true" style="position: relative; left: -1px">{{
|
||||
$t("setting.portSharingOn") }}
|
||||
</b-checkbox-button>
|
||||
</b-field>
|
||||
|
||||
<b-field v-show="transparent !== 'close'" label-position="on-border">
|
||||
<template slot="label">
|
||||
{{ $t("setting.transparentType") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
multilined
|
||||
:label="$t('setting.messages.transparentType')"
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.transparentType')" position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="transparentType" expanded class="left-border">
|
||||
<b-select v-model="transparentType" expanded>
|
||||
<option v-show="!lite" value="redirect">redirect</option>
|
||||
<option v-show="!lite" value="tproxy">tproxy</option>
|
||||
<option v-show="!lite" value="gvisor_tun">gvisor tun</option>
|
||||
<option v-show="!lite" value="system_tun">system tun</option>
|
||||
<option value="system_proxy">system proxy</option>
|
||||
</b-select>
|
||||
|
||||
<template v-if="transparentType == 'tproxy'">
|
||||
<b-button style="
|
||||
margin-left: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
" outlined @click="handleClickTproxyWhiteIpGroups">{{ $t("operations.tproxyWhiteIpGroups") }}
|
||||
</b-button>
|
||||
</template>
|
||||
</b-field>
|
||||
|
||||
<b-field label-position="on-border">
|
||||
<template slot="label">
|
||||
{{ $t("setting.pacMode") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.pacMode')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.pacMode')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="pacMode" expanded style="flex-shrink: 0">
|
||||
@@ -135,30 +98,21 @@
|
||||
<option value="routingA">RoutingA</option>
|
||||
</b-select>
|
||||
<template v-if="pacMode === 'custom'">
|
||||
<b-button
|
||||
type="is-primary"
|
||||
style="
|
||||
<b-button type="is-primary" style="
|
||||
margin-left: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
"
|
||||
outlined
|
||||
@click="handleClickConfigurePac"
|
||||
>{{ $t("operations.configure") }}
|
||||
" outlined @click="handleClickConfigurePac">{{ $t("operations.configure") }}
|
||||
</b-button>
|
||||
</template>
|
||||
<template v-if="pacMode === 'routingA'">
|
||||
<b-button
|
||||
style="
|
||||
<b-button style="
|
||||
margin-left: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
"
|
||||
outlined
|
||||
@click="handleClickConfigureRoutingA"
|
||||
>{{ $t("operations.configure") }}
|
||||
" outlined @click="handleClickConfigureRoutingA">{{ $t("operations.configure") }}
|
||||
</b-button>
|
||||
</template>
|
||||
<p></p>
|
||||
@@ -166,17 +120,9 @@
|
||||
<b-field label-position="on-border">
|
||||
<template slot="label">
|
||||
{{ $t("setting.preventDnsSpoofing") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.preventDnsSpoofing')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.preventDnsSpoofing')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="antipollution" expanded class="left-border">
|
||||
@@ -190,14 +136,10 @@
|
||||
<option value="doh">{{ $t("setting.options.doh") }}</option>
|
||||
<option value="advanced">{{ $t("setting.options.advanced") }}</option>
|
||||
</b-select>
|
||||
<b-button
|
||||
v-if="antipollution === 'advanced'"
|
||||
:class="{
|
||||
'right-extra-button': antipollution === 'closed',
|
||||
'no-border-radius': antipollution !== 'closed',
|
||||
}"
|
||||
@click="handleClickDnsSetting"
|
||||
>
|
||||
<b-button v-if="antipollution === 'advanced'" :class="{
|
||||
'right-extra-button': antipollution === 'closed',
|
||||
'no-border-radius': antipollution !== 'closed',
|
||||
}" @click="handleClickDnsSetting">
|
||||
{{ $t("operations.configure") }}
|
||||
</b-button>
|
||||
<p></p>
|
||||
@@ -205,17 +147,9 @@
|
||||
<b-field v-show="showSpecialMode" label-position="on-border">
|
||||
<template slot="label">
|
||||
{{ $t("setting.specialMode") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
multilined
|
||||
:label="$t('setting.messages.specialMode')"
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" multilined :label="$t('setting.messages.specialMode')" position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="specialMode" expanded class="left-border">
|
||||
@@ -227,17 +161,9 @@
|
||||
<b-field label-position="on-border">
|
||||
<template slot="label">
|
||||
TCPFastOpen
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.tcpFastOpen')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.tcpFastOpen')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="tcpFastOpen" expanded>
|
||||
@@ -246,20 +172,13 @@
|
||||
<option value="no">{{ $t("setting.options.off") }}</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<b-field label-position="on-border">
|
||||
<template slot="label">
|
||||
{{ $t("setting.inboundSniffing") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.inboundSniffing')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.inboundSniffing')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="inboundSniffing" expanded>
|
||||
@@ -268,58 +187,36 @@
|
||||
<option value="http,tls,quic">Http + TLS + Quic</option>
|
||||
</b-select>
|
||||
<template v-if="inboundSniffing != 'disable'">
|
||||
<b-button
|
||||
type="is-primary"
|
||||
style="
|
||||
<b-button style="
|
||||
margin-left: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-radius: 0px;
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
"
|
||||
outlined
|
||||
@click="handleClickDomainsExcluded"
|
||||
>{{ $t("operations.domainsExcluded") }}
|
||||
" outlined @click="handleClickDomainsExcluded">{{ $t("operations.domainsExcluded") }}
|
||||
</b-button>
|
||||
<b-checkbox-button v-model="routeOnly" :native-value="true" style="position: relative; left: -1px;">
|
||||
RouteOnly
|
||||
</b-checkbox-button>
|
||||
</template>
|
||||
</b-field>
|
||||
|
||||
<b-field label-position="on-border" class="with-icon-alert">
|
||||
<template slot="label">
|
||||
{{ $t("setting.mux") }}
|
||||
<b-tooltip
|
||||
type="is-dark"
|
||||
:label="$t('setting.messages.mux')"
|
||||
multilined
|
||||
position="is-right"
|
||||
>
|
||||
<b-icon
|
||||
size="is-small"
|
||||
icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal"
|
||||
/>
|
||||
<b-tooltip type="is-dark" :label="$t('setting.messages.mux')" multilined position="is-right">
|
||||
<b-icon size="is-small" icon=" iconfont icon-help-circle-outline"
|
||||
style="position: relative; top: 2px; right: 3px; font-weight: normal" />
|
||||
</b-tooltip>
|
||||
</template>
|
||||
<b-select v-model="muxOn" expanded style="flex: 1">
|
||||
<option value="no">{{ $t("setting.options.off") }}</option>
|
||||
<option value="yes">{{ $t("setting.options.on") }}</option>
|
||||
</b-select>
|
||||
<cus-b-input
|
||||
v-if="muxOn === 'yes'"
|
||||
ref="muxinput"
|
||||
v-model="mux"
|
||||
:placeholder="$t('setting.concurrency')"
|
||||
custom-class="no-shadow"
|
||||
type="number"
|
||||
min="1"
|
||||
max="1024"
|
||||
validation-icon=" iconfont icon-alert"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<cus-b-input v-if="muxOn === 'yes'" ref="muxinput" v-model="mux" :placeholder="$t('setting.concurrency')"
|
||||
custom-class="no-shadow" type="number" min="1" max="1024" validation-icon=" iconfont icon-alert"
|
||||
style="flex: 1" />
|
||||
</b-field>
|
||||
<b-field
|
||||
v-show="pacMode === 'gfwlist' || transparent === 'gfwlist'"
|
||||
:label="$t('setting.autoUpdateGfwlist')"
|
||||
label-position="on-border"
|
||||
>
|
||||
<b-field v-show="pacMode === 'gfwlist' || transparent === 'gfwlist'" :label="$t('setting.autoUpdateGfwlist')"
|
||||
label-position="on-border">
|
||||
<b-select v-model="pacAutoUpdateMode" expanded>
|
||||
<option value="none">{{ $t("setting.options.off") }}</option>
|
||||
<option value="auto_update">
|
||||
@@ -329,16 +226,9 @@
|
||||
{{ $t("setting.options.updateGfwlistAtIntervals") }}
|
||||
</option>
|
||||
</b-select>
|
||||
<cus-b-input
|
||||
v-if="pacAutoUpdateMode === 'auto_update_at_intervals'"
|
||||
ref="autoUpdatePacInput"
|
||||
v-model="pacAutoUpdateIntervalHour"
|
||||
custom-class="no-shadow"
|
||||
type="number"
|
||||
min="1"
|
||||
validation-icon=" iconfont icon-alert"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<cus-b-input v-if="pacAutoUpdateMode === 'auto_update_at_intervals'" ref="autoUpdatePacInput"
|
||||
v-model="pacAutoUpdateIntervalHour" custom-class="no-shadow" type="number" min="1"
|
||||
validation-icon=" iconfont icon-alert" style="flex: 1" />
|
||||
</b-field>
|
||||
<b-field :label="$t('setting.autoUpdateSub')" label-position="on-border">
|
||||
<b-select v-model="subscriptionAutoUpdateMode" expanded>
|
||||
@@ -350,16 +240,9 @@
|
||||
{{ $t("setting.options.updateSubAtIntervals") }}
|
||||
</option>
|
||||
</b-select>
|
||||
<cus-b-input
|
||||
v-if="subscriptionAutoUpdateMode === 'auto_update_at_intervals'"
|
||||
ref="autoUpdateSubInput"
|
||||
v-model="subscriptionAutoUpdateIntervalHour"
|
||||
custom-class="no-shadow"
|
||||
type="number"
|
||||
min="1"
|
||||
validation-icon=" iconfont icon-alert"
|
||||
style="flex: 1"
|
||||
/>
|
||||
<cus-b-input v-if="subscriptionAutoUpdateMode === 'auto_update_at_intervals'" ref="autoUpdateSubInput"
|
||||
v-model="subscriptionAutoUpdateIntervalHour" custom-class="no-shadow" type="number" min="1"
|
||||
validation-icon=" iconfont icon-alert" style="flex: 1" />
|
||||
</b-field>
|
||||
<b-field :label="$t('setting.preferModeWhenUpdate')" label-position="on-border">
|
||||
<b-select v-model="proxyModeWhenSubscribe" expanded>
|
||||
@@ -376,11 +259,7 @@
|
||||
</b-field>
|
||||
</section>
|
||||
<footer class="modal-card-foot flex-end">
|
||||
<button
|
||||
class="button footer-absolute-left"
|
||||
type="button"
|
||||
@click="$emit('clickPorts')"
|
||||
>
|
||||
<button class="button footer-absolute-left" type="button" @click="$emit('clickPorts')">
|
||||
{{ $t("customAddressPort.title") }}
|
||||
</button>
|
||||
<button class="button" type="button" @click="$parent.close()">
|
||||
@@ -399,6 +278,7 @@ import dayjs from "dayjs";
|
||||
import ModalCustomRouting from "@/components/modalCustomRouting";
|
||||
import ModalCustomRoutingA from "@/components/modalCustomRoutingA";
|
||||
import modalDomainsExcluded from "@/components/modalDomainsExcluded";
|
||||
import modalTproxyWhiteIpGroups from "@/components/modalTproxyWhiteIpGroups";
|
||||
import modalUpdateGfwList from "@/components/modalUpdateGfwList";
|
||||
import CusBInput from "./input/Input.vue";
|
||||
import { parseURL, toInt } from "@/assets/js/utils";
|
||||
@@ -418,12 +298,13 @@ export default {
|
||||
muxOn: "no",
|
||||
mux: "8",
|
||||
transparent: "close",
|
||||
transparentType: "redirect",
|
||||
transparentType: "tproxy",
|
||||
ipforward: false,
|
||||
portSharing: false,
|
||||
dnsForceMode: false,
|
||||
dnsforward: "no",
|
||||
antipollution: "none",
|
||||
routeOnly: false,
|
||||
specialMode: "none",
|
||||
pacAutoUpdateMode: "none",
|
||||
pacAutoUpdateIntervalHour: 0,
|
||||
@@ -493,6 +374,7 @@ export default {
|
||||
});
|
||||
},
|
||||
requestUpdateSetting() {
|
||||
let loading = this.$buefy.loading.open();
|
||||
let cancel;
|
||||
waitingConnected(
|
||||
this.$axios({
|
||||
@@ -515,6 +397,7 @@ export default {
|
||||
transparentType: this.transparentType,
|
||||
ipforward: this.ipforward,
|
||||
portSharing: this.portSharing,
|
||||
routeOnly: this.routeOnly,
|
||||
dnsforward: this.antipollution === "dnsforward" ? "yes" : "no", //版本兼容
|
||||
antipollution: this.antipollution,
|
||||
specialMode: this.specialMode,
|
||||
@@ -539,6 +422,7 @@ export default {
|
||||
// FIXME: tricky
|
||||
this.$parent.$parent.runningState.running = this.$t("common.notRunning");
|
||||
}
|
||||
loading.close();
|
||||
}),
|
||||
3 * 1000,
|
||||
cancel
|
||||
@@ -592,6 +476,14 @@ export default {
|
||||
canCancel: true,
|
||||
});
|
||||
},
|
||||
handleClickTproxyWhiteIpGroups() {
|
||||
this.$buefy.modal.open({
|
||||
parent: this,
|
||||
component: modalTproxyWhiteIpGroups,
|
||||
hasModalCard: true,
|
||||
canCancel: true,
|
||||
});
|
||||
},
|
||||
handleClickDomainsExcluded() {
|
||||
this.$buefy.modal.open({
|
||||
parent: this,
|
||||
@@ -673,15 +565,19 @@ export default {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.left-border select {
|
||||
border-radius: 4px 0 0 4px !important;
|
||||
}
|
||||
|
||||
.right-extra-button {
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.no-border-radius {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.modal-setting {
|
||||
.b-checkbox.checkbox {
|
||||
margin-right: 0;
|
||||
|
||||
98
v2raya/gui/src/components/modalTproxyWhiteIpGroups.vue
Normal file
98
v2raya/gui/src/components/modalTproxyWhiteIpGroups.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="modal-card" style="max-width: 450px; margin: auto">
|
||||
<header class="modal-card-head">
|
||||
<p class="modal-card-title">
|
||||
{{ $t("tproxyWhiteIpGroups.title") }}
|
||||
</p>
|
||||
</header>
|
||||
<section class="modal-card-body">
|
||||
<b-message type="is-info" class="after-line-dot5">
|
||||
<p>{{ $t("tproxyWhiteIpGroups.messages.0") }}</p>
|
||||
</b-message>
|
||||
<b-field :label="$t('tproxyWhiteIpGroups.formName1')">
|
||||
<b-select multiple v-model="countryCodes" expanded>
|
||||
<option value="CN">{{ $t("tproxyWhiteIpGroups.cn") }}</option>
|
||||
<option value="PRIVATE">{{ $t("tproxyWhiteIpGroups.private") }}</option>
|
||||
<option value="US">{{ $t("tproxyWhiteIpGroups.us") }}</option>
|
||||
<option value="CLOUDFLARE">{{ $t("tproxyWhiteIpGroups.cloudflare") }}</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
<b-field :label="$t('tproxyWhiteIpGroups.formName2')">
|
||||
<b-input v-model="customIps" type="textarea" :placeholder="$t('tproxyWhiteIpGroups.formPlaceholder2')"
|
||||
custom-class="full-min-height horizon-scroll code-font" />
|
||||
</b-field>
|
||||
<b-message type="is-warning" class="after-line-dot5">
|
||||
<p>{{ $t("tproxyWhiteIpGroups.messages.1") }}</p>
|
||||
</b-message>
|
||||
</section>
|
||||
<footer class="modal-card-foot flex-end">
|
||||
<button class="button" @click="$emit('close')">
|
||||
{{ $t("operations.cancel") }}
|
||||
</button>
|
||||
<button class="button is-primary" @click="handleClickSubmit">
|
||||
{{ $t("operations.save") }}
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { handleResponse } from "@/assets/js/utils";
|
||||
|
||||
export default {
|
||||
name: "modalTproxyWhiteIpGroups",
|
||||
data: () => ({
|
||||
countryCodes: [],
|
||||
customIps: "",
|
||||
}),
|
||||
created() {
|
||||
this.$axios({
|
||||
url: apiRoot + "/tproxyWhiteIpGroups",
|
||||
}).then((res) => {
|
||||
handleResponse(res, this, () => {
|
||||
if (res.data.data.countryCodes) {
|
||||
this.countryCodes = res.data.data.countryCodes;
|
||||
}
|
||||
if (res.data.data.customIps) {
|
||||
this.customIps = res.data.data.customIps.join("\n");
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
validateCIDRArray(arr) {
|
||||
const ipv4Cidr = /^(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)){3}\/(?:[0-9]|[12]\d|3[0-2])$/;
|
||||
|
||||
const ipv6Cidr = /^(?:(?:[A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}|(?:[A-Fa-f0-9]{1,4}:){1,7}:|(?:[A-Fa-f0-9]{1,4}:){1,6}:[A-Fa-f0-9]{1,4}|(?:[A-Fa-f0-9]{1,4}:){1,5}(?::[A-Fa-f0-9]{1,4}){1,2}|(?:[A-Fa-f0-9]{1,4}:){1,4}(?::[A-Fa-f0-9]{1,4}){1,3}|(?:[A-Fa-f0-9]{1,4}:){1,3}(?::[A-Fa-f0-9]{1,4}){1,4}|(?:[A-Fa-f0-9]{1,4}:){1,2}(?::[A-Fa-f0-9]{1,4}){1,5}|[A-Fa-f0-9]{1,4}:(?:(?::[A-Fa-f0-9]{1,4}){1,6})|:(?:(?::[A-Fa-f0-9]{1,4}){1,7}|:))\/(?:12[0-8]|1[01]\d|[1-9]?\d)$/;
|
||||
|
||||
const invalid = arr
|
||||
.map(s => (typeof s === 'string' ? s.trim() : ''))
|
||||
.filter(s => s.length === 0 || !(ipv4Cidr.test(s) || ipv6Cidr.test(s)));
|
||||
return invalid.length === 0;
|
||||
},
|
||||
handleClickSubmit() {
|
||||
if (!this.validateCIDRArray(this.customIps.split("\n").filter(line => line.trim() !== ''))) {
|
||||
this.$buefy.toast.open({
|
||||
message: this.$t("tproxyWhiteIpGroups.invalidCustomIps"),
|
||||
type: "is-danger",
|
||||
position: "is-top",
|
||||
queue: false,
|
||||
duration: 10000,
|
||||
});
|
||||
return
|
||||
}
|
||||
this.$axios({
|
||||
url: apiRoot + "/tproxyWhiteIpGroups",
|
||||
method: "put",
|
||||
data: {
|
||||
countryCodes: this.countryCodes.length ? this.countryCodes : ['NONE'],
|
||||
customIps: this.customIps.split("\n").filter(line => line.trim() !== ''),
|
||||
},
|
||||
}).then((res) => {
|
||||
handleResponse(res, this, () => {
|
||||
this.$emit("close");
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -64,6 +64,7 @@ export default {
|
||||
},
|
||||
operations: {
|
||||
name: "Operations",
|
||||
tproxyWhiteIpGroups: "Direct Whitelist IP Groups",
|
||||
update: "Update",
|
||||
autoUpdate: "Auto Update",
|
||||
manualUpdate: "Manual Update",
|
||||
@@ -91,7 +92,7 @@ export default {
|
||||
no: "No",
|
||||
switchSite: "Switch to alternate site",
|
||||
addOutbound: "Add an outbound",
|
||||
domainsExcluded:"Domains Excluded"
|
||||
domainsExcluded: "Domains Excluded"
|
||||
},
|
||||
register: {
|
||||
title: "Create an admin account first",
|
||||
@@ -328,6 +329,21 @@ export default {
|
||||
seconds: "seconds",
|
||||
autoScoll: "Auto Scroll",
|
||||
},
|
||||
tproxyWhiteIpGroups: {
|
||||
title: "White IP Groups",
|
||||
messages: [
|
||||
"The selected IP group will bypass the XRay/V2Ray core and go directly outbound (through Nftables/Iptables). Please ensure your DNS server is reliable and free of contamination so that clients can resolve the correct IPs.",
|
||||
"It's best to use this feature when your system is using Nftables, as iptables may experience performance issues when adding a large number of IPs."
|
||||
],
|
||||
formName1: "Hold down Ctrl to select multiple items.",
|
||||
formName2: "Custom IPs (one per line, standard CIDR format)",
|
||||
formPlaceholder2: "172.30.0.0/16\nfd00:aaaa:bbbb::/48",
|
||||
invalidCustomIps:"Invalid Custom IPs",
|
||||
cn: 'China Mainland',
|
||||
private: 'Private',
|
||||
us: 'United States',
|
||||
cloudflare: 'Cloudflare',
|
||||
},
|
||||
domainsExcluded: {
|
||||
title: "Domains Excluded",
|
||||
messages: [
|
||||
|
||||
@@ -62,6 +62,7 @@ export default {
|
||||
subscription: "订阅",
|
||||
},
|
||||
operations: {
|
||||
tproxyWhiteIpGroups: "直通白名单IP组",
|
||||
name: "操作",
|
||||
update: "更新",
|
||||
autoUpdate: "自动更新",
|
||||
@@ -330,6 +331,22 @@ export default {
|
||||
seconds: "秒",
|
||||
autoScoll: "自动滚动",
|
||||
},
|
||||
|
||||
tproxyWhiteIpGroups: {
|
||||
title: "直通白名单IP组",
|
||||
messages: [
|
||||
"选中的IP组将会不经过XRay/V2Ray核心直接出站(通过Nftables/Iptables直接转发),请确保你的DNS服务器足够可靠无污染能使客户端能解析到正确的IP",
|
||||
"最好系统使用Nftables时使用此功能,Iptables可能在添加大量IP时存在性能问题"
|
||||
],
|
||||
formName1: "按住Ctrl可以多选",
|
||||
formName2: "自定义IP(一行一个,标准CIDR格式)",
|
||||
formPlaceholder2: "172.30.0.0/16\nfd00:dead:beef::/48",
|
||||
invalidCustomIps:"自定义IP格式错误",
|
||||
cn: '中国大陆',
|
||||
private: '私网网段',
|
||||
us: '美国',
|
||||
cloudflare: 'Cloudflare',
|
||||
},
|
||||
domainsExcluded: {
|
||||
title: "排除域名",
|
||||
messages: [
|
||||
|
||||
@@ -1294,6 +1294,7 @@ export default {
|
||||
let cancel;
|
||||
if (!row.connected) {
|
||||
//该节点并未处于连接状态,因此进行连接
|
||||
let loading = this.$buefy.loading.open();
|
||||
waitingConnected(
|
||||
this.$axios({
|
||||
url: apiRoot + "/connection",
|
||||
@@ -1308,6 +1309,7 @@ export default {
|
||||
cancel = c;
|
||||
}),
|
||||
}).then((res) => {
|
||||
loading.close();
|
||||
if (res.data.code === "SUCCESS") {
|
||||
Object.assign(this.runningState, {
|
||||
running: res.data.data.running
|
||||
|
||||
Reference in New Issue
Block a user