Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/web/html
diff options
context:
space:
mode:
authorAlireza Ahmadi <alireza7@gmail.com>2023-12-05 20:13:36 +0300
committerAlireza Ahmadi <alireza7@gmail.com>2023-12-05 20:20:44 +0300
commitc419eadf15630518606ab434387079172070d340 (patch)
tree1933bd5868840cbc85c2b289523f57c22491b7b9 /web/html
parent4d3bea48e11883f0fb99f2e4bb8d943fe162c687 (diff)
xray setting enhancements #1286
Diffstat (limited to 'web/html')
-rw-r--r--web/html/common/js.html6
-rw-r--r--web/html/login.html7
-rw-r--r--web/html/xui/form/outbound.html306
-rw-r--r--web/html/xui/inbounds.html6
-rw-r--r--web/html/xui/index.html1
-rw-r--r--web/html/xui/settings.html3
-rw-r--r--web/html/xui/xray.html560
-rw-r--r--web/html/xui/xray_outbound_modal.html125
-rw-r--r--web/html/xui/xray_reverse_modal.html139
-rw-r--r--web/html/xui/xray_rule_modal.html213
10 files changed, 1313 insertions, 53 deletions
diff --git a/web/html/common/js.html b/web/html/common/js.html
index e3fcdba9..661a0b87 100644
--- a/web/html/common/js.html
+++ b/web/html/common/js.html
@@ -2,18 +2,12 @@
<script src="{{ .base_path }}assets/vue@2.6.12/vue.min.js"></script>
<script src="{{ .base_path }}assets/moment/moment.min.js"></script>
<script src="{{ .base_path }}assets/ant-design-vue@1.7.8/antd.min.js"></script>
-<script src="{{ .base_path }}assets/base64/base64.min.js"></script>
<script src="{{ .base_path }}assets/axios/axios.min.js"></script>
<script src="{{ .base_path }}assets/qs/qs.min.js"></script>
-<script src="{{ .base_path }}assets/qrcode/qrious.min.js"></script>
-<script src="{{ .base_path }}assets/clipboard/clipboard.min.js"></script>
-<script src="{{ .base_path }}assets/uri/URI.min.js"></script>
<script src="{{ .base_path }}assets/js/axios-init.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/util/common.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/util/date-util.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/util/utils.js?{{ .cur_ver }}"></script>
-<script src="{{ .base_path }}assets/js/model/xray.js?{{ .cur_ver }}"></script>
-<script src="{{ .base_path }}assets/js/model/models.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/langs.js"></script>
<script>
const basePath = '{{ .base_path }}';
diff --git a/web/html/login.html b/web/html/login.html
index 736004f6..07d5f52e 100644
--- a/web/html/login.html
+++ b/web/html/login.html
@@ -176,7 +176,12 @@
{{template "component/themeSwitcher" .}}
{{template "component/password" .}}
<script>
-
+ class User {
+ constructor() {
+ this.username = "";
+ this.password = "";
+ }
+ }
const app = new Vue({
delimiters: ['[[', ']]'],
el: '#app',
diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html
new file mode 100644
index 00000000..a8b58ba0
--- /dev/null
+++ b/web/html/xui/form/outbound.html
@@ -0,0 +1,306 @@
+{{define "form/outbound"}}
+<!-- base -->
+<a-tabs :active-key="outModal.activeKey" style="padding: 0; background-color: transparent;" @change="(activeKey) => {outModal.toggleJson(activeKey == '2'); }">
+<a-tab-pane key="1" tab="Form">
+<a-form layout="inline">
+ <a-form-item label='{{ i18n "protocol" }}'>
+ <a-select v-model="outbound.protocol" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="x,y in Protocols" :value="x">[[ y ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label='{{ i18n "pages.xray.outbound.tag" }}'>
+ <a-input v-model.trim="outbound.tag" style="width: 250px" @change="outModal.check()" :style="outModal.duplicateTag? 'border-color: red;' : ''"></a-input>
+ </a-form-item>
+<!-- freedom settings-->
+<template v-if="outbound.protocol === Protocols.Freedom">
+ <a-form-item label="Strategy">
+ <a-select
+ v-model="outbound.settings.domainStrategy"
+ style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="s in outboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="Fragment">
+ <a-switch
+ :checked="Object.keys(outbound.settings.fragment).length >0"
+ @change="checked => outbound.settings.fragment = checked ? new Outbound.FreedomSettings.Fragment() : {}">
+ </a-switch>
+ </a-form-item>
+ <template v-if="Object.keys(outbound.settings.fragment).length >0">
+ <a-form-item label="Packets">
+ <a-select
+ v-model="outbound.settings.fragment.packets"
+ style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="s in ['1-3','tlshello']" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="Length">
+ <a-input v-model.trim="outbound.settings.fragment.length" style="width: 250px"></a-input>
+ </a-form-item>
+ <a-form-item label="Interval">
+ <a-input v-model.trim="outbound.settings.fragment.interval" style="width: 250px"></a-input>
+ </a-form-item>
+ </template>
+</template>
+
+<!-- blackhole settings -->
+<template v-if="outbound.protocol === Protocols.Blackhole">
+ <a-form-item label="Response Type">
+ <a-select
+ v-model="outbound.settings.type"
+ style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="s in ['', 'none','http']" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+</template>
+
+<!-- dns settings -->
+<template v-if="outbound.protocol === Protocols.DNS">
+ <a-form-item label='{{ i18n "pages.inbounds.network" }}'>
+ <a-select
+ v-model="outbound.settings.network"
+ style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="s in ['udp','tcp']" :value="s">[[ s ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+</template>
+
+<!-- Address + Port -->
+<template v-if="outbound.hasAddressPort()">
+ <a-form-item label='{{ i18n "pages.inbounds.address" }}'>
+ <a-input v-model.trim="outbound.settings.address" style="width: 250px"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "pages.inbounds.port" }}'>
+ <a-input-number v-model.number="outbound.settings.port"></a-input-number>
+ </a-form-item>
+</template>
+
+<!-- Vnext (vless/vmess) settings -->
+<template v-if="[Protocols.VMess, Protocols.VLESS].includes(outbound.protocol)">
+ <a-form-item label="ID">
+ <a-input v-model.trim="outbound.settings.id" style="width: 250px"></a-input>
+ </a-form-item>
+ <!-- vless settings -->
+ <template v-if="outbound.canEnableTlsFlow()">
+ <a-form-item label="Flow">
+ <a-select v-model="outbound.settings.flow" style="width: 250px" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="" selected>{{ i18n "none" }}</a-select-option>
+ <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ </template>
+</template>
+
+<!-- Servers (trojan/shadowsocks/socks/http) settings -->
+<template v-if="outbound.hasServers()">
+ <template v-if="outbound.hasUsername()">
+ <a-form-item label='{{ i18n "username" }}'>
+ <a-input v-model.trim="outbound.settings.user" style="width: 250px"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "password" }}'>
+ <a-input v-model.trim="outbound.settings.password" style="width: 250px"></a-input>
+ </a-form-item>
+ </template>
+ <!-- shadowsocks -->
+ <template v-if="outbound.protocol === Protocols.Shadowsocks">
+ <a-form-item label='{{ i18n "encryption" }}'>
+ <a-select v-model="outbound.settings.method" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="UDP over TCP">
+ <a-switch v-model="outbound.settings.uot"></a-switch>
+ </a-form-item>
+ </template>
+</template>
+
+<!-- stream settings -->
+<template v-if="outbound.canEnableStream()">
+ <a-form-item label='{{ i18n "transmission" }}'>
+ <a-select v-model="outbound.stream.network" @change="streamNetworkChange"
+ style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="tcp">TCP</a-select-option>
+ <a-select-option value="kcp">KCP</a-select-option>
+ <a-select-option value="ws">WebSocket</a-select-option>
+ <a-select-option value="http">HTTP2</a-select-option>
+ <a-select-option value="quic">QUIC</a-select-option>
+ <a-select-option value="grpc">gRPC</a-select-option>
+ </a-select>
+ </a-form-item>
+ <template v-if="outbound.stream.network === 'tcp'">
+ <a-form-item label='http {{ i18n "camouflage" }}'>
+ <a-switch
+ :checked="outbound.stream.tcp.type === 'http'"
+ @change="checked => outbound.stream.tcp.type = checked ? 'http' : 'none'">
+ </a-switch>
+ </a-form-item>
+ <template v-if="outbound.stream.tcp.type == 'http'">
+ <a-form-item label='{{ i18n "host" }}'>
+ <a-input style="width: 250px;" v-model.trim="outbound.stream.tcp.host"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "path" }}'>
+ <a-input style="width: 250px;" v-model.trim="outbound.stream.tcp.path"></a-input>
+ </a-form-item>
+ </template>
+ </template>
+
+ <!-- kcp -->
+ <template v-if="outbound.stream.network === 'kcp'">
+ <a-form-item label='{{ i18n "camouflage" }}'>
+ <a-select v-model="outbound.stream.kcp.type" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="none">none (not camouflage)</a-select-option>
+ <a-select-option value="srtp">srtp (video call)</a-select-option>
+ <a-select-option value="utp">utp (BT download)</a-select-option>
+ <a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
+ <a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
+ <a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label='{{ i18n "password" }}'>
+ <a-input v-model="outbound.stream.kcp.seed" style="width: 250px;"></a-input>
+ </a-form-item>
+ <a-form-item label="mtu">
+ <a-input-number v-model.number="outbound.stream.kcp.mtu"></a-input-number>
+ </a-form-item>
+ <a-form-item label="tti (ms)">
+ <a-input-number v-model.number="outbound.stream.kcp.tti"></a-input-number>
+ </a-form-item>
+ <a-form-item label="uplink capacity (MB/S)">
+ <a-input-number v-model.number="outbound.stream.kcp.upCap"></a-input-number>
+ </a-form-item>
+ <a-form-item label="downlink capacity (MB/S)">
+ <a-input-number v-model.number="outbound.stream.kcp.downCap"></a-input-number>
+ </a-form-item>
+ <a-form-item label="congestion">
+ <a-switch v-model="outbound.stream.kcp.congestion"></a-switch>
+ </a-form-item>
+ <a-form-item label="read buffer size (MB)">
+ <a-input-number v-model.number="outbound.stream.kcp.readBuffer"></a-input-number>
+ </a-form-item>
+ <a-form-item label="write buffer size (MB)">
+ <a-input-number v-model.number="outbound.stream.kcp.writeBuffer"></a-input-number>
+ </a-form-item>
+ </template>
+
+ <!-- ws -->
+ <template v-if="outbound.stream.network === 'ws'">
+ <a-form-item label='{{ i18n "host" }}'>
+ <a-input style="width: 250px" v-model="outbound.stream.ws.host"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "path" }}'>
+ <a-input style="width: 250px;" v-model.trim="outbound.stream.ws.path"></a-input>
+ </a-form-item>
+ </template>
+
+ <!-- http -->
+ <template v-if="outbound.stream.network === 'http'">
+ <a-form-item label='{{ i18n "host" }}'>
+ <a-input v-model.trim="outbound.stream.http.host" style="width: 250px;"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "path" }}'>
+ <a-input v-model.trim="outbound.stream.http.path" style="width: 250px;"></a-input>
+ </a-form-item>
+ </template>
+
+ <!-- quic -->
+ <template v-if="outbound.stream.network === 'quic'">
+ <a-form-item label='{{ i18n "pages.inbounds.stream.quic.encryption" }}'>
+ <a-select v-model="outbound.stream.quic.security" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="none">none</a-select-option>
+ <a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option>
+ <a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label='{{ i18n "password" }}'>
+ <a-input v-model.trim="outbound.stream.quic.key" style="width: 250px;"></a-input>
+ </a-form-item>
+ <a-form-item label='{{ i18n "camouflage" }}'>
+ <a-select v-model="outbound.stream.quic.type" style="width: 250px;" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="none">none (not camouflage)</a-select-option>
+ <a-select-option value="srtp">srtp (video call)</a-select-option>
+ <a-select-option value="utp">utp (BT download)</a-select-option>
+ <a-select-option value="wechat-video">wechat-video (WeChat video)</a-select-option>
+ <a-select-option value="dtls">dtls (DTLS 1.2 packages)</a-select-option>
+ <a-select-option value="wireguard">wireguard (wireguard packages)</a-select-option>
+ </a-select>
+ </a-form-item>
+ </template>
+
+ <!-- grpc -->
+ <template v-if="outbound.stream.network === 'grpc'">
+ <a-form-item label="serviceName">
+ <a-input v-model.trim="outbound.stream.grpc.serviceName" style="width: 250px;"></a-input>
+ </a-form-item>
+ <a-form-item label="MultiMode">
+ <a-switch v-model="outbound.stream.grpc.multiMode"></a-switch>
+ </a-form-item>
+ </template>
+</template>
+
+<!-- tls settings -->
+<template v-if="outbound.canEnableTls()">
+ <a-form-item label='{{ i18n "security" }}'>
+ <a-radio-group v-model="outbound.stream.security" button-style="solid">
+ <a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
+ <a-radio-button value="tls">TLS</a-radio-button>
+ <a-radio-button v-if="outbound.canEnableReality()" value="reality">Reality</a-radio-button>
+ </a-radio-group>
+ </a-form-item><br />
+ <template v-if="outbound.stream.isTls">
+ <a-form-item label="SNI" placeholder="Server Name Indication">
+ <a-input v-model.trim="outbound.stream.tls.serverName" style="width: 250px"></a-input>
+ </a-form-item>
+ <a-form-item label="uTLS">
+ <a-select v-model="outbound.stream.tls.fingerprint"
+ style="width: 250px" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value=''>None</a-select-option>
+ <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="ALPN">
+ <a-select
+ mode="multiple"
+ style="width: 250px"
+ :dropdown-class-name="themeSwitcher.currentTheme"
+ v-model="outbound.stream.tls.alpn">
+ <a-select-option v-for="alpn in ALPN_OPTION" :value="alpn">[[ alpn ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="Allow insecure">
+ <a-switch v-model="outbound.stream.tls.allowInsecure"></a-switch>
+ </a-form-item>
+ </template>
+
+ <!-- reality settings -->
+ <template v-if="outbound.stream.isReality">
+ <a-form-item label='{{ i18n "domainName" }}'>
+ <a-input v-model.trim="outbound.stream.reality.serverName" style="width: 250px"></a-input>
+ </a-form-item>
+ <a-form-item label="uTLS">
+ <a-select v-model="outbound.stream.reality.fingerprint"
+ style="width: 250px" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
+ </a-select>
+ </a-form-item>
+ <a-form-item label="Short Id">
+ <a-input v-model.trim="outbound.stream.reality.shortId" style="width:250px"></a-input>
+ </a-form-item>
+ <a-form-item label="SpiderX">
+ <a-input v-model.trim="outbound.stream.reality.spiderX" style="width:250px"></a-input>
+ </a-form-item>
+ <a-form-item label="Public Key">
+ <a-input v-model.trim="outbound.stream.reality.publicKey" style="width: 250px"></a-input>
+ </a-form-item>
+ </template>
+</template>
+</a-form>
+</a-tab-pane>
+<a-tab-pane key="2" tab="JSON" force-render="true">
+ <a-form-item style="margin: 10px 0">
+ Link: <a-input v-model.trim="outModal.link" style="width: 300px; margin-right: 5px;" placeholder="vmess:// vless:// trojan:// ss://"></a-input>
+ <a-button @click="convertLink" type="primary"><a-icon type="form"></a-icon></a-button>
+ </a-form-item>
+ <textarea style="position:absolute; left: -800px;" id="outboundJson"></textarea>
+</a-tab-pane>
+</a-tabs>
+{{end}} \ No newline at end of file
diff --git a/web/html/xui/inbounds.html b/web/html/xui/inbounds.html
index f8ba5a51..2a6d74ab 100644
--- a/web/html/xui/inbounds.html
+++ b/web/html/xui/inbounds.html
@@ -429,6 +429,12 @@
</a-layout>
</a-layout>
{{template "js" .}}
+<script src="{{ .base_path }}assets/base64/base64.min.js"></script>
+<script src="{{ .base_path }}assets/qrcode/qrious.min.js"></script>
+<script src="{{ .base_path }}assets/clipboard/clipboard.min.js"></script>
+<script src="{{ .base_path }}assets/uri/URI.min.js"></script>
+<script src="{{ .base_path }}assets/js/model/xray.js?{{ .cur_ver }}"></script>
+<script src="{{ .base_path }}assets/js/model/dbinbound.js?{{ .cur_ver }}"></script>
{{template "component/themeSwitcher" .}}
<script>
const columns = [{
diff --git a/web/html/xui/index.html b/web/html/xui/index.html
index cafdb8f9..868d3e4e 100644
--- a/web/html/xui/index.html
+++ b/web/html/xui/index.html
@@ -317,6 +317,7 @@
</a-layout>
{{template "js" .}}
+<script src="{{ .base_path }}assets/clipboard/clipboard.min.js"></script>
{{template "component/themeSwitcher" .}}
{{template "textModal"}}
<script>
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html
index 44b040e9..59d20716 100644
--- a/web/html/xui/settings.html
+++ b/web/html/xui/settings.html
@@ -253,6 +253,7 @@
</a-layout>
</a-layout>
{{template "js" .}}
+<script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script>
{{template "component/themeSwitcher" .}}
{{template "component/password" .}}
{{template "component/setting"}}
@@ -267,7 +268,7 @@
oldAllSetting: new AllSetting(),
allSetting: new AllSetting(),
saveBtnDisable: true,
- user: new User(),
+ user: {},
lang: getLang(),
},
methods: {
diff --git a/web/html/xui/xray.html b/web/html/xui/xray.html
index ff22bfe5..9bcacebd 100644
--- a/web/html/xui/xray.html
+++ b/web/html/xui/xray.html
@@ -1,6 +1,22 @@
<!DOCTYPE html>
<html lang="en">
{{template "head" .}}
+<link rel="stylesheet" href="{{ .base_path }}assets/codemirror/codemirror.css">
+<link rel="stylesheet" href="{{ .base_path }}assets/codemirror/fold/foldgutter.css">
+<link rel="stylesheet" href="{{ .base_path }}assets/codemirror/xq.css">
+<link rel="stylesheet" href="{{ .base_path }}assets/codemirror/lint/lint.css">
+
+<script src="{{ .base_path }}assets/js/model/outbound.js"></script>
+<script src="{{ .base_path }}assets/codemirror/codemirror.js"></script>
+<script src="{{ .base_path }}assets/codemirror/javascript.js"></script>
+<script src="{{ .base_path }}assets/codemirror/jshint.js"></script>
+<script src="{{ .base_path }}assets/codemirror/jsonlint.js"></script>
+<script src="{{ .base_path }}assets/codemirror/lint/lint.js"></script>
+<script src="{{ .base_path }}assets/codemirror/lint/javascript-lint.js"></script>
+<script src="{{ .base_path }}assets/codemirror/hint/javascript-hint.js"></script>
+<script src="{{ .base_path }}assets/codemirror/fold/foldcode.js"></script>
+<script src="{{ .base_path }}assets/codemirror/fold/foldgutter.js"></script>
+<script src="{{ .base_path }}assets/codemirror/fold/brace-fold.js"></script>
<style>
@media (min-width: 769px) {
.ant-layout-content {
@@ -59,8 +75,10 @@
</a-col>
</a-row>
</a-card>
- <a-tabs class="ant-card-dark-box-nohover" default-active-key="tpl-1" :class="themeSwitcher.currentTheme" style="padding: 20px 20px;">
- <a-tab-pane key="tpl-1" tab='{{ i18n "pages.xray.basicTemplate"}}' style="padding-top: 20px;">
+ <a-tabs class="ant-card-dark-box-nohover" default-active-key="tpl-1"
+ @change="(activeKey) => { if(activeKey == 'tpl-4') this.changeCode(); }"
+ :class="themeSwitcher.currentTheme">
+ <a-tab-pane key="tpl-1" tab='{{ i18n "pages.xray.basicTemplate"}}'>
<a-space direction="horizontal" style="padding: 20px 20px">
<a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
</a-space>
@@ -175,49 +193,196 @@
</a-collapse-panel>
</a-collapse>
</a-tab-pane>
- <a-tab-pane key="tpl-2" tab='{{ i18n "pages.xray.manualLists"}}' style="padding-top: 20px;">
- <a-row :xs="24" :sm="24" :lg="12">
- <h2 class="collapse-title">
- <a-icon type="warning"></a-icon>
- {{ i18n "pages.xray.manualListsDesc" }}
- </h2>
- </a-row>
- <a-collapse>
- <a-collapse-panel header='{{ i18n "pages.xray.manualBlockedIPs"}}'>
- <setting-list-item type="textarea" v-model="manualBlockedIPs"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.manualBlockedDomains"}}'>
- <setting-list-item type="textarea" v-model="manualBlockedDomains"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.manualDirectIPs"}}'>
- <setting-list-item type="textarea" v-model="manualDirectIPs"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.manualDirectDomains"}}'>
- <setting-list-item type="textarea" v-model="manualDirectDomains"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.manualIPv4Domains"}}'>
- <setting-list-item type="textarea" v-model="manualIPv4Domains"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.manualWARPDomains"}}'>
- <setting-list-item type="textarea" v-model="manualWARPDomains"></setting-list-item>
- </a-collapse-panel>
- </a-collapse>
+ <a-tab-pane key="tpl-2" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;">
+ <a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
+ message='{{ i18n "pages.xray.RoutingsDesc"}}' show-icon></a-alert>
+ <a-button type="primary" icon="plus" @click="addRule">{{ i18n "pages.xray.rules.add" }}</a-button>
+ <a-table :columns="isMobile ? rulesMobileColumns : rulesColumns" bordered
+ :row-key="r => r.key"
+ :data-source="routingRuleData"
+ :scroll="isMobile ? {} : { x: 1000 }"
+ :pagination="false"
+ :indent-size="0"
+ :style="isMobile ? 'padding: 5px 0' : 'margin-top: 10px;'">
+ <template slot="action" slot-scope="text, rule, index">
+ [[ index+1 ]]
+ <a-dropdown :trigger="['click']">
+ <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
+ <a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
+ <a-menu-item v-if="index>0" @click="replaceRule(index,0)">
+ <a-icon type="vertical-align-top"></a-icon>
+ {{ i18n "pages.xray.rules.first"}}
+ </a-menu-item>
+ <a-menu-item v-if="index>0" @click="replaceRule(index,index-1)">
+ <a-icon type="arrow-up"></a-icon>
+ {{ i18n "pages.xray.rules.up"}}
+ </a-menu-item>
+ <a-menu-item v-if="index<routingRuleData.length-1" @click="replaceRule(index,index+1)">
+ <a-icon type="arrow-down"></a-icon>
+ {{ i18n "pages.xray.rules.down"}}
+ </a-menu-item>
+ <a-menu-item v-if="index<routingRuleData.length-1" @click="replaceRule(index,routingRuleData.length-1)">
+ <a-icon type="vertical-align-bottom"></a-icon>
+ {{ i18n "pages.xray.rules.last"}}
+ </a-menu-item>
+ <a-menu-item @click="editRule(index)">
+ <a-icon type="edit"></a-icon>
+ {{ i18n "edit" }}
+ </a-menu-item>
+ <a-menu-item @click="deleteRule(index)">
+ <span style="color: #FF4D4F">
+ <a-icon type="delete"></a-icon> {{ i18n "delete"}}
+ </span>
+ </a-menu-item>
+ </a-menu>
+ </a-dropdown>
+ </template>
+ <template slot="inbound" slot-scope="text, rule, index">
+ <a-popover :overlay-class-name="themeSwitcher.currentTheme">
+ <template slot="content">
+ <p v-if="rule.inboundTag">Inbound Tag: [[ rule.inboundTag ]]</p>
+ <p v-if="rule.user">User email: [[ rule.user ]]</p>
+ </template>
+ [[ [rule.inboundTag,rule.user].join('\n') ]]
+ </a-popover>
+ </template>
+ <template slot="outbound" slot-scope="text, rule, index">
+ <a-popover :overlay-class-name="themeSwitcher.currentTheme">
+ <template slot="content">
+ <p v-if="rule.outboundTag">Outbound Tag: [[ rule.outboundTag ]]</p>
+ </template>
+ [[ rule.outboundTag ]]
+ </a-popover>
+ </template>
+ <template slot="info" slot-scope="text, rule, index">
+ <a-popover placement="bottomRight"
+ v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
+ :overlay-class-name="themeSwitcher.currentTheme" trigger="click">
+ <template slot="content">
+ <table cellpadding="2" style="max-width: 300px;">
+ <tr v-if="rule.source">
+ <td>Source</td>
+ <td><a-tag color="blue" v-for="r in rule.source.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.sourcePort">
+ <td>Source Port</td>
+ <td><a-tag color="green" v-for="r in rule.sourcePort.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.network">
+ <td>Network</td>
+ <td><a-tag color="blue" v-for="r in rule.network.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.protocol">
+ <td>Protocol</td>
+ <td><a-tag color="green" v-for="r in rule.protocol.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.attrs">
+ <td>Attrs</td>
+ <td><a-tag color="blue" v-for="r in rule.attrs.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.ip">
+ <td>IP</td>
+ <td><a-tag color="green" v-for="r in rule.ip.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.domain">
+ <td>Domain</td>
+ <td><a-tag color="blue" v-for="r in rule.domain.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ <tr v-if="rule.port">
+ <td>Port</td>
+ <td><a-tag color="green" v-for="r in rule.port.split(',')">[[ r ]]</a-tag></td>
+ </tr>
+ </table>
+ </template>
+ <a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
+ <a-icon type="info"></a-icon>
+ </a-button>
+ </a-popover>
+ </template>
+ </a-table>
</a-tab-pane>
- <a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;">
- <a-collapse>
- <a-collapse-panel header='{{ i18n "pages.xray.xrayConfigInbounds"}}'>
- <setting-list-item type="textarea" title='{{ i18n "pages.xray.xrayConfigInbounds"}}' desc='{{ i18n "pages.xray.xrayConfigInboundsDesc"}}' v-model="inboundSettings"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.xrayConfigOutbounds"}}'>
- <setting-list-item type="textarea" title='{{ i18n "pages.xray.xrayConfigOutbounds"}}' desc='{{ i18n "pages.xray.xrayConfigOutboundsDesc"}}' v-model="outboundSettings"></setting-list-item>
- </a-collapse-panel>
- <a-collapse-panel header='{{ i18n "pages.xray.xrayConfigRoutings"}}'>
- <setting-list-item type="textarea" title='{{ i18n "pages.xray.xrayConfigRoutings"}}' desc='{{ i18n "pages.xray.xrayConfigRoutingsDesc"}}' v-model="routingRuleSettings"></setting-list-item>
- </a-collapse-panel>
- </a-collapse>
+ <a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
+ <a-button type="primary" icon="plus" @click="addOutbound()">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
+ <a-button type="primary" icon="plus" @click="addReverse()">{{ i18n "pages.xray.outbound.addReverse" }}</a-button>
+ <a-row>
+ <a-col :sm="24" :md="12">
+ <p style="margin: 10px;">{{ i18n "pages.xray.Outbounds"}}</p>
+ <a-table :columns="outboundColumns" bordered
+ :row-key="r => r.key"
+ :data-source="outboundData"
+ :scroll="isMobile ? {} : { x: 200 }"
+ :pagination="false"
+ :indent-size="0"
+ :style="isMobile ? 'padding: 5px 5px' : 'margin-right: 1px;'">
+ <template slot="action" slot-scope="text, outbound, index">
+ [[ index+1 ]]
+ <a-dropdown :trigger="['click']">
+ <a-icon @click="e => e.preventDefault()" type="more" style="font-size: 16px; text-decoration: bold;"></a-icon>
+ <a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
+ <a-menu-item @click="editOutbound(index)">
+ <a-icon type="edit"></a-icon>
+ {{ i18n "edit" }}