This commit is contained in:
Shishkevich D. 2025-04-04 22:53:44 +03:30 committed by GitHub
commit 52b4f31c6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 627 additions and 477 deletions

View file

@ -83,7 +83,7 @@ class PromiseUtil {
class RandomUtil {
static getSeq({ type = "default", hasNumbers = true, hasLowercase = true, hasUppercase = true } = {}) {
let seq = '';
switch (type) {
case "hex":
seq += "0123456789abcdef";
@ -488,7 +488,7 @@ class ClipboardManager {
return new Promise((resolve) => {
try {
const textarea = window.document.createElement('textarea');
textarea.style.fontSize = '12pt';
textarea.style.border = '0';
textarea.style.padding = '0';
@ -498,14 +498,14 @@ class ClipboardManager {
textarea.style.top = `${window.pageYOffset || document.documentElement.scrollTop}px`;
textarea.setAttribute('readonly', '');
textarea.value = content;
window.document.body.appendChild(textarea);
textarea.select();
window.document.execCommand("copy");
window.document.body.removeChild(textarea);
resolve(true)
} catch {
resolve(false)
@ -558,10 +558,6 @@ class CPUFormatter {
static cpuSpeedFormat(speed) {
return speed > 1000 ? (speed / 1000).toFixed(2) + " GHz" : speed.toFixed(2) + " MHz";
}
static cpuCoreFormat(cores) {
return cores === 1 ? "1 Core" : cores + " Cores";
}
}
class TimeFormatter {
@ -579,7 +575,7 @@ class NumberFormatter {
static addZero(num) {
return num < 10 ? "0" + num : num;
}
static toFixed(num, n) {
n = Math.pow(10, n);
return Math.floor(num * n) / n;
@ -610,7 +606,7 @@ class CookieManager {
}
return '';
}
static setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
@ -630,7 +626,7 @@ class ColorUtils {
default: return "red";
}
}
static clientUsageColor(clientStats, trafficDiff) {
switch (true) {
case !clientStats || clientStats.total == 0: return "#7a316f";
@ -639,7 +635,7 @@ class ColorUtils {
default: return "#cf3c3c";
}
}
static userExpiryColor(threshold, client, isDark = false) {
if (!client.enable) return isDark ? '#2c3950' : '#bcbcbc';
let now = new Date().getTime(), expiry = client.expiryTime;
@ -665,7 +661,7 @@ class URLBuilder {
if (!host || host.length === 0) host = window.location.hostname;
if (!port || port.length === 0) port = window.location.port;
if (isTLS === undefined) isTLS = window.location.protocol === "https:";
const protocol = isTLS ? "https:" : "http:";
port = String(port);
if (port === "" || (isTLS && port === "443") || (!isTLS && port === "80")) {
@ -673,7 +669,7 @@ class URLBuilder {
} else {
port = `:${port}`;
}
return `${protocol}//${host}${port}${base}${path}`;
}
}
@ -744,11 +740,11 @@ class LanguageManager {
static getLanguage() {
let lang = CookieManager.getCookie("lang");
if (!lang) {
if (window.navigator) {
lang = window.navigator.language || window.navigator.userLanguage;
if (LanguageManager.isSupportLanguage(lang)) {
CookieManager.setCookie("lang", lang, 150);
} else {
@ -760,30 +756,43 @@ class LanguageManager {
window.location.reload();
}
}
return lang;
}
static setLanguage(language) {
if (!LanguageManager.isSupportLanguage(language)) {
language = "en-US";
}
CookieManager.setCookie("lang", language, 150);
window.location.reload();
}
static isSupportLanguage(language) {
const languageFilter = LanguageManager.supportedLanguages.filter((lang) => {
return lang.value === language
})
return languageFilter.length > 0;
}
}
}
class DeviceUtils {
static isMobile() {
return window.innerWidth <= 768;
}
const MediaQueryMixin = {
data() {
return {
isMobile: window.innerWidth <= 768,
};
},
methods: {
updateDeviceType() {
this.isMobile = window.innerWidth <= 768;
},
},
mounted() {
window.addEventListener('resize', this.updateDeviceType);
},
beforeDestroy() {
window.removeEventListener('resize', this.updateDeviceType);
},
}

View file

@ -2,30 +2,30 @@
<template slot="actions" slot-scope="text, client, index">
<a-tooltip>
<template slot="title">{{ i18n "qrCode" }}</template>
<a-icon style="font-size: 24px;" class="normal-icon" type="qrcode" v-if="record.hasLink()" @click="showQrcode(record.id,client);"></a-icon>
<a-icon :style="{ fontSize: '24px' }" class="normal-icon" type="qrcode" v-if="record.hasLink()" @click="showQrcode(record.id,client);"></a-icon>
</a-tooltip>
<a-tooltip>
<template slot="title">{{ i18n "pages.client.edit" }}</template>
<a-icon style="font-size: 24px;" class="normal-icon" type="edit" @click="openEditClient(record.id,client);"></a-icon>
<a-icon :style="{ fontSize: '24px' }" class="normal-icon" type="edit" @click="openEditClient(record.id,client);"></a-icon>
</a-tooltip>
<a-tooltip>
<template slot="title">{{ i18n "info" }}</template>
<a-icon style="font-size: 24px;" class="normal-icon" type="info-circle" @click="showInfo(record.id,client);"></a-icon>
<a-icon :style="{ fontSize: '24px' }" class="normal-icon" type="info-circle" @click="showInfo(record.id,client);"></a-icon>
</a-tooltip>
<a-tooltip>
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
<a-popconfirm @confirm="resetClientTraffic(client,record.id,false)" title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme" ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'>
<a-icon slot="icon" type="question-circle-o" :style="themeSwitcher.isDarkTheme ? 'color: var(--color-primary-100)' : 'color: var(--color-primary-100)'"></a-icon>
<a-icon style="font-size: 24px; cursor: pointer;" class="normal-icon" type="retweet" v-if="client.email.length > 0"></a-icon>
<a-icon slot="icon" type="question-circle-o" :style="{ color: 'var(--color-primary-100)'}"></a-icon>
<a-icon :style="{ fontSize: '24px', cursor: 'pointer' }" class="normal-icon" type="retweet" v-if="client.email.length > 0"></a-icon>
</a-popconfirm>
</a-tooltip>
<a-tooltip>
<template slot="title">
<span style="color: #FF4D4F"> {{ i18n "delete"}}</span>
<span :style="{ color: '#FF4D4F' }"> {{ i18n "delete"}}</span>
</template>
<a-popconfirm @confirm="delClient(record.id,client,false)" title='{{ i18n "pages.inbounds.deleteClientContent"}}' :overlay-class-name="themeSwitcher.currentTheme" ok-text='{{ i18n "delete"}}' ok-type="danger" cancel-text='{{ i18n "cancel"}}'>
<a-icon slot="icon" type="question-circle-o" style="color: #e04141"></a-icon>
<a-icon style="font-size: 24px; cursor: pointer;" class="delete-icon" type="delete" v-if="isRemovable(record.id)"></a-icon>
<a-icon slot="icon" type="question-circle-o" :style="{ color: '#e04141' }"></a-icon>
<a-icon :style="{ fontSize: '24px', cursor: 'pointer' }" class="delete-icon" type="delete" v-if="isRemovable(record.id)"></a-icon>
</a-popconfirm>
</a-tooltip>
</template>
@ -124,9 +124,9 @@
</template>
</span>
</template>
<a-tag style="min-width: 50px; border: none;" :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
<a-tag :style="{ minWidth: '50px', border: 'none' }" :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
</a-popover>
<a-tag v-else :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)" style="border: none;" class="infinite-tag">
<a-tag v-else :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)" :style="{ border: 'none' }" class="infinite-tag">
<svg height="10px" width="14px" viewBox="0 0 640 512" fill="currentColor">
<path d="M484.4 96C407 96 349.2 164.1 320 208.5C290.8 164.1 233 96 155.6 96C69.75 96 0 167.8 0 256s69.75 160 155.6 160C233.1 416 290.8 347.9 320 303.5C349.2 347.9 407 416 484.4 416C570.3 416 640 344.2 640 256S570.3 96 484.4 96zM155.6 368C96.25 368 48 317.8 48 256s48.25-112 107.6-112c67.75 0 120.5 82.25 137.1 112C276 285.8 223.4 368 155.6 368zM484.4 368c-67.75 0-120.5-82.25-137.1-112C364 226.2 416.6 144 484.4 144C543.8 144 592 194.2 592 256S543.8 368 484.4 368z" fill="currentColor"></path>
</svg>
@ -135,27 +135,27 @@
</template>
<template slot="actionMenu" slot-scope="text, client, index">
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="ellipsis" style="font-size: 20px;"></a-icon>
<a-icon @click="e => e.preventDefault()" type="ellipsis" :style="{ fontSize: '20px' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item v-if="record.hasLink()" @click="showQrcode(record.id,client);">
<a-icon style="font-size: 14px;" type="qrcode"></a-icon>
<a-icon :style="{ fontSize: '14px' }" type="qrcode"></a-icon>
{{ i18n "qrCode" }}
</a-menu-item>
<a-menu-item @click="openEditClient(record.id,client);">
<a-icon style="font-size: 14px;" type="edit"></a-icon>
<a-icon :style="{ fontSize: '14px' }" type="edit"></a-icon>
{{ i18n "pages.client.edit" }}
</a-menu-item>
<a-menu-item @click="showInfo(record.id,client);">
<a-icon style="font-size: 14px;" type="info-circle"></a-icon>
<a-icon :style="{ fontSize: '14px' }" type="info-circle"></a-icon>
{{ i18n "info" }}
</a-menu-item>
<a-menu-item @click="resetClientTraffic(client,record.id)" v-if="client.email.length > 0">
<a-icon style="font-size: 14px;" type="retweet"></a-icon>
<a-icon :style="{ fontSize: '14px' }" type="retweet"></a-icon>
{{ i18n "pages.inbounds.resetTraffic" }}
</a-menu-item>
<a-menu-item v-if="isRemovable(record.id)" @click="delClient(record.id,client)">
<a-icon style="font-size: 14px;" type="delete"></a-icon>
<span style="color: #FF4D4F"> {{ i18n "delete"}}</span>
<a-icon :style="{ fontSize: '14px' }" type="delete"></a-icon>
<span :style="{ color: '#FF4D4F' }"> {{ i18n "delete"}}</span>
</a-menu-item>
<a-menu-item>
<a-switch v-model="client.enable" size="small" @change="switchEnableClient(record.id,client)"></a-switch>
@ -169,10 +169,10 @@
<template slot="content">
<table>
<tr>
<td colspan="3" style="text-align: center;">{{ i18n "pages.inbounds.traffic" }}</td>
<td colspan="3" :style="{ textAlign: 'center' }">{{ i18n "pages.inbounds.traffic" }}</td>
</tr>
<tr>
<td width="80px" style="margin:0; text-align: right;font-size: 1em;"> [[ SizeFormatter.sizeFormat(getUpStats(record, client.email) + getDownStats(record, client.email)) ]] </td>
<td width="80px" :style="{ margin: '0', textAlign: 'right', fontSize: '1em' }"> [[ SizeFormatter.sizeFormat(getUpStats(record, client.email) + getDownStats(record, client.email)) ]] </td>
<td width="120px" v-if="!client.enable">
<a-progress :stroke-color="themeSwitcher.isDarkTheme ? 'rgb(72 84 105)' : '#bcbcbc'" :show-info="false" :percent="statsProgress(record, client.email)" />
</td>
@ -202,14 +202,14 @@
</td>
</tr>
<tr>
<td colspan="3" style="text-align: center;">
<a-divider style="margin: 0; border-collapse: separate;"></a-divider>
<td colspan="3" :style="{ textAlign: 'center' }">
<a-divider :style="{ margin: '0', borderCollapse: 'separate' }"></a-divider>
{{ i18n "pages.inbounds.expireDate" }}
</td>
</tr>
<tr>
<template v-if="client.expiryTime !=0 && client.reset >0">
<td width="80px" style="margin:0; text-align: right;font-size: 1em;"> [[ remainedDays(client.expiryTime) ]] </td>
<td width="80px" :style="{ margin: '0', textAlign: 'right', fontSize: '1em' }"> [[ remainedDays(client.expiryTime) ]] </td>
<td width="120px" class="infinite-bar">
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
@ -230,7 +230,7 @@
<td width="60px">[[ client.reset + "d" ]]</td>
</template>
<template v-else>
<td colspan="3" style="text-align: center;">
<td colspan="3" :style="{ textAlign: 'center' }">
<a-popover v-if="client.expiryTime != 0" :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<span v-if="client.expiryTime < 0">{{ i18n "pages.client.delayedStart" }}
@ -244,7 +244,7 @@
</template>
</span>
</template>
<a-tag style="min-width: 50px; border: none;" :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
<a-tag :style="{ minWidth: '50px', border: 'none' }" :color="ColorUtils.userExpiryColor(app.expireDiff, client, themeSwitcher.isDarkTheme)"> [[ remainedDays(client.expiryTime) ]] </a-tag>
</a-popover>
<a-tag v-else :color="client.enable ? 'purple' : themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc'" class="infinite-tag">
<svg height="10px" width="14px" viewBox="0 0 640 512" fill="currentColor">
@ -257,8 +257,8 @@
</table>
</template>
<a-badge>
<a-icon v-if="!client.enable" slot="count" type="pause-circle" theme="filled" :style="'color: ' + themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc'"></a-icon>
<a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
<a-icon v-if="!client.enable" slot="count" type="pause-circle" theme="filled" :style="{ color: themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc' }"></a-icon>
<a-button shape="round" size="small" :style="{ fontSize: '14px', padding: '0 10px' }">
<a-icon type="solution"></a-icon>
</a-button>
</a-badge>

View file

@ -5,7 +5,7 @@
@input="$emit('input', convertToGregorian($event.target.value)); jalaliDatepicker.hide();"
:placeholder="placeholder">
<template #addonAfter>
<a-icon type="calendar" style="font-size: 14px; opacity: 0.5;" />
<a-icon type="calendar" :style="{ fontSize: '14px', opacity: '0.5' }" />
</template>
</a-input>
</div>

View file

@ -1,6 +1,6 @@
{{define "component/settingListItem"}}
<a-list-item :style="{ padding: padding }">
<a-row>
<a-row :gutter="[8,16]">
<a-col :lg="24" :xl="12">
<a-list-item-meta>
<template #title>

View file

@ -1,5 +1,5 @@
{{define "component/sortableTableTrigger"}}
<a-icon type="drag" class="sortable-icon" style="cursor: move;" @mouseup="mouseUpHandler" @mousedown="mouseDownHandler"
<a-icon type="drag" class="sortable-icon" :style="{ cursor: 'move' }" @mouseup="mouseUpHandler" @mousedown="mouseDownHandler"
@click="clickHandler" />
{{end}}

View file

@ -8,13 +8,13 @@
</span>
<a-menu-item id="change-theme" class="ant-menu-theme-switch" @mousedown="themeSwitcher.animationsOff()">
<span>{{ i18n "menu.dark" }}</span>
<a-switch style="margin-left: 2px;" size="small" :default-checked="themeSwitcher.isDarkTheme"
<a-switch :style="{ marginLeft: '2px' }" size="small" :default-checked="themeSwitcher.isDarkTheme"
@change="themeSwitcher.toggleTheme()"></a-switch>
</a-menu-item>
<a-menu-item id="change-theme-ultra" v-if="themeSwitcher.isDarkTheme" class="ant-menu-theme-switch"
@mousedown="themeSwitcher.animationsOffUltra()">
<span>{{ i18n "menu.ultraDark" }}</span>
<a-checkbox style="margin-left: 2px;" :checked="themeSwitcher.isUltra"
<a-checkbox :style="{ marginLeft: '2px' }" :checked="themeSwitcher.isUltra"
@click="themeSwitcher.toggleUltra()"></a-checkbox>
</a-menu-item>
</a-sub-menu>

View file

@ -66,7 +66,7 @@
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input-number style="width: 50%" v-model.number="client.tgId" min="0"></a-input-number>
<a-input-number :style="{ width: '50%' }" v-model.number="client.tgId" min="0"></a-input-number>
</a-form-item>
<a-form-item v-if="client.email" label='{{ i18n "comment" }}'>
<a-input v-model.trim="client.comment"></a-input>
@ -97,7 +97,7 @@
<template slot="title">
<span>{{ i18n "pages.inbounds.IPLimitlogclear" }}</span>
</template>
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete" @click="clearDBClientIps(client.email)"></a-icon>
</span>
</a-tooltip>

View file

@ -54,7 +54,7 @@
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-date-picker style="width: 100%;" v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }"
<a-date-picker :style="{ width: '100%' }" v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }"
format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme"
v-model="dbInbound._expiryTime"></a-date-picker>
<a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}'

View file

@ -1,6 +1,6 @@
{{define "form/outbound"}}
<!-- base -->
<a-tabs :active-key="outModal.activeKey" style="padding: 0; background-color: transparent;" @change="(activeKey) => {outModal.toggleJson(activeKey == '2'); }">
<a-tabs :active-key="outModal.activeKey" :style="{ padding: '0', backgroundColor: 'transparent' }" @change="(activeKey) => {outModal.toggleJson(activeKey == '2'); }">
<a-tab-pane key="1" tab="Form">
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "protocol" }}'>
@ -60,9 +60,9 @@
<!-- Noise Configurations -->
<a-form v-for="(noise, index) in outbound.settings.noises" :key="index" :colon="false" :label-col="{ md: {span:8} }"
:wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;"> Noise [[ index + 1 ]]
<a-divider :style="{ margin: '0' }"> Noise [[ index + 1 ]]
<a-icon v-if="outbound.settings.noises.length > 1" type="delete" @click="() => outbound.settings.delNoise(index)"
style="color: rgb(255, 77, 79); cursor: pointer;"></a-icon>
:style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
</a-divider>
<a-form-item label='Type'>
<a-select v-model="noise.type" :dropdown-class-name="themeSwitcher.currentTheme">
@ -164,7 +164,7 @@
<a-button icon="plus" type="primary" size="small" @click="outbound.settings.addPeer()"></a-button>
</a-form-item>
<a-form v-for="(peer, index) in outbound.settings.peers" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;"> Peer [[ index + 1 ]] <a-icon v-if="outbound.settings.peers.length>1" type="delete" @click="() => outbound.settings.delPeer(index)" style="color: rgb(255, 77, 79);cursor: pointer;"></a-icon>
<a-divider :style="{ margin: '0' }"> Peer [[ index + 1 ]] <a-icon v-if="outbound.settings.peers.length>1" type="delete" @click="() => outbound.settings.delPeer(index)" :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
</a-divider>
<a-form-item label='{{ i18n "pages.xray.wireguard.endpoint" }}'>
<a-input v-model.trim="peer.endpoint"></a-input>
@ -180,7 +180,7 @@
{{ i18n "pages.xray.wireguard.allowedIPs" }}
<a-button icon="plus" type="primary" size="small" @click="peer.allowedIPs.push('')"></a-button>
</template>
<template v-for="(aip, index) in peer.allowedIPs" style="margin-bottom: 10px;">
<template v-for="(aip, index) in peer.allowedIPs" :style="{ marginBottom: '10px' }">
<a-input v-model.trim="peer.allowedIPs[index]">
<a-button icon="minus" v-if="peer.allowedIPs.length>1" slot="addonAfter" size="small" @click="peer.allowedIPs.splice(index, 1)"></a-button>
</a-input>
@ -444,10 +444,10 @@
</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-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-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"></a-input>
@ -506,11 +506,11 @@
</a-form>
</a-tab-pane>
<a-tab-pane key="2" tab="JSON" force-render="true">
<a-space direction="vertical" :size="10" style="margin-top: 10px;">
<a-space direction="vertical" :size="10" :style="{ marginTop: '10px' }">
<a-input addon-before='{{ i18n "pages.xray.outbound.link" }}' v-model.trim="outModal.link" placeholder="vmess:// vless:// trojan:// ss://">
<a-icon slot="addonAfter" type="form" @click="convertLink"></a-icon>
</a-input>
<textarea style="position:absolute; left: -800px;" id="outboundJson"></textarea>
<textarea :style="{ position: 'absolute', left: '-800px' }" id="outboundJson"></textarea>
</a-space>
</a-tab-pane>
</a-tabs>

View file

@ -1,6 +1,6 @@
{{define "form/http"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<table style="width: 100%; text-align: center; margin: 1rem 0;">
<table :style="{ width: '100%', textAlign: 'center', margin: '1rem 0' }">
<tr>
<td width="45%">{{ i18n "username" }}</td>
<td width="45%">{{ i18n "password" }}</td>
@ -9,11 +9,11 @@
</td>
</tr>
</table>
<a-input-group compact v-for="(account, index) in inbound.settings.accounts" style="margin-bottom: 10px;">
<a-input style="width: 50%" v-model.trim="account.user" placeholder='{{ i18n "username" }}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input-group compact v-for="(account, index) in inbound.settings.accounts" :style="{ marginBottom: '10px' }">
<a-input :style="{ width: '50%' }" v-model.trim="account.user" placeholder='{{ i18n "username" }}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="account.pass" placeholder='{{ i18n "password" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="account.pass" placeholder='{{ i18n "password" }}'>
<template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.settings.delAccount(index)"></a-button>
</template>

View file

@ -37,7 +37,7 @@
<a-input v-model.trim="inbound.settings.password"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.network" }}'>
<a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="inbound.settings.network" :style="{ width: '100px' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp,udp">TCP,UDP</a-select-option>
<a-select-option value="tcp">TCP</a-select-option>
<a-select-option value="udp">UDP</a-select-option>

View file

@ -10,7 +10,7 @@
<a-switch :checked="inbound.settings.auth === 'password'" @change="checked => inbound.settings.auth = checked ? 'password' : 'noauth'"></a-switch>
</a-form-item>
<template v-if="inbound.settings.auth === 'password'">
<table style="width: 100%; text-align: center; margin: 1rem 0;">
<table :style="{ width: '100%', textAlign: 'center', margin: '1rem 0' }">
<tr>
<td width="45%">{{ i18n "username" }}</td>
<td width="45%">{{ i18n "password" }}</td>
@ -19,11 +19,11 @@
</td>
</tr>
</table>
<a-input-group compact v-for="(account, index) in inbound.settings.accounts" style="margin-bottom: 10px;">
<a-input style="width: 50%" v-model.trim="account.user" placeholder='{{ i18n "username" }}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input-group compact v-for="(account, index) in inbound.settings.accounts" :style="{ marginBottom: '10px' }">
<a-input :style="{ width: '50%' }" v-model.trim="account.user" placeholder='{{ i18n "username" }}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="account.pass" placeholder='{{ i18n "password" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="account.pass" placeholder='{{ i18n "password" }}'>
<template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.settings.delAccount(index)"></a-button>
</template>

View file

@ -27,7 +27,7 @@
<!-- trojan fallbacks -->
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;"> Fallback [[ index + 1 ]] <a-icon type="delete" @click="() => inbound.settings.delFallback(index)" style="color: rgb(255, 77, 79);cursor: pointer;"></a-icon>
<a-divider :style="{ margin: '0' }"> Fallback [[ index + 1 ]] <a-icon type="delete" @click="() => inbound.settings.delFallback(index)" :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
</a-divider>
<a-form-item label='SNI'>
<a-input v-model="fallback.name"></a-input>

View file

@ -27,7 +27,7 @@
<!-- vless fallbacks -->
<a-form v-for="(fallback, index) in inbound.settings.fallbacks" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;"> Fallback [[ index + 1 ]] <a-icon type="delete" @click="() => inbound.settings.delFallback(index)" style="color: rgb(255, 77, 79);cursor: pointer;"></a-icon>
<a-divider :style="{ margin: '0' }"> Fallback [[ index + 1 ]] <a-icon type="delete" @click="() => inbound.settings.delFallback(index)" :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
</a-divider>
<a-form-item label='SNI'>
<a-input v-model="fallback.name"></a-input>
@ -45,6 +45,6 @@
<a-input-number v-model.number="fallback.xver" :min="0" :max="2"></a-input-number>
</a-form-item>
</a-form>
<a-divider style="margin:5px 0;"></a-divider>
<a-divider :style="{ margin: '5px 0' }"></a-divider>
</template>
{{end}}

View file

@ -25,7 +25,7 @@
<a-button icon="plus" type="primary" size="small" @click="inbound.settings.addPeer()"></a-button>
</a-form-item>
<a-form v-for="(peer, index) in inbound.settings.peers" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:0;"> Peer [[ index + 1 ]] <a-icon v-if="inbound.settings.peers.length>1" type="delete" @click="() => inbound.settings.delPeer(index)" style="color: rgb(255, 77, 79);cursor: pointer;"></a-icon>
<a-divider :style="{ margin: '0' }"> Peer [[ index + 1 ]] <a-icon v-if="inbound.settings.peers.length>1" type="delete" @click="() => inbound.settings.delPeer(index)" :style="{ color: 'rgb(255, 77, 79)', cursor: 'pointer' }"></a-icon>
</a-divider>
<a-form-item>
<template slot="label">
@ -62,7 +62,7 @@
{{ i18n "pages.xray.wireguard.allowedIPs" }}
<a-button icon="plus" type="primary" size="small" @click="peer.allowedIPs.push('')"></a-button>
</template>
<template v-for="(aip, index) in peer.allowedIPs" style="margin-bottom: 10px;">
<template v-for="(aip, index) in peer.allowedIPs" :style="{ marginBottom: '10px' }">
<a-input v-model.trim="peer.allowedIPs[index]">
<a-button icon="minus" v-if="peer.allowedIPs.length>1" slot="addonAfter" size="small" @click="peer.allowedIPs.splice(index, 1)"></a-button>
</a-input>

View file

@ -7,7 +7,7 @@
<a-input-number v-model.number="inbound.stream.reality.xver" :min="0"></a-input-number>
</a-form-item>
<a-form-item label='uTLS'>
<a-select v-model="inbound.stream.reality.settings.fingerprint" style="width: 100%"
<a-select v-model="inbound.stream.reality.settings.fingerprint" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
</a-select>

View file

@ -1,25 +1,25 @@
{{define "form/externalProxy"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:5px 0 0;"></a-divider>
<a-divider :style="{ margin: '5px 0 0' }"></a-divider>
<a-form-item label="External Proxy">
<a-switch v-model="externalProxy"></a-switch>
<a-button icon="plus" v-if="externalProxy" type="primary" style="margin-left: 10px" size="small" @click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})"></a-button>
<a-button icon="plus" v-if="externalProxy" type="primary" :style="{ marginLeft: '10px' }" size="small" @click="inbound.stream.externalProxy.push({forceTls: 'same', dest: '', port: 443, remark: ''})"></a-button>
</a-form-item>
<a-input-group style="margin: 8px 0;" compact v-for="(row, index) in inbound.stream.externalProxy">
<a-input-group :style="{ margin: '8px 0' }" compact v-for="(row, index) in inbound.stream.externalProxy">
<template>
<a-tooltip title="Force TLS">
<a-select v-model="row.forceTls" style="width:20%; margin: 0px" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="row.forceTls" :style="{ width: '20%', margin: '0px' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="same">{{ i18n "pages.inbounds.same" }}</a-select-option>
<a-select-option value="none">{{ i18n "none" }}</a-select-option>
<a-select-option value="tls">TLS</a-select-option>
</a-select>
</a-tooltip>
</template>
<a-input style="width: 35%" v-model.trim="row.dest" placeholder='{{ i18n "host" }}'></a-input>
<a-input :style="{ width: '35%' }" v-model.trim="row.dest" placeholder='{{ i18n "host" }}'></a-input>
<a-tooltip title='{{ i18n "pages.inbounds.port" }}'>
<a-input-number style="width: 15%;" v-model.number="row.port" min="1" max="65531"></a-input-number>
<a-input-number :style="{ width: '15%' }" v-model.number="row.port" min="1" max="65531"></a-input-number>
</a-tooltip>
<a-input style="width: 30%; top: 0;" v-model.trim="row.remark" placeholder='{{ i18n "remark" }}'>
<a-input :style="{ width: '50%', top: '0' }" v-model.trim="row.remark" placeholder='{{ i18n "remark" }}'>
<template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.stream.externalProxy.splice(index, 1)"></a-button>
</template>

View file

@ -14,10 +14,10 @@
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.httpupgrade.headers">
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input :style="{ width: '50%' }" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.httpupgrade.removeHeader(index)"></a-button>
</a-input>
</a-input-group>

View file

@ -1,7 +1,7 @@
{{define "form/streamKCP"}}
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "camouflage" }}'>
<a-select v-model="inbound.stream.kcp.type" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="inbound.stream.kcp.type" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="none">None</a-select-option>
<a-select-option value="srtp">SRTP</a-select-option>
<a-select-option value="utp">uTP</a-select-option>

View file

@ -2,7 +2,7 @@
<!-- select stream network -->
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label='{{ i18n "transmission" }}'>
<a-select v-model="inbound.stream.network" style="width: 75%" @change="streamNetworkChange"
<a-select v-model="inbound.stream.network" :style="{ width: '75%' }" @change="streamNetworkChange"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="tcp">TCP (RAW)</a-select-option>
<a-select-option value="kcp">mKCP</a-select-option>

View file

@ -1,5 +1,5 @@
{{define "form/streamSockopt"}}
<a-divider style="margin:5px 0 0;"></a-divider>
<a-divider :style="{ margin: '5px 0 0' }"></a-divider>
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Sockopt">
<a-switch v-model="inbound.stream.sockoptSwitch"></a-switch>
@ -39,17 +39,17 @@
<a-switch v-model.trim="inbound.stream.sockopt.V6Only"></a-switch>
</a-form-item>
<a-form-item label='Domain Strategy'>
<a-select v-model="inbound.stream.sockopt.domainStrategy" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="inbound.stream.sockopt.domainStrategy" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in DOMAIN_STRATEGY_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='TCP Congestion'>
<a-select v-model="inbound.stream.sockopt.tcpcongestion" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="inbound.stream.sockopt.tcpcongestion" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in TCP_CONGESTION_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="TProxy">
<a-select v-model="inbound.stream.sockopt.tproxy" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="inbound.stream.sockopt.tproxy" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="off">Off</a-select-option>
<a-select-option value="redirect">Redirect</a-select-option>
<a-select-option value="tproxy">TProxy</a-select-option>

View file

@ -11,7 +11,7 @@
<a-form v-if="inbound.stream.tcp.type === 'http'" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<!-- tcp request -->
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.request" }}</a-divider>
<a-divider :style="{ margin: '0' }">{{ i18n "pages.inbounds.stream.general.request" }}</a-divider>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
<a-input v-model.trim="inbound.stream.tcp.request.version"></a-input>
</a-form-item>
@ -33,17 +33,17 @@
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.request.headers">
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input :style="{ width: '50%' }" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.tcp.request.removeHeader(index)"></a-button>
</a-input>
</a-input-group>
</a-form-item>
<!-- tcp response -->
<a-divider style="margin:0;">{{ i18n "pages.inbounds.stream.general.response" }}</a-divider>
<a-divider :style="{ margin: '0' }">{{ i18n "pages.inbounds.stream.general.response" }}</a-divider>
<a-form-item label='{{ i18n "pages.inbounds.stream.tcp.version" }}'>
<a-input v-model.trim="inbound.stream.tcp.response.version"></a-input>
</a-form-item>
@ -58,10 +58,10 @@
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.tcp.response.headers">
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input :style="{ width: '50%' }" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<template slot="addonAfter">
<a-button icon="minus" size="small" @click="inbound.stream.tcp.response.removeHeader(index)"></a-button>
</template>

View file

@ -17,10 +17,10 @@
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.ws.headers">
<a-input style="width: 50%" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input :style="{ width: '50%' }" v-model.trim="header.name" placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-input :style="{ width: '50%' }" v-model.trim="header.value" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.ws.removeHeader(index)"></a-button>
</a-input>
</a-input-group>

View file

@ -11,18 +11,18 @@
</a-form-item>
<a-form-item :wrapper-col="{span:24}">
<a-input-group compact v-for="(header, index) in inbound.stream.xhttp.headers">
<a-input style="width: 50%" v-model.trim="header.name"
<a-input :style="{ width: '50%' }" v-model.trim="header.name"
placeholder='{{ i18n "pages.inbounds.stream.general.name"}}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model.trim="header.value"
<a-input :style="{ width: '50%' }" v-model.trim="header.value"
placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button icon="minus" slot="addonAfter" size="small" @click="inbound.stream.xhttp.removeHeader(index)"></a-button>
</a-input>
</a-input-group>
</a-form-item>
<a-form-item label='Mode'>
<a-select v-model="inbound.stream.xhttp.mode" style="width: 50%"
<a-select v-model="inbound.stream.xhttp.mode" :style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in MODE_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>

View file

@ -1,7 +1,7 @@
{{define "form/tlsSettings"}}
<!-- tls enable -->
<a-form v-if="inbound.canEnableTls()" :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<a-divider style="margin:3px 0;"></a-divider>
<a-divider :style="{ margin: '3px 0' }"></a-divider>
<a-form-item label='{{ i18n "security" }}'>
<a-radio-group v-model="inbound.stream.security" button-style="solid">
<a-radio-button value="none">{{ i18n "none" }}</a-radio-button>
@ -23,18 +23,18 @@
</a-form-item>
<a-form-item label="Min/Max Version">
<a-input-group compact>
<a-select v-model="inbound.stream.tls.minVersion" style="width: 50%"
<a-select v-model="inbound.stream.tls.minVersion" :style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
<a-select v-model="inbound.stream.tls.maxVersion" style="width: 50%"
<a-select v-model="inbound.stream.tls.maxVersion" :style="{ width: '50%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-input-group>
</a-form-item>
<a-form-item label="uTLS">
<a-select v-model="inbound.stream.tls.settings.fingerprint" style="width: 100%"
<a-select v-model="inbound.stream.tls.settings.fingerprint" :style="{ width: '100%' }"
: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>
@ -67,9 +67,9 @@
<a-radio-button :value="false">{{ i18n "pages.inbounds.certificateContent" }}</a-radio-button>
</a-radio-group>
<a-button icon="plus" v-if="index === 0" type="primary" size="small" @click="inbound.stream.tls.addCert()"
style="margin-left: 10px"></a-button>
:style="{ marginLeft: '10px' }"></a-button>
<a-button icon="minus" v-if="inbound.stream.tls.certs.length>1" type="primary" size="small"
@click="inbound.stream.tls.removeCert(index)" style="margin-left: 10px"></a-button>
@click="inbound.stream.tls.removeCert(index)" :style="{ marginLeft: '10px' }"></a-button>
</a-form-item>
<template v-if="cert.useFile">
<a-form-item label='{{ i18n "pages.inbounds.publicKey" }}'>
@ -98,7 +98,7 @@
<a-switch v-model="cert.oneTimeLoading"></a-switch>
</a-form-item>
<a-form-item label='Usage Option'>
<a-select v-model="cert.usage" style="width: 50%" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select v-model="cert.usage" :style="{ width: '50%' }" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in USAGE_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>

View file

@ -138,7 +138,7 @@
<a-layout-content>
<a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'>
<transition name="list" appear>
<a-alert type="error" v-if="showAlert" style="margin-bottom: 10px"
<a-alert type="error" v-if="showAlert" :style="{ marginBottom: '10px' }"
message='{{ i18n "secAlertTitle" }}'
color="red"
description='{{ i18n "secAlertSsl" }}'
@ -146,7 +146,7 @@
</a-alert>
</transition>
<transition name="list" appear>
<a-card size="small" style="padding: 16px;" hoverable>
<a-card size="small" :style="{ padding: '16px' }" hoverable>
<a-row>
<a-col :sm="12" :md="6">
<a-custom-statistic title='{{ i18n "pages.inbounds.totalDownUp" }}' :value="`${SizeFormatter.sizeFormat(total.up)} / ${SizeFormatter.sizeFormat(total.down)}`">
@ -241,7 +241,7 @@
<a-icon type="file-done"></a-icon>
{{ i18n "pages.inbounds.resetAllClientTraffics" }}
</a-menu-item>
<a-menu-item key="delDepletedClients" style="color: #FF4D4F;">
<a-menu-item key="delDepletedClients" :style="{ color: '#FF4D4F' }">
<a-icon type="rest"></a-icon>
{{ i18n "pages.inbounds.delDepletedClients" }}
</a-menu-item>
@ -264,7 +264,7 @@
<span>{{ i18n "pages.inbounds.autoRefreshInterval" }}</span>
<a-select v-model="refreshInterval"
:disabled="!isRefreshEnabled"
style="width: 100%;"
:style="{ width: '100%' }"
@change="changeRefreshInterval"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in [5,10,30,60]" :value="key*1000">[[ key ]]s</a-select-option>
@ -276,14 +276,14 @@
</a-button-group>
</template>
<a-space direction="vertical">
<div :style="isMobile ? '' : 'display: flex; align-items: center; justify-content: flex-start;'">
<div :style="isMobile ? {} : { display: 'flex', alignItems: 'center', justifyContent: 'flex-start' }">
<a-switch v-model="enableFilter"
:style="isMobile ? 'margin-bottom: .5rem; display: flex;' : 'margin-right: .5rem;'"
:style="isMobile ? { marginBottom: '.5rem', display: 'flex' } : { marginRight: '.5rem' }"
@change="toggleFilter">
<a-icon slot="checkedChildren" type="search"></a-icon>
<a-icon slot="unCheckedChildren" type="filter"></a-icon>
</a-switch>
<a-input v-if="!enableFilter" v-model.lazy="searchKey" placeholder='{{ i18n "search" }}' autofocus style="max-width: 300px" :size="isMobile ? 'small' : ''"></a-input>
<a-input v-if="!enableFilter" v-model.lazy="searchKey" placeholder='{{ i18n "search" }}' autofocus :style="{ maxWidth: '300px' }" :size="isMobile ? 'small' : ''"></a-input>
<a-radio-group v-if="enableFilter" v-model="filterBy" @change="filterInbounds" button-style="solid" :size="isMobile ? 'small' : ''">
<a-radio-button value="">{{ i18n "none" }}</a-radio-button>
<a-radio-button value="deactive">{{ i18n "disabled" }}</a-radio-button>
@ -301,10 +301,10 @@
:expand-icon-column-index="0"
:indent-size="0"
:row-class-name="dbInbound => (dbInbound.isMultiUser() ? '' : 'hideExpandIcon')"
style="margin-top: 10px">
:style="{ marginTop: '10px' }">
<template slot="action" slot-scope="text, dbInbound">
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more" style="font-size: 20px; text-decoration: solid;"></a-icon>
<a-icon @click="e => e.preventDefault()" type="more" :style="{ fontSize: '20px', textDecoration: 'solid' }"></a-icon>
<a-menu slot="overlay" @click="a => clickAction(a, dbInbound)" :theme="themeSwitcher.currentTheme">
<a-menu-item key="edit">
<a-icon type="edit"></a-icon>
@ -335,7 +335,7 @@
<a-icon type="export"></a-icon>
{{ i18n "pages.inbounds.export"}} - {{ i18n "pages.settings.subSettings" }}
</a-menu-item>
<a-menu-item key="delDepletedClients" style="color: #FF4D4F;">
<a-menu-item key="delDepletedClients" :style="{ color: '#FF4D4F' }">
<a-icon type="rest"></a-icon>
{{ i18n "pages.inbounds.delDepletedClients" }}
</a-menu-item>
@ -357,7 +357,7 @@
<a-icon type="block"></a-icon> {{ i18n "pages.inbounds.clone"}}
</a-menu-item>
<a-menu-item key="delete">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
@ -369,39 +369,39 @@
</a-dropdown>
</template>
<template slot="protocol" slot-scope="text, dbInbound">
<a-tag style="margin:0;" color="purple">[[ dbInbound.protocol ]]</a-tag>
<a-tag :style="{ margin: '0' }" color="purple">[[ dbInbound.protocol ]]</a-tag>
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
<a-tag style="margin:0;" color="green">[[ dbInbound.toInbound().stream.network ]]</a-tag>
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isTls" color="blue">TLS</a-tag>
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isReality" color="blue">Reality</a-tag>
<a-tag :style="{ margin: '0' }" color="green">[[ dbInbound.toInbound().stream.network ]]</a-tag>
<a-tag :style="{ margin: '0' }" v-if="dbInbound.toInbound().stream.isTls" color="blue">TLS</a-tag>
<a-tag :style="{ margin: '0' }" v-if="dbInbound.toInbound().stream.isReality" color="blue">Reality</a-tag>
</template>
</template>
<template slot="clients" slot-scope="text, dbInbound">
<template v-if="clientCount[dbInbound.id]">
<a-tag style="margin:0;" color="green">[[ clientCount[dbInbound.id].clients ]]</a-tag>
<a-tag :style="{ margin: '0' }" color="green">[[ clientCount[dbInbound.id].clients ]]</a-tag>
<a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<div v-for="clientEmail in clientCount[dbInbound.id].deactive"><span>[[ clientEmail ]]</span></div>
</template>
<a-tag style="margin:0; padding: 0 2px;" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<div v-for="clientEmail in clientCount[dbInbound.id].depleted"><span>[[ clientEmail ]]</span></div>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<div v-for="clientEmail in clientCount[dbInbound.id].expiring"><span>[[ clientEmail ]]</span></div>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "online" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<div v-for="clientEmail in clientCount[dbInbound.id].online"><span>[[ clientEmail ]]</span></div>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="blue" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="blue" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag>
</a-popover>
</template>
</template>
@ -443,7 +443,7 @@
<template v-else slot="content">
[[ DateUtil.convertToJalalian(moment(dbInbound.expiryTime)) ]]
</template>
<a-tag style="min-width: 50px;" :color="ColorUtils.usageColor(new Date().getTime(), app.expireDiff, dbInbound._expiryTime)">
<a-tag :style="{ minWidth: '50px' }" :color="ColorUtils.usageColor(new Date().getTime(), app.expireDiff, dbInbound._expiryTime)">
[[ remainedDays(dbInbound._expiryTime) ]]
</a-tag>
</a-popover>
@ -460,11 +460,11 @@
<tr>
<td>{{ i18n "pages.inbounds.protocol" }}</td>
<td>
<a-tag style="margin:0;" color="purple">[[ dbInbound.protocol ]]</a-tag>
<a-tag :style="{ margin: '0' }" color="purple">[[ dbInbound.protocol ]]</a-tag>
<template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS">
<a-tag style="margin:0;" color="blue">[[ dbInbound.toInbound().stream.network ]]</a-tag>
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isTls" color="green">tls</a-tag>
<a-tag style="margin:0;" v-if="dbInbound.toInbound().stream.isReality" color="green">reality</a-tag>
<a-tag :style="{ margin: '0' }" color="blue">[[ dbInbound.toInbound().stream.network ]]</a-tag>
<a-tag :style="{ margin: '0' }" v-if="dbInbound.toInbound().stream.isTls" color="green">tls</a-tag>
<a-tag :style="{ margin: '0' }" v-if="dbInbound.toInbound().stream.isReality" color="green">reality</a-tag>
</template>
</td>
</tr>
@ -475,30 +475,30 @@
<tr v-if="clientCount[dbInbound.id]">
<td>{{ i18n "clients" }}</td>
<td>
<a-tag style="margin:0;" color="blue">[[ clientCount[dbInbound.id].clients ]]</a-tag>
<a-tag :style="{ margin: '0' }" color="blue">[[ clientCount[dbInbound.id].clients ]]</a-tag>
<a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<p v-for="clientEmail in clientCount[dbInbound.id].deactive">[[ clientEmail ]]</p>
</template>
<a-tag style="margin:0; padding: 0 2px;" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" v-if="clientCount[dbInbound.id].deactive.length">[[ clientCount[dbInbound.id].deactive.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<p v-for="clientEmail in clientCount[dbInbound.id].depleted">[[ clientEmail ]]</p>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="red" v-if="clientCount[dbInbound.id].depleted.length">[[ clientCount[dbInbound.id].depleted.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<p v-for="clientEmail in clientCount[dbInbound.id].expiring">[[ clientEmail ]]</p>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="orange" v-if="clientCount[dbInbound.id].expiring.length">[[ clientCount[dbInbound.id].expiring.length ]]</a-tag>
</a-popover>
<a-popover title='{{ i18n "online" }}' :overlay-class-name="themeSwitcher.currentTheme">
<template slot="content">
<p v-for="clientEmail in clientCount[dbInbound.id].online">[[ clientEmail ]]</p>
</template>
<a-tag style="margin:0; padding: 0 2px;" color="green" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag>
<a-tag :style="{ margin: '0', padding: '0 2px' }" color="green" v-if="clientCount[dbInbound.id].online.length">[[ clientCount[dbInbound.id].online.length ]]</a-tag>
</a-popover>
</td>
</tr>
@ -535,7 +535,7 @@
<tr>
<td>{{ i18n "pages.inbounds.expireDate" }}</td>
<td>
<a-tag style="min-width: 50px; text-align: center;" v-if="dbInbound.expiryTime > 0"
<a-tag :style="{ minWidth: '50px', textAlign: 'center' }" v-if="dbInbound.expiryTime > 0"
:color="dbInbound.isExpiry? 'red': 'blue'">
<template v-if="app.datepicker === 'gregorian'">
[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]
@ -544,7 +544,7 @@
[[ DateUtil.convertToJalalian(moment(dbInbound.expiryTime)) ]]
</template>
</a-tag>
<a-tag v-else style="text-align: center;" color="purple" class="infinite-tag">
<a-tag v-else :style="{ textAlign: 'center' }" color="purple" class="infinite-tag">
<svg height="10px" width="14px" viewBox="0 0 640 512" fill="currentColor">
<path d="M484.4 96C407 96 349.2 164.1 320 208.5C290.8 164.1 233 96 155.6 96C69.75 96 0 167.8 0 256s69.75 160 155.6 160C233.1 416 290.8 347.9 320 303.5C349.2 347.9 407 416 484.4 416C570.3 416 640 344.2 640 256S570.3 96 484.4 96zM155.6 368C96.25 368 48 317.8 48 256s48.25-112 107.6-112c67.75 0 120.5 82.25 137.1 112C276 285.8 223.4 368 155.6 368zM484.4 368c-67.75 0-120.5-82.25-137.1-112C364 226.2 416.6 144 484.4 144C543.8 144 592 194.2 592 256S543.8 368 484.4 368z" fill="currentColor"></path>
</svg>
@ -554,8 +554,8 @@
</table>
</template>
<a-badge>
<a-icon v-if="!dbInbound.enable" slot="count" type="pause-circle" :style="'color: ' + themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc'"></a-icon>
<a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
<a-icon v-if="!dbInbound.enable" slot="count" type="pause-circle" :style="{ color: themeSwitcher.isDarkTheme ? '#2c3950' : '#bcbcbc' }"></a-icon>
<a-button shape="round" size="small" :style="{ fontSize: '14px', padding: '0 10px' }">
<a-icon type="info"></a-icon>
</a-button>
</a-badge>
@ -567,7 +567,7 @@
:columns="isMobile ? innerMobileColumns : innerColumns"
:data-source="getInboundClients(record)"
:pagination=pagination(getInboundClients(record))
:style="isMobile ? 'margin: -10px 2px -11px;' : 'margin: -10px 22px -11px;'">
:style="{ margin: `-10px ${isMobile ? '2px' : '22px'} -11px` }">
{{template "component/aClientTable"}}
</a-table>
</template>
@ -678,6 +678,7 @@
const app = new Vue({
delimiters: ['[[', ']]'],
el: '#app',
mixins: [MediaQueryMixin],
data: {
themeSwitcher,
persianDatepicker,
@ -709,7 +710,6 @@
showAlert: false,
ipLimitEnable: false,
pageSize: 50,
isMobile: DeviceUtils.isMobile(),
},
methods: {
loading(spinning = true) {
@ -1471,9 +1471,6 @@
return p;
}
return false
},
onResize() {
this.isMobile = DeviceUtils.isMobile();
}
},
watch: {
@ -1485,8 +1482,6 @@
if (window.location.protocol !== "https:") {
this.showAlert = true;
}
window.addEventListener('resize', this.onResize);
this.onResize();
this.loading();
this.getDefaultSettings();
if (this.isRefreshEnabled) {

View file

@ -84,7 +84,7 @@
<a-layout-content>
<a-spin :spinning="spinning" :delay="200" :tip="loadingTip">
<transition name="list" appear>
<a-alert type="error" v-if="showAlert" style="margin-bottom: 10px"
<a-alert type="error" v-if="showAlert" :style="{ marginBottom: '10px' }"
message='{{ i18n "secAlertTitle" }}'
color="red"
description='{{ i18n "secAlertSsl" }}'
@ -94,8 +94,8 @@
<transition name="list" appear>
<template>
<a-row v-if="!status.isLoaded">
<a-card hoverable style="text-align: center; padding: 30px 0; margin-top: 10px; background: transparent;">
<a-spin tip="Loading..."></a-spin>
<a-card hoverable :style="{ textAlign: 'center', padding: '30px 0', marginTop: '10px', background: 'transparent' }">
<a-spin tip='{{ i18n "loading" }}'></a-spin>
</a-card>
</a-row>
<a-row v-else>
@ -104,44 +104,69 @@
<a-row>
<a-col :sm="24" :md="12">
<a-row>
<a-col :span="12" style="text-align: center">
<a-col :span="12" :style="{ textAlign: 'center' }">
<a-progress type="dashboard" status="normal"
:stroke-color="status.cpu.color"
:percent="status.cpu.percent"></a-progress>
<div><b>CPU:</b> [[ CPUFormatter.cpuCoreFormat(status.cpuCores) ]] <a-tooltip>
<a-icon type="area-chart"></a-icon>
<template slot="title">
<div><b>Logical Processors:</b> [[ (status.logicalPro) ]]</div>
<div><b>Speed:</b> [[ CPUFormatter.cpuSpeedFormat(status.cpuSpeedMhz) ]]</div>
</template>
</a-tooltip></div>
<div>
<span>{{ i18n "pages.index.cpu" }}</span>
<a-tooltip>
<a-icon type="area-chart"></a-icon>
<template slot="title">
<div><b>{{ i18n "pages.index.cpuCores" }}:</b> [[ (status.cpuCores) ]]</div>
<div><b>{{ i18n "pages.index.logicalProcessors" }}:</b> [[ (status.logicalPro) ]]</div>
<div><b>{{ i18n "pages.index.frequency" }}:</b> [[ CPUFormatter.cpuSpeedFormat(status.cpuSpeedMhz) ]]</div>
</template>
</a-tooltip>
</div>
</a-col>
<a-col :span="12" style="text-align: center">
<a-col :span="12" :style="{ textAlign: 'center' }">
<a-progress type="dashboard" status="normal"
:stroke-color="status.mem.color"
:percent="status.mem.percent"></a-progress>
<div>
<b>{{ i18n "pages.index.memory"}}:</b> [[ SizeFormatter.sizeFormat(status.mem.current) ]] / [[ SizeFormatter.sizeFormat(status.mem.total) ]]
<span>{{ i18n "pages.index.memory" }}</span>
<a-tooltip>
<a-icon type="area-chart"></a-icon>
<template slot="title">
<div><b>{{ i18n "pages.index.storageUsed" }}:</b> [[ SizeFormatter.sizeFormat(status.mem.current) ]]</div>
<div><b>{{ i18n "pages.index.storageTotal" }}:</b> [[ SizeFormatter.sizeFormat(status.mem.total) ]]</div>
</template>
</a-tooltip>
</div>
</a-col>
</a-row>
</a-col>
<a-col :sm="24" :md="12">
<a-row>
<a-col :span="12" style="text-align: center">
<a-col :span="12" :style="{ textAlign: 'center' }">
<a-progress type="dashboard" status="normal"
:stroke-color="status.swap.color"
:percent="status.swap.percent"></a-progress>
<div>
<b>Swap:</b> [[ SizeFormatter.sizeFormat(status.swap.current) ]] / [[ SizeFormatter.sizeFormat(status.swap.total) ]]
<span>{{ i18n "pages.index.swap" }}</span>
<a-tooltip>
<a-icon type="area-chart"></a-icon>
<template slot="title">
<div><b>{{ i18n "pages.index.storageUsed" }}:</b> [[ SizeFormatter.sizeFormat(status.swap.current) ]]</div>
<div><b>{{ i18n "pages.index.storageTotal" }}:</b> [[ SizeFormatter.sizeFormat(status.swap.total) ]]</div>
</template>
</a-tooltip>
</div>
</a-col>
<a-col :span="12" style="text-align: center">
<a-col :span="12" :style="{ textAlign: 'center' }">
<a-progress type="dashboard" status="normal"
:stroke-color="status.disk.color"
:percent="status.disk.percent"></a-progress>
<div>
<b>{{ i18n "pages.index.hard"}}:</b> [[ SizeFormatter.sizeFormat(status.disk.current) ]] / [[ SizeFormatter.sizeFormat(status.disk.total) ]]
<span>{{ i18n "pages.index.storage" }}</span>
<a-tooltip>
<a-icon type="area-chart"></a-icon>
<template slot="title">
<div><b>{{ i18n "pages.index.storageUsed" }}:</b> [[ SizeFormatter.sizeFormat(status.disk.current) ]]</div>
<div><b>{{ i18n "pages.index.storageTotal" }}:</b> [[ SizeFormatter.sizeFormat(status.disk.total) ]]</div>
</template>
</a-tooltip>
</div>
</a-col>
</a-row>
@ -160,31 +185,38 @@
</a-space>
</template>
<template #extra>
<template v-if="status.xray.state != State.Error">
<a-badge status="processing" class="running-animation" :text="status.xray.state" :color="status.xray.color" style="text-transform: capitalize;"/>
<template v-if="status.xray.state != 'error'">
<a-badge status="processing" class="running-animation" :text="status.xray.stateMsg" :color="status.xray.color"/>
</template>
<template v-else>
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
<a-tag color="purple" style="cursor: pointer; float: right;" @click="openLogs()">{{ i18n "pages.index.logs" }}</a-tag>
<span slot="title">
<a-row type="flex" align="middle" justify="space-between">
<a-col>
<span>{{ i18n "pages.index.xrayErrorPopoverTitle" }}</span>
</a-col>
<a-col>
<a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openLogs()"></a-tag>
</a-col>
</a-row>
</span>
<template slot="content">
<p style="max-width: 400px" v-for="line in status.xray.errorMsg.split('\n')">[[ line ]]</p>
<span :style="{ maxWidth: '400px' }" v-for="line in status.xray.errorMsg.split('\n')">[[ line ]]</span>
</template>
<a-badge :text="status.xray.state" :color="status.xray.color" style="text-transform: capitalize;"/>
<a-badge :text="status.xray.stateMsg" :color="status.xray.color"/>
</a-popover>
</template>
</template>
<template #actions>
<a-space direction="horizontal" @click="stopXrayService" style="justify-content: center;">
<a-space direction="horizontal" @click="stopXrayService" :style="{ justifyContent: 'center' }">
<a-icon type="poweroff"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.stopXray" }}</span>
</a-space>
<a-space direction="horizontal" @click="restartXrayService" style="justify-content: center;">
<a-space direction="horizontal" @click="restartXrayService" :style="{ justifyContent: 'center' }">
<a-icon type="reload"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.restartXray" }}</span>
</a-space>
<a-space direction="horizontal" @click="openSelectV2rayVersion" style="justify-content: center;">
<a-space direction="horizontal" @click="openSelectV2rayVersion" :style="{ justifyContent: 'center' }">
<a-icon type="tool"></a-icon>
<span v-if="!isMobile">
[[ status.xray.version != 'Unknown' ? `v${status.xray.version}` : '{{ i18n "pages.index.xraySwitch" }}' ]]
@ -196,15 +228,15 @@
<a-col :sm="24" :lg="12">
<a-card title='{{ i18n "menu.link" }}' hoverable>
<template #actions>
<a-space direction="horizontal" @click="openLogs()" style="justify-content: center;">
<a-space direction="horizontal" @click="openLogs()" :style="{ justifyContent: 'center' }">
<a-icon type="bars"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.logs" }}</span>
</a-space>
<a-space direction="horizontal" @click="openConfig" style="justify-content: center;">
<a-space direction="horizontal" @click="openConfig" :style="{ justifyContent: 'center' }">
<a-icon type="control"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.config" }}</span>
</a-space>
<a-space direction="horizontal" @click="openBackup" style="justify-content: center;">
<a-space direction="horizontal" @click="openBackup" :style="{ justifyContent: 'center' }">
<a-icon type="cloud-server"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.backup" }}</span>
</a-space>
@ -237,13 +269,13 @@
</a-col>
<a-col :sm="24" :lg="12">
<a-card title='{{ i18n "usage"}}' hoverable>
<a-tag color="green"> RAM: [[ SizeFormatter.sizeFormat(status.appStats.mem) ]] </a-tag>
<a-tag color="green"> Threads: [[ status.appStats.threads ]] </a-tag>
<a-tag color="green"> {{ i18n "pages.index.memory" }}: [[ SizeFormatter.sizeFormat(status.appStats.mem) ]] </a-tag>
<a-tag color="green"> {{ i18n "pages.index.threads" }}: [[ status.appStats.threads ]] </a-tag>
</a-card>
</a-col>
<a-col :sm="24" :lg="12">
<a-card title='{{ i18n "pages.index.overallSpeed" }}' hoverable>
<a-row>
<a-row :gutter="isMobile ? [8,8] : 0">
<a-col :span="12">
<a-custom-statistic title='{{ i18n "pages.index.upload" }}' :value="SizeFormatter.sizeFormat(status.netIO.up)">
<template #prefix>
@ -269,7 +301,7 @@
</a-col>
<a-col :sm="24" :lg="12">
<a-card title='{{ i18n "pages.index.totalData" }}' hoverable>
<a-row>
<a-row :gutter="isMobile ? [8,8] : 0">
<a-col :span="12">
<a-custom-statistic title='{{ i18n "pages.index.sent" }}' :value="SizeFormatter.sizeFormat(status.netTraffic.sent)">
<template #prefix>
@ -297,15 +329,15 @@
<a-icon :type="showIp ? 'eye' : 'eye-invisible'" :style="{ fontSize: '1rem' }" @click="showIp = !showIp"></a-icon>
</a-tooltip>
</template>
<a-row :class="showIp ? 'ip-visible' : 'ip-hidden'">
<a-col :xs="24" :xxl="12" :style="{ marginTop: isMobile ? '10px' : 0 }">
<a-row :class="showIp ? 'ip-visible' : 'ip-hidden'" :gutter="isMobile ? [8,8] : 0">
<a-col :span="isMobile ? 24 : 12">
<a-custom-statistic title="IPv4" :value="status.publicIP.ipv4">
<template #prefix>
<a-icon type="global" />
</template>
</a-custom-statistic>
</a-col>
<a-col :xs="24" :xxl="12" :style="{ marginTop: isMobile ? '10px' : 0 }">
<a-col :span="isMobile ? 24 : 12">
<a-custom-statistic title="IPv6" :value="status.publicIP.ipv6">
<template #prefix>
<a-icon type="global" />
@ -317,7 +349,7 @@
</a-col>
<a-col :sm="24" :lg="12">
<a-card title='{{ i18n "pages.index.connectionCount" }}' hoverable>
<a-row>
<a-row :gutter="isMobile ? [8,8] : 0">
<a-col :span="12">
<a-custom-statistic title="TCP" :value="status.tcpCount">
<template #prefix>
@ -343,9 +375,9 @@
</a-layout>
<a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}' :closable="true"
@ok="() => versionModal.visible = false" :class="themeSwitcher.currentTheme" footer="">
<a-alert type="warning" style="margin-bottom: 12px; width: 100%;"
<a-alert type="warning" :style="{ marginBottom: '12px', width: '100%' }"
message='{{ i18n "pages.index.xraySwitchClickDesk" }}' show-icon></a-alert>
<a-list class="ant-xray-version-list" bordered style="width: 100%;">
<a-list class="ant-xray-version-list" bordered :style="{ width: '100%' }">
<a-list-item class="ant-xray-version-list-item" v-for="version, index in versionModal.versions">
<a-tag :color="index % 2 == 0 ? 'purple' : 'green'">[[ version ]]</a-tag>
<a-radio :class="themeSwitcher.currentTheme" :checked="version === `v${status.xray.version}`" @click="switchV2rayVersion(version)"></a-radio>
@ -360,15 +392,15 @@
{{ i18n "pages.index.logs" }}
<a-icon :spin="logModal.loading"
type="sync"
style="vertical-align: middle; margin-left: 10px;"
:style="{ verticalAlign: 'middle', marginLeft: '10px' }"
:disabled="logModal.loading"
@click="openLogs()">
</a-icon>
</template>
<a-form layout="inline">
<a-form-item style="margin-right: 0.5rem;">
<a-form-item :style="{ marginRight: '0.5rem' }">
<a-input-group compact>
<a-select size="small" v-model="logModal.rows" style="width:70px;"
<a-select size="small" v-model="logModal.rows" :style="{ width: '70px' }"
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="10">10</a-select-option>
<a-select-option value="20">20</a-select-option>
@ -376,7 +408,7 @@
<a-select-option value="100">100</a-select-option>
<a-select-option value="500">500</a-select-option>
</a-select>
<a-select size="small" v-model="logModal.level" style="width:95px;"
<a-select size="small" v-model="logModal.level" :style="{ width: '95px' }"
@change="openLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option value="debug">Debug</a-select-option>
<a-select-option value="info">Info</a-select-option>
@ -389,13 +421,13 @@
<a-form-item>
<a-checkbox v-model="logModal.syslog" @change="openLogs()">SysLog</a-checkbox>
</a-form-item>
<a-form-item style="float: right;">
<a-form-item :style="{ float: 'right' }">
<a-button type="primary" icon="download"
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(logModal.logs?.join('\n'))" download="x-ui.log">
</a-button>
</a-form-item>
</a-form>
<div class="ant-input" style="height: auto; max-height: 500px; overflow: auto; margin-top: 0.5rem;" v-html="logModal.formattedLogs"></div>
<div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="logModal.formattedLogs"></div>
</a-modal>
<a-modal id="backup-modal"
v-model="backupModal.visible"
@ -403,7 +435,7 @@
:closable="true"
footer=""
:class="themeSwitcher.currentTheme">
<a-list class="ant-backup-list" bordered style="width: 100%;">
<a-list class="ant-backup-list" bordered :style="{ width: '100%' }">
<a-list-item class="ant-backup-list-item">
<a-list-item-meta>
<template #title>{{ i18n "pages.index.exportDatabase" }}</template>
@ -427,13 +459,6 @@
{{template "component/aCustomStatistic" .}}
{{template "modals/textModal"}}
<script>
const State = {
Running: "running",
Stop: "stop",
Error: "error",
}
Object.freeze(State);
class CurTotal {
constructor(current, total) {
@ -478,7 +503,8 @@
this.uptime = 0;
this.appUptime = 0;
this.appStats = {threads: 0, mem: 0, uptime: 0};
this.xray = { state: State.Stop, errorMsg: "", version: "", color: "" };
this.xray = { state: 'stop', stateMsg: "", errorMsg: "", version: "", color: "" };
if (data == null) {
return;
@ -503,17 +529,22 @@
this.appStats = data.appStats;
this.xray = data.xray;
switch (this.xray.state) {
case State.Running:
case 'running':
this.xray.color = "green";
this.xray.stateMsg = '{{ i18n "pages.index.xrayStatusRunning" }}';
break;
case State.Stop:
case 'stop':
this.xray.color = "orange";
this.xray.stateMsg = '{{ i18n "pages.index.xrayStatusStop" }}';
break;
case State.Error:
case 'error':
this.xray.color = "red";
this.xray.stateMsg ='{{ i18n "pages.index.xrayStatusError" }}';
break;
default:
this.xray.color = "gray";
this.xray.stateMsg = '{{ i18n "pages.index.xrayStatusUnknown" }}';
break;
}
}
}
@ -596,6 +627,7 @@
const app = new Vue({
delimiters: ['[[', ']]'],
el: '#app',
mixins: [MediaQueryMixin],
data: {
themeSwitcher,
status: new Status(),
@ -605,8 +637,7 @@
spinning: false,
loadingTip: '{{ i18n "loading"}}',
showAlert: false,
showIp: false,
isMobile: DeviceUtils.isMobile()
showIp: false
},
methods: {
loading(spinning, tip = '{{ i18n "loading"}}') {

View file

@ -451,7 +451,7 @@
<body>
<a-layout id="app" v-cloak :class="themeSwitcher.currentTheme">
<transition name="list" appear>
<a-layout-content class="under" style="min-height: 0;">
<a-layout-content class="under" :style="{ minHeight: '0' }">
<div class="waves-header">
<div class="waves-inner-header"></div>
<svg class="waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
@ -484,10 +484,10 @@
<a-button shape="circle" icon="setting"></a-button>
</a-popover>
</div>
<a-row type="flex" justify="center" align="middle" style="height: 100%; overflow: auto; overflow-x: hidden;">
<a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" style="margin: 3rem 0;">
<a-row type="flex" justify="center" align="middle" :style="{ height: '100%', overflow: 'auto', overflowX: 'hidden' }">
<a-col :xs="22" :sm="20" :md="14" :lg="10" :xl="8" :xxl="6" id="login" :style="{ margin: '3rem 0' }">
<a-row type="flex" justify="center">
<a-col style="width: 100%;">
<a-col :style="{ width: '100%' }">
<h2 class="title headline zoom">
<span class="words-wrapper">
<b class="is-visible">{{ i18n "pages.login.hello" }}</b>
@ -503,18 +503,20 @@
<a-form-item>
<a-input autocomplete="username" name="username" v-model.trim="user.username"
placeholder='{{ i18n "username" }}' @keydown.enter.native="login" autofocus>
<a-icon slot="prefix" type="user" style="font-size: 16px;"></a-icon>
<a-icon slot="prefix" type="user" :style="{ fontSize: '16px' }"></a-icon>
</a-input>
</a-form-item>
<a-form-item>
<a-password-input autocomplete="password" name="password" icon="lock" v-model.trim="user.password"
<a-input-password autocomplete="password" name="password" icon="lock" v-model.trim="user.password"
placeholder='{{ i18n "password" }}' @keydown.enter.native="login">
</a-password-input>
<a-icon slot="prefix" type="lock" :style="{ fontSize: '16px' }"></a-icon>
</a-input-password>
</a-form-item>
<a-form-item v-if="secretEnable">
<a-password-input autocomplete="secret" name="secret" icon="key" v-model.trim="user.loginSecret"
<a-input-password autocomplete="secret" name="secret" icon="lock" v-model.trim="user.loginSecret"
placeholder='{{ i18n "secretToken" }}' @keydown.enter.native="login">
</a-password-input>
<a-icon slot="prefix" type="key" :style="{ fontSize: '16px' }"></a-icon>
</a-input-password>
</a-form-item>
<a-form-item>
<a-row justify="center" class="centered">
@ -538,7 +540,6 @@
</a-layout>
{{template "js" .}}
{{template "component/aThemeSwitch" .}}
{{template "component/aPasswordInput" .}}
<script>
const app = new Vue({
delimiters: ['[[', ']]'],

View file

@ -61,7 +61,7 @@
<a-icon type="question-circle"></a-icon>
</a-tooltip>
</template>
<a-input-number style="width: 50%" v-model.number="clientsBulkModal.tgId" min="0"></a-input-number>
<a-input-number :style="{ width: '50%' }" v-model.number="clientsBulkModal.tgId" min="0"></a-input-number>
</a-form-item>
<a-form-item v-if="app.ipLimitEnable">
<template slot="label">

View file

@ -4,7 +4,7 @@
:class="themeSwitcher.currentTheme"
:ok-text="clientModal.okText" cancel-text='{{ i18n "close" }}'>
<template v-if="isEdit">
<a-tag v-if="isExpiry || isTrafficExhausted" color="red" style="margin-bottom: 10px;display: block;text-align: center;">Account is (Expired|Traffic Ended) And Disabled</a-tag>
<a-tag v-if="isExpiry || isTrafficExhausted" color="red" :style="{ marginBottom: '10px', display: 'block', textAlign: 'center' }">Account is (Expired|Traffic Ended) And Disabled</a-tag>
</template>
{{template "form/client"}}
</a-modal>

View file

@ -16,7 +16,7 @@
</template>
</a-form-item>
<a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced">
<a-select v-model="dnsModal.dnsServer.queryStrategy" style="width: 100%"
<a-select v-model="dnsModal.dnsServer.queryStrategy" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']"> [[ l ]] </a-select-option>
</a-select>

View file

@ -107,7 +107,7 @@
<a-tag v-else color="orange">{{ i18n "none" }}</a-tag>
</template>
</template>
<table v-if="dbInbound.isSS" style="margin-bottom: 10px; width: 100%;">
<table v-if="dbInbound.isSS" :style="{ marginBottom: '10px', width: '100%' }">
<tr>
<td>{{ i18n "encryption" }}</td>
<td>
@ -131,7 +131,7 @@
</table>
<template v-if="infoModal.clientSettings">
<a-divider>{{ i18n "pages.inbounds.client" }}</a-divider>
<table style="margin-bottom: 10px;">
<table :style="{ marginBottom: '10px' }">
<tr>
<td>{{ i18n "pages.inbounds.email" }}</td>
<td v-if="infoModal.clientSettings.email">
@ -203,7 +203,7 @@
<td>{{ i18n "pages.inbounds.IPLimitlog" }}</td>
<td>
<a-tag>[[ infoModal.clientIps ]]</a-tag>
<a-icon type="sync" :spin="refreshing" @click="refreshIPs" style="margin: 0 5px;"></a-icon>
<a-icon type="sync" :spin="refreshing" @click="refreshIPs" :style="{ margin: '0 5px' }"></a-icon>
<a-tooltip :title="[[ dbInbound.address ]]">
<template slot="title">
<span>{{ i18n "pages.inbounds.IPLimitlogclear" }}</span>
@ -213,7 +213,7 @@
</td>
</tr>
</table>
<table style="display: inline-table; margin-block: 10px; width: 100%; text-align: center;">
<table :style="{ display: 'inline-table', marginBlock: '10px', width: '100%', textAlign: 'center' }">
<tr>
<th>{{ i18n "remained" }}</th>
<th>{{ i18n "pages.inbounds.totalFlow" }}</th>
@ -290,7 +290,7 @@
<tr-info-title class="tr-info-title">
<a-tag class="tr-info-tag" color="green">[[ link.remark ]]</a-tag>
<a-tooltip title='{{ i18n "copy" }}'>
<a-button style="min-width: 24px;" size="small" icon="snippets" @click="copy(link.link)"></a-button>
<a-button :style="{ minWidth: '24px' }" size="small" icon="snippets" @click="copy(link.link)"></a-button>
</a-tooltip>
</tr-info-title>
<code>[[ link.link ]]</code>
@ -304,7 +304,7 @@
<tr-info-title class="tr-info-title">
<a-tag class="tr-info-tag" color="green">[[ link.remark ]]</a-tag>
<a-tooltip title='{{ i18n "copy" }}'>
<a-button style="min-width: 24px;" size="small" icon="snippets" @click="copy(link.link)"></a-button>
<a-button :style="{ minWidth: '24px' }" size="small" icon="snippets" @click="copy(link.link)"></a-button>
</a-tooltip>
</tr-info-title>
<code>[[ link.link ]]</code>
@ -431,10 +431,10 @@
<tr-info-title class="tr-info-title">
<a-tag color="blue">Config</a-tag>
<a-tooltip title='{{ i18n "copy" }}'>
<a-button style="min-width: 24px;" size="small" icon="snippets" @click="copy(infoModal.links[index])"></a-button>
<a-button :style="{ minWidth: '24px' }" size="small" icon="snippets" @click="copy(infoModal.links[index])"></a-button>
</a-tooltip>
</tr-info-title>
<div v-html="infoModal.links[index].replaceAll(`\n`,`<br />`)" style="border-radius: 1rem; padding: 0.5rem;" class="client-table-odd-row">
<div v-html="infoModal.links[index].replaceAll(`\n`,`<br />`)" :style="{ borderRadius: '1rem', padding: '0.5rem' }" class="client-table-odd-row">
</div>
</tr-info-row>
</td>

View file

@ -1,6 +1,6 @@
{{define "modals/qrcodeModal"}}
<a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title"
:dialog-style="DeviceUtils.isMobile() ? { top: '18px' } : {}"
:dialog-style="isMobile ? { top: '18px' } : {}"
:closable="true"
:class="themeSwitcher.currentTheme"
:footer="null" width="fit-content">
@ -73,6 +73,7 @@
const qrModalApp = new Vue({
delimiters: ['[[', ']]'],
el: '#qrcode-modal',
mixins: [MediaQueryMixin],
data: {
qrModal: qrModal,
},

View file

@ -1,20 +1,20 @@
{{define "modals/textModal"}}
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title"
:closable="true"
:class="themeSwitcher.currentTheme">
<a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title" :closable="true"
:class="themeSwitcher.currentTheme">
<a-input :style="{ overflowY: 'auto' }" type="textarea" v-model="txtModal.content"
:autosize="{ minRows: 10, maxRows: 20}"></a-input>
<template slot="footer">
<a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" icon="download"
:href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)"
:download="txtModal.fileName">[[ txtModal.fileName ]]
@click="txtModal.download(txtModal.content, txtModal.fileName)">
<span>[[ txtModal.fileName ]]</span>
</a-button>
<a-button type="primary" icon="copy" @click="txtModal.copy(txtModal.content)">
<span>{{ i18n "copy" }}</span>
</a-button>
<a-button type="primary" @click="txtModal.copy(txtModal.content)">{{ i18n "copy" }}</a-button>
</template>
<a-input style="overflow-y: auto;" type="textarea" v-model="txtModal.content"
:autosize="{ minRows: 10, maxRows: 20}"></a-input>
</a-modal>
<script>
const txtModal = {
title: '',
content: '',
@ -35,6 +35,17 @@
this.close();
})
},
download: function (content = '', fileName = '') {
let link = document.createElement('a');
link.download = fileName;
link.href = URL.createObjectURL(new Blob([content], { type: 'text/plain' }));
link.click();
URL.revokeObjectURL(link.href);
link.remove();
},
close: function () {
this.visible = false;
},
@ -47,6 +58,5 @@
txtModal: txtModal,
},
});
</script>
{{end}}
{{end}}

View file

@ -6,7 +6,7 @@
<a-button icon="api" @click="register" :loading="warpModal.confirmLoading">{{ i18n "pages.inbounds.create" }}</a-button>
</template>
<template v-else>
<table style="margin: 5px 0; width: 100%;">
<table :style="{ margin: '5px 0', width: '100%' }">
<tr class="client-table-odd-row">
<td>Access Token</td>
<td>[[ warpModal.warpData.access_token ]]</td>
@ -25,8 +25,8 @@
</tr>
</table>
<a-button @click="delConfig" :loading="warpModal.confirmLoading" type="danger">{{ i18n "delete" }}</a-button>
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.settings" }}</a-divider>
<a-collapse style="margin: 10px 0;">
<a-divider :style="{ margin: '0' }">{{ i18n "pages.xray.outbound.settings" }}</a-divider>
<a-collapse :style="{ margin: '10px 0' }">
<a-collapse-panel header='WARP/WARP+ License Key'>
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
<a-form-item label="Key">
@ -37,11 +37,11 @@
</a-form>
</a-collapse-panel>
</a-collapse>
<a-divider style="margin: 0;">{{ i18n "pages.xray.outbound.accountInfo" }}</a-divider>
<a-button icon="sync" @click="getConfig" style="margin-top: 5px; margin-bottom: 10px;"
<a-divider :style="{ margin: '0' }">{{ i18n "pages.xray.outbound.accountInfo" }}</a-divider>
<a-button icon="sync" @click="getConfig" :style="{ marginTop: '5px', marginBottom: '10px' }"
:loading="warpModal.confirmLoading" type="primary">{{ i18n "info" }}</a-button>
<template v-if="!ObjectUtil.isEmpty(warpModal.warpConfig)">
<table style="width: 100%">
<table :style="{ width: '100%' }">
<tr class="client-table-odd-row">
<td>Device Name</td>
<td>[[ warpModal.warpConfig.name ]]</td>
@ -77,14 +77,14 @@
</tr>
</template>
</table>
<a-divider style="margin: 10px 0;">{{ i18n "pages.xray.outbound.outboundStatus" }}</a-divider>
<a-divider :style="{ margin: '10px 0' }">{{ i18n "pages.xray.outbound.outboundStatus" }}</a-divider>
<a-form :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
<template v-if="warpOutboundIndex>=0">
<a-tag color="green" style="line-height: 31px;">{{ i18n "enabled" }}</a-tag>
<a-tag color="green" :style="{ lineHeight: '31px' }">{{ i18n "enabled" }}</a-tag>
<a-button @click="resetOutbound" :loading="warpModal.confirmLoading" type="danger">{{ i18n "reset" }}</a-button>
</template>
<template v-else>
<a-tag color="orange" style="line-height: 31px;">{{ i18n "disabled" }}</a-tag>
<a-tag color="orange" :style="{ lineHeight: '31px' }">{{ i18n "disabled" }}</a-tag>
<a-button @click="addOutbound" :loading="warpModal.confirmLoading" type="primary">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
</template>
</a-form-item>

View file

@ -1,7 +1,7 @@
{{define "modals/outModal"}}
<a-modal id="out-modal" v-model="outModal.visible" :title="outModal.title" @ok="outModal.ok"
:confirm-loading="outModal.confirmLoading" :closable="true" :mask-closable="false"
:ok-button-props="{ props: { disabled: !outModal.isValid } }" style="overflow: hidden;"
:ok-button-props="{ props: { disabled: !outModal.isValid } }" :style="{ overflow: 'hidden' }"
:ok-text="outModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
{{template "form/outbound"}}
</a-modal>

View file

@ -37,14 +37,14 @@
</a-select>
</a-form-item>
<a-form-item label='Attributes'>
<a-button icon="plus" size="small" style="margin-left: 10px" @click="ruleModal.rule.attrs.push(['', ''])"></a-button>
<a-button icon="plus" size="small" :style="{ marginLeft: '10px' }" @click="ruleModal.rule.attrs.push(['', ''])"></a-button>
</a-form-item>
<a-form-item :wrapper-col="{span: 24}">
<a-input-group compact v-for="(attr,index) in ruleModal.rule.attrs">
<a-input style="width: 50%" v-model="attr[0]" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" style="margin: 0;">[[ index+1 ]]</template>
<a-input :style="{ width: '50%' }" v-model="attr[0]" placeholder='{{ i18n "pages.inbounds.stream.general.name" }}'>
<template slot="addonBefore" :style="{ margin: '0' }">[[ index+1 ]]</template>
</a-input>
<a-input style="width: 50%" v-model="attr[1]" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-input :style="{ width: '50%' }" v-model="attr[1]" placeholder='{{ i18n "pages.inbounds.stream.general.value" }}'>
<a-button icon="minus" slot="addonAfter" size="small" @click="ruleModal.rule.attrs.splice(index,1)"></a-button>
</a-input>
</a-input-group>

View file

@ -53,6 +53,9 @@
color: inherit;
font-size: 24px;
}
.dark .ant-input-password-icon {
color: var(--dark-color-text-primary);
}
</style>
<body>
<a-layout id="app" v-cloak :class="themeSwitcher.currentTheme">
@ -61,7 +64,7 @@
<a-layout-content>
<a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'>
<transition name="list" appear>
<a-alert type="error" v-if="confAlerts.length>0" style="margin-bottom: 10px;"
<a-alert type="error" v-if="confAlerts.length>0" :style="{ marginBottom: '10px' }"
message='{{ i18n "secAlertTitle" }}'
color="red"
show-icon closable>
@ -72,9 +75,9 @@
</a-alert>
</transition>
<a-space direction="vertical">
<a-card hoverable style="margin-bottom: .5rem; overflow-x: hidden;">
<a-row style="display: flex; flex-wrap: wrap; align-items: center;">
<a-col :xs="24" :sm="10" style="padding: 4px;">
<a-card hoverable :style="{ marginBottom: '.5rem', overflowX: 'hidden' }">
<a-row :style="{ display: 'flex', flexWrap: 'wrap', alignItems: 'center' }">
<a-col :xs="24" :sm="10" :style="{ padding: '4px' }">
<a-space direction="horizontal">
<a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.settings.save" }}</a-button>
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button>
@ -84,7 +87,7 @@
<template>
<div>
<a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200"></a-back-top>
<a-alert type="warning" style="float: right; width: fit-content"
<a-alert type="warning" :style="{ float: 'right', width: 'fit-content' }"
message='{{ i18n "pages.settings.infoDesc" }}'
show-icon>
</a-alert>
@ -94,19 +97,19 @@
</a-row>
</a-card>
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings" }}' style="padding-top: 20px;">
<a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings" }}' :style="{ paddingTop: '20px' }">
{{ template "settings/panel/general" . }}
</a-tab-pane>
<a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings" }}' style="padding-top: 20px;">
<a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings" }}' :style="{ paddingTop: '20px' }">
{{ template "settings/panel/security" . }}
</a-tab-pane>
<a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings" }}' style="padding-top: 20px;">
<a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings" }}' :style="{ paddingTop: '20px' }">
{{ template "settings/panel/telegram" . }}
</a-tab-pane>
<a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}' style="padding-top: 20px;">
<a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}' :style="{ paddingTop: '20px' }">
{{ template "settings/panel/subscription/general" . }}
</a-tab-pane>
<a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable" style="padding-top: 20px;">
<a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable" :style="{ paddingTop: '20px' }">
{{ template "settings/panel/subscription/json" . }}
</a-tab-pane>
</a-tabs>
@ -119,7 +122,6 @@
<script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script>
{{template "component/aSidebar" .}}
{{template "component/aThemeSwitch" .}}
{{template "component/aPasswordInput" .}}
{{template "component/aSettingListItem" .}}
<script>
const app = new Vue({

View file

@ -9,12 +9,12 @@
{{ i18n "pages.settings.sampleRemark"}}: <i>#[[ remarkSample ]]</i>
</template>
<template #control>
<a-input-group style="width: 100%;">
<a-select style="padding-right: .5rem; min-width: 80%; width: auto;" mode="multiple"
<a-input-group :style="{ width: '100%' }">
<a-select :style="{ paddingRight: '.5rem', minWidth: '80%', width: 'auto' }" mode="multiple"
v-model="remarkModel" :dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="(value, key) in remarkModels" :value="key">[[ value ]]</a-select-option>
</a-select>
<a-select style="width: 20%;" v-model="remarkSeparator"
<a-select :style="{ width: '20%' }" v-model="remarkSeparator"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option v-for="key in remarkSeparators" :value="key">[[ key ]]</a-select-option>
</a-select>
@ -39,7 +39,7 @@
<template #title>{{ i18n "pages.settings.panelPort"}}</template>
<template #description>{{ i18n "pages.settings.panelPortDesc"}}</template>
<template #control>
<a-input-number :min="1" :min="65531" v-model="allSetting.webPort" style="width: 100%;"></a-input>
<a-input-number :min="1" :min="65531" v-model="allSetting.webPort" :style="{ width: '100%' }"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
@ -53,21 +53,21 @@
<template #title>{{ i18n "pages.settings.sessionMaxAge" }}</template>
<template #description>{{ i18n "pages.settings.sessionMaxAgeDesc" }}</template>
<template #control>
<a-input-number :min="60" v-model="allSetting.sessionMaxAge" style="width: 100%;"></a-input>
<a-input-number :min="60" v-model="allSetting.sessionMaxAge" :style="{ width: '100%' }"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.pageSize" }}</template>
<template #description>{{ i18n "pages.settings.pageSizeDesc" }}</template>
<template #control>
<a-input-number :min="0" step="5" v-model="allSetting.pageSize" style="width: 100%;"></a-input>
<a-input-number :min="0" step="5" v-model="allSetting.pageSize" :style="{ width: '100%' }"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.language"}}</template>
<template #control>
<a-select ref="selectLang" v-model="lang" @change="LanguageManager.setLanguage(lang)"
:dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
:dropdown-class-name="themeSwitcher.currentTheme" :style="{ width: '100%' }">
<a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages">
<span role="img" :aria-label="l.name" v-text="l.icon"></span> &nbsp;&nbsp; <span
v-text="l.name"></span>
@ -81,14 +81,14 @@
<template #title>{{ i18n "pages.settings.expireTimeDiff" }}</template>
<template #description>{{ i18n "pages.settings.expireTimeDiffDesc" }}</template>
<template #control>
<a-input-number :min="0" v-model="allSetting.expireDiff" style="width: 100%;"></a-input>
<a-input-number :min="0" v-model="allSetting.expireDiff" :style="{ width: '100%' }"></a-input>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.trafficDiff" }}</template>
<template #description>{{ i18n "pages.settings.trafficDiffDesc" }}</template>
<template #control>
<a-input-number :min="0" v-model="allSetting.trafficDiff" style="width: 100%;"></a-input>
<a-input-number :min="0" v-model="allSetting.trafficDiff" :style="{ width: '100%' }"></a-input>
</template>
</a-setting-list-item>
</a-collapse-panel>
@ -137,7 +137,7 @@
<template #title>{{ i18n "pages.settings.datepicker"}}</template>
<template #description>{{ i18n "pages.settings.datepickerDescription"}}</template>
<template #control>
<a-select style="width: 100%" :dropdown-class-name="themeSwitcher.currentTheme" v-model="datepicker">
<a-select :style="{ width: '100%' }" :dropdown-class-name="themeSwitcher.currentTheme" v-model="datepicker">
<a-select-option v-for="item in datepickerList" :value="item.value">
<span v-text="item.name"></span>
</a-select-option>

View file

@ -10,7 +10,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.currentPassword"}}</template>
<template #control>
<a-password-input autocomplete="current-password" v-model="user.oldPassword"></a-password-input>
<a-input-password autocomplete="current-password" v-model="user.oldPassword"></a-input-password>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
@ -22,11 +22,11 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.newPassword"}}</template>
<template #control>
<a-password-input autocomplete="new-password" v-model="user.newPassword"></a-password-input>
<a-input-password autocomplete="new-password" v-model="user.newPassword"></a-input-password>
</template>
</a-setting-list-item>
<a-list-item>
<a-space direction="horizontal" style="padding: 0 20px;">
<a-space direction="horizontal" :style="{ padding: '0 20px' }">
<a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button>
</a-space>
</a-list-item>
@ -37,7 +37,7 @@
<template #description>{{ i18n "pages.settings.security.loginSecurityDesc" }}</template>
<template #control>
<a-switch @change="toggleToken(allSetting.secretEnable)" v-model="allSetting.secretEnable"></a-switch>
<a-icon style="margin-left: 1rem;" v-if="allSetting.secretEnable" :spin="this.changeSecret" type="sync"
<a-icon :style="{ marginLeft: '1rem' }" v-if="allSetting.secretEnable" :spin="this.changeSecret" type="sync"
@click="getNewSecret"></a-icon>
</template>
</a-setting-list-item>
@ -49,7 +49,7 @@
</template>
</a-setting-list-item>
<a-list-item>
<a-space direction="horizontal" style="padding: 0 20px;">
<a-space direction="horizontal" :style="{ padding: '0 20px' }">
<a-button type="primary" :loading="this.changeSecret" @click="updateSecret">
<span>{{ i18n "confirm"}}</span>
</a-button>

View file

@ -34,7 +34,7 @@
<template #description>{{ i18n "pages.settings.subPortDesc"}}</template>
<template #control>
<a-input-number v-model="allSetting.subPort" :min="1" :min="65531"
style="width: 100%;"></a-input-number>
:style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
@ -90,7 +90,7 @@
<template #title>{{ i18n "pages.settings.subUpdates"}}</template>
<template #description>{{ i18n "pages.settings.subUpdatesDesc"}}</template>
<template #control>
<a-input-number :min="1" v-model="allSetting.subUpdates" style="width: 100%;"></a-input-number>
<a-input-number :min="1" v-model="allSetting.subUpdates" :style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
</a-collapse-panel>

View file

@ -25,7 +25,7 @@
<a-switch v-model="fragment"></a-switch>
</template>
</a-setting-list-item>
<a-list-item v-if="fragment" style="padding: 10px 20px;">
<a-list-item v-if="fragment" :style="{ padding: '10px 20px' }">
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.settings.fragmentSett"}}' v-if="fragment">
<a-setting-list-item paddings="small">
@ -59,13 +59,13 @@
<a-switch v-model="noises"></a-switch>
</template>
</a-setting-list-item>
<a-list-item v-if="noises" style="padding: 10px 20px;">
<a-list-item v-if="noises" :style="{ padding: '10px 20px' }">
<a-collapse>
<a-collapse-panel v-for="(noise, index) in noisesArray" :key="index" :header="`Noise №${index + 1}`">
<a-setting-list-item paddings="small">
<template #title>Type</template>
<template #control>
<a-select :value="noise.type" style="width: 100%"
<a-select :value="noise.type" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme"
@change="(value) => updateNoiseType(index, value)">
<a-select-option :value="p" :label="p" v-for="p in ['rand', 'base64', 'str', 'hex']" :key="p">
@ -90,13 +90,13 @@
placeholder="10-20"></a-input>
</template>
</a-setting-list-item>
<a-space direction="horizontal" style="padding: 10px 20px;">
<a-space direction="horizontal" :style="{ padding: '10px 20px' }">
<a-button v-if="noisesArray.length > 1" type="danger"
@click="removeNoise(index)">Remove</a-button>
</a-space>
</a-collapse-panel>
</a-collapse>
<a-button v-if="noises" type="primary" @click="addNoise" style="margin-top: 10px">Add Noise</a-button>
<a-button v-if="noises" type="primary" @click="addNoise" :style="{ marginTop: '10px' }">Add Noise</a-button>
</a-list-item>
</a-collapse-panel>
<a-collapse-panel key="4" header='{{ i18n "pages.settings.mux"}}'>
@ -107,27 +107,27 @@
<a-switch v-model="enableMux"></a-switch>
</template>
</a-setting-list-item>
<a-list-item v-if="enableMux" style="padding: 10px 20px;">
<a-list-item v-if="enableMux" :style="{ padding: '10px 20px' }">
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.settings.muxSett"}}'>
<a-setting-list-item paddings="small">
<template #title>Concurrency</template>
<template #control>
<a-input-number v-model="muxConcurrency" :min="-1" :max="1024"
style="width: 100%;"></a-input-number>
:style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>xudp Concurrency</template>
<template #control>
<a-input-number v-model="muxXudpConcurrency" :min="-1" :max="1024"
style="width: 100%;"></a-input-number>
:style="{ width: '100%' }"></a-input-number>
</template>
</a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>xudp UDP 443</template>
<template #control>
<a-select v-model="muxXudpProxyUDP443" style="width: 100%"
<a-select v-model="muxXudpProxyUDP443" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p" :label="p" v-for="p in ['reject', 'allow', 'skip']">
<span>[[ p ]]</span>
@ -147,13 +147,13 @@
<a-switch v-model="enableDirect"></a-switch>
</template>
</a-setting-list-item>
<a-list-item v-if="enableDirect" style="padding: 10px 20px;">
<a-list-item v-if="enableDirect" :style="{ padding: '10px 20px' }">
<a-collapse>
<a-collapse-panel header='{{ i18n "pages.settings.direct"}}'>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.directips" }}</template>
<template #control>
<a-select mode="tags" style="width: 100%" v-model="directIPs"
<a-select mode="tags" :style="{ width: '100%' }" v-model="directIPs"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in directIPsOptions">
<span>[[ p.label ]]</span>
@ -164,7 +164,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.directdomains" }}</template>
<template #control>
<a-select mode="tags" style="width: 100%" v-model="directDomains"
<a-select mode="tags" :style="{ width: '100%' }" v-model="directDomains"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in diretDomainsOptions">
<span>[[ p.label ]]</span>

View file

@ -26,7 +26,7 @@
<template #title>{{ i18n "pages.settings.telegramBotLanguage"}}</template>
<template #control>
<a-select ref="selectBotLang" v-model="allSetting.tgLang"
:dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
:dropdown-class-name="themeSwitcher.currentTheme" :style="{ width: '100%' }">
<a-select-option :value="l.value" :label="l.value" v-for="l in LanguageManager.supportedLanguages">
<span role="img" :aria-label="l.name" v-text="l.icon"></span> &nbsp;&nbsp; <span
v-text="l.name"></span>
@ -61,7 +61,7 @@
<template #title>{{ i18n "pages.settings.tgNotifyCpu" }}</template>
<template #description>{{ i18n "pages.settings.tgNotifyCpuDesc" }}</template>
<template #control>
<a-input-number :min="0" :min="100" v-model="allSetting.tgCpu" style="width: 100%;"></a-switch>
<a-input-number :min="0" :min="100" v-model="allSetting.tgCpu" :style="{ width: '100%' }"></a-switch>
</template>
</a-setting-list-item>
</a-collapse-panel>

View file

@ -2,13 +2,13 @@
<a-space direction="vertical" size="small">
<a-list-item-meta title='{{ i18n "pages.xray.Template"}}'
description='{{ i18n "pages.xray.TemplateDesc"}}'></a-list-item-meta>
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" style="margin: 10px 0;"
<a-radio-group v-model="advSettings" @change="changeCode" button-style="solid" :style="{ margin: '10px 0' }"
:size="isMobile ? 'small' : ''">
<a-radio-button value="xraySetting">{{ i18n "pages.xray.completeTemplate"}}</a-radio-button>
<a-radio-button value="inboundSettings">{{ i18n "pages.xray.Inbounds" }}</a-radio-button>
<a-radio-button value="outboundSettings">{{ i18n "pages.xray.Outbounds" }}</a-radio-button>
<a-radio-button value="routingRuleSettings">{{ i18n "pages.xray.Routings" }}</a-radio-button>
</a-radio-group>
<textarea style="position:absolute; left: -800px;" id="xraySetting"></textarea>
<textarea :style="{ position: 'absolute', left: '-800px' }" id="xraySetting"></textarea>
</a-space>
{{end}}

View file

@ -10,14 +10,14 @@
<span>[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: 'bold' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editBalancer(index)">
<a-icon type="edit"></a-icon>
<span>{{ i18n "edit" }}</span>
</a-menu-item>
<a-menu-item @click="deleteBalancer(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
@ -26,13 +26,13 @@
</a-dropdown>
</template>
<template slot="strategy" slot-scope="text, balancer, index">
<a-tag style="margin:0;" v-if="balancer.strategy=='random'" color="purple">Random</a-tag>
<a-tag style="margin:0;" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag>
<a-tag style="margin:0;" v-if="balancer.strategy=='leastLoad'" color="green">Least Load</a-tag>
<a-tag style="margin:0;" v-if="balancer.strategy=='leastPing'" color="green">Least Ping</a-tag>
<a-tag :style="{ margin: '0' }" v-if="balancer.strategy=='random'" color="purple">Random</a-tag>
<a-tag :style="{ margin: '0' }" v-if="balancer.strategy=='roundRobin'" color="green">Round Robin</a-tag>
<a-tag :style="{ margin: '0' }" v-if="balancer.strategy=='leastLoad'" color="green">Least Load</a-tag>
<a-tag :style="{ margin: '0' }" v-if="balancer.strategy=='leastPing'" color="green">Least Ping</a-tag>
</template>
<template slot="selector" slot-scope="text, balancer, index">
<a-tag class="info-large-tag" style="margin:1;" v-for="sel in balancer.selector">[[ sel ]]</a-tag>
<a-tag class="info-large-tag" :style="{ margin: '1' }" v-for="sel in balancer.selector">[[ sel ]]</a-tag>
</template>
</a-table>
<a-radio-group v-if="observatoryEnable || burstObservatoryEnable" v-model="obsSettings" @change="changeObsCode"
@ -40,12 +40,12 @@
<a-radio-button value="observatory" v-if="observatoryEnable">Observatory</a-radio-button>
<a-radio-button value="burstObservatory" v-if="burstObservatoryEnable">Burst Observatory</a-radio-button>
</a-radio-group>
<textarea style="position:absolute; left: -800px;" id="obsSetting"></textarea>
<textarea :style="{ position: 'absolute', left: '-800px' }" id="obsSetting"></textarea>
</a-space>
</template>
<template v-else>
<a-empty description='{{ i18n "emptyBalancersDesc" }}' style="margin: 10px;">
<a-button type="primary" icon="plus" @click="addBalancer()" style="margin-top: 10px;">
<a-empty description='{{ i18n "emptyBalancersDesc" }}' :style="{ margin: '10px' }">
<a-button type="primary" icon="plus" @click="addBalancer()" :style="{ marginTop: '10px' }">
<span>{{ i18n "pages.xray.balancer.addBalancer"}}</span>
</a-button>
</a-empty>

View file

@ -2,9 +2,9 @@
<a-collapse default-active-key="1">
<a-collapse-panel key="1" header='{{ i18n "pages.xray.generalConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center;">
<a-alert type="warning" :style="{ textAlign: 'center' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.generalConfigsDesc" }}</span>
</template>
</a-alert>
@ -14,7 +14,7 @@
<template #description>{{ i18n "pages.xray.FreedomStrategyDesc" }}</template>
<template #control>
<a-select v-model="freedomStrategy" :dropdown-class-name="themeSwitcher.currentTheme"
style="width: 100%">
:style="{ width: '100%' }">
<a-select-option v-for="s in OutboundDomainStrategies" :value="s">
<span>[[ s ]]</span>
</a-select-option>
@ -26,7 +26,7 @@
<template #description>{{ i18n "pages.xray.RoutingStrategyDesc" }}</template>
<template #control>
<a-select v-model="routingStrategy" :dropdown-class-name="themeSwitcher.currentTheme"
style="width: 100%">
:style="{ width: '100%' }">
<a-select-option v-for="s in routingDomainStrategies" :value="s">
<span>[[ s ]]</span>
</a-select-option>
@ -66,9 +66,9 @@
</a-collapse-panel>
<a-collapse-panel key="3" header='{{ i18n "pages.xray.logConfigs" }}'>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center;">
<a-alert type="warning" :style="{ textAlign: 'center' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.logConfigsDesc" }}</span>
</template>
</a-alert>
@ -77,7 +77,7 @@
<template #title>{{ i18n "pages.xray.logLevel" }}</template>
<template #description>{{ i18n "pages.xray.logLevelDesc" }}</template>
<template #control>
<a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
<a-select v-model="logLevel" :dropdown-class-name="themeSwitcher.currentTheme" :style="{ width: '100%' }">
<a-select-option v-for="s in log.loglevel" :value="s">
<span>[[ s ]]</span>
</a-select-option>
@ -88,7 +88,7 @@
<template #title>{{ i18n "pages.xray.accessLog" }}</template>
<template #description>{{ i18n "pages.xray.accessLogDesc" }}</template>
<template #control>
<a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
<a-select v-model="accessLog" :dropdown-class-name="themeSwitcher.currentTheme" :style="{ width: '100%' }">
<a-select-option value=''>
<span>Empty</span>
</a-select-option>
@ -102,7 +102,7 @@
<template #title>{{ i18n "pages.xray.errorLog" }}</template>
<template #description>{{ i18n "pages.xray.errorLogDesc" }}</template>
<template #control>
<a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" style="width: 100%">
<a-select v-model="errorLog" :dropdown-class-name="themeSwitcher.currentTheme" :style="{ width: '100%' }">
<a-select-option value=''>
<span>Empty</span>
</a-select-option>
@ -117,7 +117,7 @@
<template #description>{{ i18n "pages.xray.maskAddressDesc" }}</template>
<template #control>
<a-select v-model="maskAddressLog" :dropdown-class-name="themeSwitcher.currentTheme"
style="width: 100%">
:style="{ width: '100%' }">
<a-select-option value=''>
<span>Empty</span>
</a-select-option>
@ -137,9 +137,9 @@
</a-collapse-panel>
<a-collapse-panel key="4" header='{{ i18n "pages.xray.blockConfigs"}}'>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center;">
<a-alert type="warning" :style="{ textAlign: 'center' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.blockConfigsDesc" }}</span>
</template>
</a-alert>
@ -161,9 +161,9 @@
</a-collapse-panel>
<a-collapse-panel key="5" header='{{ i18n "pages.xray.basicRouting"}}'>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center;">
<a-alert type="warning" :style="{ textAlign: 'center' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.blockConnectionsConfigsDesc" }}</span>
</template>
</a-alert>
@ -171,7 +171,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.blockips" }}</template>
<template #control>
<a-select mode="tags" v-model="blockedIPs" style="width: 100%"
<a-select mode="tags" v-model="blockedIPs" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions">
<span>[[ p.label ]]</span>
@ -182,7 +182,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.blockdomains" }}</template>
<template #control>
<a-select mode="tags" v-model="blockedDomains" style="width: 100%"
<a-select mode="tags" v-model="blockedDomains" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.BlockDomainsOptions">
<span>[[ p.label ]]</span>
@ -191,9 +191,9 @@
</template>
</a-setting-list-item>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
<a-alert type="warning" :style="{ textAlign: 'center', marginTop: '20px' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.directConnectionsConfigsDesc" }}</span>
</template>
</a-alert>
@ -201,7 +201,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.directips" }}</template>
<template #control>
<a-select mode="tags" style="width: 100%" v-model="directIPs"
<a-select mode="tags" :style="{ width: '100%' }" v-model="directIPs"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.IPsOptions">
<span>[[ p.label ]]</span>
@ -212,7 +212,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.directdomains" }}</template>
<template #control>
<a-select mode="tags" style="width: 100%" v-model="directDomains"
<a-select mode="tags" :style="{ width: '100%' }" v-model="directDomains"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.DomainsOptions">
<span>[[ p.label ]]</span>
@ -221,9 +221,9 @@
</template>
</a-setting-list-item>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
<a-alert type="warning" :style="{ textAlign: 'center', marginTop: '20px' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
<span>{{ i18n "pages.xray.ipv4RoutingDesc" }}</span>
</template>
</a-alert>
@ -231,7 +231,7 @@
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.xray.ipv4Routing" }}</template>
<template #control>
<a-select mode="tags" style="width: 100%" v-model="ipv4Domains"
<a-select mode="tags" :style="{ width: '100%' }" v-model="ipv4Domains"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions">
<span>[[ p.label ]]</span>
@ -240,9 +240,9 @@
</template>
</a-setting-list-item>
<a-row :xs="24" :sm="24" :lg="12">
<a-alert type="warning" style="text-align: center; margin-top: 20px;">
<a-alert type="warning" :style="{ textAlign: 'center', marginTop: '20px' }">
<template slot="message">
<a-icon type="exclamation-circle" theme="filled" style="color: #FFA031"></a-icon>
<a-icon type="exclamation-circle" theme="filled" :style="{ color: '#FFA031' }"></a-icon>
{{ i18n "pages.xray.warpRoutingDesc" }}
</template>
</a-alert>
@ -251,7 +251,7 @@
<template #title>{{ i18n "pages.xray.warpRouting" }}</template>
<template #control>
<template v-if="WarpExist">
<a-select mode="tags" style="width: 100%" v-model="warpDomains"
<a-select mode="tags" :style="{ width: '100%' }" v-model="warpDomains"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="p.value" :label="p.label" v-for="p in settingsData.ServicesOptions">
<span>[[ p.label ]]</span>
@ -265,7 +265,7 @@
</a-setting-list-item>
</a-collapse-panel>
<a-collapse-panel key="6" header='{{ i18n "pages.settings.resetDefaultConfig"}}'>
<a-space direction="horizontal" style="padding: 0 20px">
<a-space direction="horizontal" :style="{ padding: '0 20px' }">
<a-button type="danger" @click="resetXrayConfigToDefault">
<span>{{ i18n "pages.settings.resetDefaultConfig" }}</span>
</a-button>

View file

@ -27,7 +27,7 @@
<template #title>{{ i18n "pages.xray.dns.strategy" }}</template>
<template #description>{{ i18n "pages.xray.dns.strategyDesc" }}</template>
<template #control>
<a-select v-model="dnsStrategy" style="width: 100%"
<a-select v-model="dnsStrategy" :style="{ width: '100%' }"
:dropdown-class-name="themeSwitcher.currentTheme">
<a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']">
<span>[[ l ]]</span>
@ -71,14 +71,14 @@
<span>[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: 'bold' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editDNSServer(index)">
<a-icon type="edit"></a-icon>
<span>{{ i18n "edit" }}</span>
</a-menu-item>
<a-menu-item @click="deleteDNSServer(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
@ -100,8 +100,8 @@
</a-space>
</template>
<template v-else>
<a-empty description='{{ i18n "emptyDnsDesc" }}' style="margin: 10px;">
<a-button type="primary" icon="plus" @click="addDNSServer()" style="margin-top: 10px;">
<a-empty description='{{ i18n "emptyDnsDesc" }}' :style="{ margin: '10px' }">
<a-button type="primary" icon="plus" @click="addDNSServer()" :style="{ marginTop: '10px' }">
<span>{{ i18n "pages.xray.dns.add" }}</span>
</a-button>
</a-empty>
@ -118,14 +118,14 @@
<span>[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: 'bold' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editFakedns(index)">
<a-icon type="edit"></a-icon>
<span>{{ i18n "edit" }}</span>
</a-menu-item>
<a-menu-item @click="deleteFakedns(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
@ -137,8 +137,8 @@
</a-space>
</template>
<template v-else>
<a-empty description='{{ i18n "emptyFakeDnsDesc" }}' style="margin: 20px;">
<a-button type="primary" icon="plus" @click="addFakedns()" style="margin-top: 10px;">
<a-empty description='{{ i18n "emptyFakeDnsDesc" }}' :style="{ margin: '20px' }">
<a-button type="primary" icon="plus" @click="addFakedns()" :style="{ marginTop: '10px' }">
<span>{{ i18n "pages.xray.fakedns.add" }}</span>
</a-button>
</a-empty>

View file

@ -9,15 +9,17 @@
<a-button type="primary" icon="cloud" @click="showWarp()">WARP</a-button>
</a-space>
</a-col>
<a-col :xs="12" :sm="12" :lg="12" style="text-align: right;">
<a-icon type="sync" :spin="refreshing" @click="refreshOutboundTraffic()" style="margin: 0 5px;"></a-icon>
<a-popconfirm placement="topRight" @confirm="resetOutboundTraffic(-1)"
title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme"
ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'>
<a-icon slot="icon" type="question-circle-o"
:style="themeSwitcher.isDarkTheme ? 'color: #008771' : 'color: #008771'"></a-icon>
<a-icon type="retweet" style="cursor: pointer;"></a-icon>
</a-popconfirm>
<a-col :xs="12" :sm="12" :lg="12" :style="{ textAlign: 'right' }">
<a-button-group>
<a-button icon="sync" @click="refreshOutboundTraffic()" :loading="refreshing"></a-button>
<a-popconfirm placement="topRight" @confirm="resetOutboundTraffic(-1)"
title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme"
ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'>
<a-icon slot="icon" type="question-circle-o"
:style="{ color: themeSwitcher.isDarkTheme ? '#008771' : '#008771' }"></a-icon>
<a-button icon="retweet"></a-button>
</a-popconfirm>
</a-button-group>
</a-col>
</a-row>
<a-table :columns="outboundColumns" bordered :row-key="r => r.key" :data-source="outboundData"
@ -26,7 +28,7 @@
<span>[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: 'bold' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item v-if="index>0" @click="setFirstOutbound(index)">
<a-icon type="vertical-align-top"></a-icon>
@ -43,7 +45,7 @@
</span>
</a-menu-item>
<a-menu-item @click="deleteOutbound(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
@ -52,15 +54,15 @@
</a-dropdown>
</template>
<template slot="address" slot-scope="text, outbound, index">
<p style="margin: 0 5px;" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p>
<p :style="{ margin: '0 5px' }" v-for="addr in findOutboundAddress(outbound)">[[ addr ]]</p>
</template>
<template slot="protocol" slot-scope="text, outbound, index">
<a-tag style="margin:0;" color="purple">[[ outbound.protocol ]]</a-tag>
<a-tag :style="{ margin: '0' }" color="purple">[[ outbound.protocol ]]</a-tag>
<template
v-if="[Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(outbound.protocol)">
<a-tag style="margin:0;" color="blue">[[ outbound.streamSettings.network ]]</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag>
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'"
<a-tag :style="{ margin: '0' }" color="blue">[[ outbound.streamSettings.network ]]</a-tag>
<a-tag :style="{ margin: '0' }" v-if="outbound.streamSettings.security=='tls'" color="green">tls</a-tag>
<a-tag :style="{ margin: '0' }" v-if="outbound.streamSettings.security=='reality'"
color="green">reality</a-tag>
</template>
</template>

View file

@ -10,14 +10,14 @@
<span>[[ index+1 ]]</span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: 'bold' }"></a-icon>
<a-menu slot="overlay" :theme="themeSwitcher.currentTheme">
<a-menu-item @click="editReverse(index)">
<a-icon type="edit"></a-icon>
<span>{{ i18n "edit" }}</span>
</a-menu-item>
<a-menu-item @click="deleteReverse(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon>
<span>{{ i18n "delete"}}</span>
</span>
@ -29,8 +29,8 @@
</a-space>
</template>
<template v-else>
<a-empty description='{{ i18n "emptyReverseDesc" }}' style="margin: 10px;">
<a-button type="primary" icon="plus" @click="addReverse()" style="margin-top: 10px;">
<a-empty description='{{ i18n "emptyReverseDesc" }}' :style="{ margin: '10px' }">
<a-button type="primary" icon="plus" @click="addReverse()" :style="{ marginTop: '10px' }">
{{ i18n "pages.xray.outbound.addReverse" }}
</a-button>
</a-empty>

View file

@ -9,7 +9,7 @@
<span class="ant-table-row-index"> [[ index+1 ]] </span>
<a-dropdown :trigger="['click']">
<a-icon @click="e => e.preventDefault()" type="more"
style="font-size: 16px; text-decoration: bold;"></a-icon>
:style="{ fontSize: '16px', textDecoration: '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>
@ -33,7 +33,7 @@
{{ i18n "edit" }}
</a-menu-item>
<a-menu-item @click="deleteRule(index)">
<span style="color: #FF4D4F">
<span :style="{ color: '#FF4D4F' }">
<a-icon type="delete"></a-icon> {{ i18n "delete"}}
</span>
</a-menu-item>
@ -70,7 +70,7 @@
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;">
<table cellpadding="2" :style="{ maxWidth: '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>
@ -109,7 +109,7 @@
</tr>
</table>
</template>
<a-button shape="round" size="small" style="font-size: 14px; padding: 0 10px;">
<a-button shape="round" size="small" :style="{ fontSize: '14px', padding: '0 10px' }">
<a-icon type="info"></a-icon>
</a-button>
</a-popover>

View file

@ -50,7 +50,7 @@
<a-layout-content>
<a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'>
<transition name="list" appear>
<a-alert type="error" v-if="showAlert" style="margin-bottom: 10px"
<a-alert type="error" v-if="showAlert" :style="{ marginBottom: '10px' }"
message='{{ i18n "secAlertTitle" }}'
color="red"
description='{{ i18n "secAlertSsl" }}'
@ -58,17 +58,17 @@
</a-alert>
</transition>
<a-space direction="vertical">
<a-card hoverable style="margin-bottom: .5rem;">
<a-row style="display: flex; flex-wrap: wrap; align-items: center;">
<a-col :xs="24" :sm="10" style="padding: 4px;">
<a-card hoverable :style="{ marginBottom: '.5rem' }">
<a-row :style="{ display: 'flex', flexWrap: 'wrap', alignItems: 'center' }">
<a-col :xs="24" :sm="10" :style="{ padding: '4px' }">
<a-space direction="horizontal">
<a-button type="primary" :disabled="saveBtnDisable" @click="updateXraySetting">{{ i18n "pages.xray.save" }}</a-button>
<a-button type="danger" :disabled="!saveBtnDisable" @click="restartXray">{{ i18n "pages.xray.restart" }}</a-button>
<a-popover v-if="restartResult"
:overlay-class-name="themeSwitcher.currentTheme">
<span slot="title" style="font-size: 12pt">Error in running xray-core</span>
<span slot="title">{{ i18n "pages.index.xrayErrorPopoverTitle" }}</span>
<template slot="content">
<p style="max-width: 400px" v-for="line in restartResult.split('\n')">[[ line ]]</p>
<span :style="{ maxWidth: '400px' }" v-for="line in restartResult.split('\n')">[[ line ]]</span>
</template>
<a-icon type="question-circle"></a-icon>
</a-popover>
@ -78,7 +78,7 @@
<template>
<div>
<a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200"></a-back-top>
<a-alert type="warning" style="float: right; width: fit-content" message='{{ i18n "pages.settings.infoDesc" }}' show-icon>
<a-alert type="warning" :style="{ float: 'right', width: 'fit-content' }" message='{{ i18n "pages.settings.infoDesc" }}' show-icon>
</a-alert>
</div>
</template>
@ -88,25 +88,25 @@
<a-tabs class="ant-card-dark-box-nohover" default-active-key="1"
@change="(activeKey) => { this.changePage(activeKey); }"
:class="themeSwitcher.currentTheme">
<a-tab-pane key="tpl-basic" tab='{{ i18n "pages.xray.basicTemplate"}}' style="padding-top: 20px;">
<a-tab-pane key="tpl-basic" tab='{{ i18n "pages.xray.basicTemplate"}}' :style="{ paddingTop: '20px' }">
{{ template "settings/xray/basics" . }}
</a-tab-pane>
<a-tab-pane key="tpl-routing" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;">
<a-tab-pane key="tpl-routing" tab='{{ i18n "pages.xray.Routings"}}' :style="{ paddingTop: '20px' }">
{{ template "settings/xray/routing" . }}
</a-tab-pane>
<a-tab-pane key="tpl-outbound" tab='{{ i18n "pages.xray.Outbounds"}}' force-render="true">
{{ template "settings/xray/outbounds" . }}
</a-tab-pane>
<a-tab-pane key="tpl-reverse" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true">
<a-tab-pane key="tpl-reverse" tab='{{ i18n "pages.xray.outbound.reverse"}}' :style="{ paddingTop: '20px' }" force-render="true">
{{ template "settings/xray/reverse" . }}
</a-tab-pane>
<a-tab-pane key="tpl-balancer" tab='{{ i18n "pages.xray.Balancers"}}' style="padding-top: 20px;" force-render="true">
<a-tab-pane key="tpl-balancer" tab='{{ i18n "pages.xray.Balancers"}}' :style="{ paddingTop: '20px' }" force-render="true">
{{ template "settings/xray/balancers" . }}
</a-tab-pane>
<a-tab-pane key="tpl-dns" tab='DNS' style="padding-top: 20px;" force-render="true">
<a-tab-pane key="tpl-dns" tab='DNS' :style="{ paddingTop: '20px' }" force-render="true">
{{ template "settings/xray/dns" . }}
</a-tab-pane>
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' style="padding-top: 20px;" force-render="true">
<a-tab-pane key="tpl-advanced" tab='{{ i18n "pages.xray.advancedTemplate"}}' :style="{ paddingTop: '20px' }" force-render="true">
{{ template "settings/xray/advanced" . }}
</a-tab-pane>
</a-tabs>
@ -192,6 +192,7 @@
const app = new Vue({
delimiters: ['[[', ']]'],
mixins: [MediaQueryMixin],
el: '#app',
data: {
themeSwitcher,
@ -205,7 +206,6 @@
refreshing: false,
restartResult: '',
showAlert: false,
isMobile: DeviceUtils.isMobile(),
advSettings: 'xraySetting',
obsSettings: '',
cm: null,

View file

@ -1,57 +0,0 @@
{{define "component/passwordInput"}}
<template>
<a-input :value="value" :type="showPassword ? 'text' : 'password'" :placeholder="placeholder"
:autocomplete="autocomplete" :name="name" @input="$emit('input', $event.target.value)">
<template v-if="icon" #prefix>
<a-icon :type="icon" style="font-size: 16px;" />
</template>
<template #addonAfter>
<a-icon :type="showPassword ? 'eye-invisible' : 'eye'" @click="toggleShowPassword" style="font-size: 16px;" />
</template>
</a-input>
</template>
{{end}}
{{define "component/aPasswordInput"}}
<script>
Vue.component('a-password-input', {
props: {
'title': {
type: String,
required: false,
},
'value': {
type: String,
required: false,
},
'placeholder': {
type: String,
required: false,
},
'autocomplete': {
type: String,
required: false,
},
'name': {
type: String,
required: false,
},
'icon': {
type: undefined,
required: false
}
},
template: `{{template "component/passwordInput"}}`,
data() {
return {
showPassword: false,
};
},
methods: {
toggleShowPassword() {
this.showPassword = !this.showPassword;
},
},
});
</script>
{{end}}

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Overview"
"cpu" = "CPU"
"cpuCores" = "Cores"
"logicalProcessors" = "Logical Processors"
"frequency" = "Frequency"
"swap" = "Swap"
"storage" = "Storage"
"storageUsed" = "Used"
"storageTotal" = "Total"
"memory" = "RAM"
"hard" = "Disk"
"threads" = "Threads"
"xrayStatus" = "Xray"
"stopXray" = "Stop"
"restartXray" = "Restart"
"xraySwitch" = "Version"
"xraySwitchClick" = "Choose the version you want to switch to."
"xraySwitchClickDesk" = "Choose carefully, as older versions may not be compatible with current configurations."
"xrayStatusUnknown" = "Unknown"
"xrayStatusRunning" = "Running"
"xrayStatusStop" = "Stop"
"xrayStatusError" = "Error"
"xrayErrorPopoverTitle" = "An error occurred while running Xray"
"operationHours" = "Uptime"
"systemLoad" = "System Load"
"systemLoadDesc" = "System load average for the past 1, 5, and 15 minutes"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Estado del Sistema"
"memory" = "Memoria"
"hard" = "Disco Duro"
"cpu" = "CPU"
"cpuCores" = "Núcleos"
"logicalProcessors" = "Procesadores lógicos"
"frequency" = "Frecuencia"
"swap" = "Intercambio"
"storage" = "Almacenamiento"
"storageUsed" = "Usado"
"storageTotal" = "Total"
"memory" = "RAM"
"threads" = "Hilos"
"xrayStatus" = "Xray"
"stopXray" = "Detener"
"restartXray" = "Reiniciar"
"xraySwitch" = "Versión"
"xraySwitchClick" = "Elige la versión a la que deseas cambiar."
"xraySwitchClickDesk" = "Elige sabiamente, ya que las versiones anteriores pueden no ser compatibles con las configuraciones actuales."
"xrayStatusUnknown" = "Desconocido"
"xrayStatusRunning" = "En ejecución"
"xrayStatusStop" = "Detenido"
"xrayStatusError" = "Error"
"xrayErrorPopoverTitle" = "Se produjo un error al ejecutar Xray"
"operationHours" = "Tiempo de Funcionamiento"
"systemLoad" = "Carga del Sistema"
"systemLoadDesc" = "promedio de carga del sistema en los últimos 1, 5 y 15 minutos"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "نمای کلی"
"memory" = "RAM"
"hard" = "Disk"
"cpu" = "پردازنده"
"cpuCores" = "هسته‌ها"
"logicalProcessors" = "پردازنده‌های منطقی"
"frequency" = "فرکانس"
"swap" = "سواپ"
"storage" = "ذخیره‌سازی"
"storageUsed" = "استفاده شده"
"storageTotal" = "کل"
"memory" = "حافظه رم"
"threads" = "رشته‌ها"
"xrayStatus" = "ایکس‌ری"
"stopXray" = "توقف"
"restartXray" = "شروع‌مجدد"
"xraySwitch" = "‌نسخه"
"xraySwitchClick" = "نسخه مورد نظر را انتخاب کنید"
"xraySwitchClickDesk" = "لطفا بادقت انتخاب کنید. درصورت انتخاب نسخه قدیمی‌تر، امکان ناهماهنگی با پیکربندی فعلی وجود دارد"
"xrayStatusUnknown" = "ناشناخته"
"xrayStatusRunning" = "در حال اجرا"
"xrayStatusStop" = "متوقف"
"xrayStatusError" = "خطا"
"xrayErrorPopoverTitle" = "خطا در هنگام اجرای Xray رخ داد"
"operationHours" = "مدت‌کارکرد"
"systemLoad" = "بارسیستم"
"systemLoadDesc" = "میانگین بار سیستم برای 1، 5 و 15 دقیقه گذشته"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Ikhtisar"
"cpu" = "CPU"
"cpuCores" = "Inti"
"logicalProcessors" = "Prosesor logis"
"frequency" = "Frekuensi"
"swap" = "Swap"
"storage" = "Penyimpanan"
"storageUsed" = "Digunakan"
"storageTotal" = "Total"
"memory" = "RAM"
"hard" = "Disk"
"threads" = "Thread"
"xrayStatus" = "Xray"
"stopXray" = "Stop"
"restartXray" = "Restart"
"xraySwitch" = "Versi"
"xraySwitchClick" = "Pilih versi yang ingin Anda pindah."
"xraySwitchClickDesk" = "Pilih dengan hati-hati, karena versi yang lebih lama mungkin tidak kompatibel dengan konfigurasi saat ini."
"xrayStatusUnknown" = "Tidak diketahui"
"xrayStatusRunning" = "Berjalan"
"xrayStatusStop" = "Berhenti"
"xrayStatusError" = "Kesalahan"
"xrayErrorPopoverTitle" = "Terjadi kesalahan saat menjalankan Xray"
"operationHours" = "Waktu Aktif"
"systemLoad" = "Beban Sistem"
"systemLoadDesc" = "Rata-rata beban sistem selama 1, 5, dan 15 menit terakhir"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "システムステータス"
"memory" = "メモリ"
"hard" = "ハードディスク"
"cpu" = "CPU"
"cpuCores" = "コア"
"logicalProcessors" = "論理プロセッサ"
"frequency" = "周波数"
"swap" = "スワップ"
"storage" = "ストレージ"
"storageUsed" = "使用済み"
"storageTotal" = "合計"
"memory" = "RAM"
"threads" = "スレッド"
"xrayStatus" = "Xray"
"stopXray" = "停止"
"restartXray" = "再起動"
"xraySwitch" = "バージョン"
"xraySwitchClick" = "切り替えるバージョンを選択してください"
"xraySwitchClickDesk" = "慎重に選択してください。古いバージョンは現在の設定と互換性がない可能性があります。"
"xrayStatusUnknown" = "不明"
"xrayStatusRunning" = "実行中"
"xrayStatusStop" = "停止"
"xrayStatusError" = "エラー"
"xrayErrorPopoverTitle" = "Xrayの実行中にエラーが発生しました"
"operationHours" = "システム稼働時間"
"systemLoad" = "システム負荷"
"systemLoadDesc" = "過去1、5、15分間のシステム平均負荷"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Visão Geral"
"memory" = "Memória RAM"
"hard" = "Disco"
"cpu" = "CPU"
"cpuCores" = "Núcleos"
"logicalProcessors" = "Processadores lógicos"
"frequency" = "Frequência"
"swap" = "Swap"
"storage" = "Armazenamento"
"storageUsed" = "Usado"
"storageTotal" = "Total"
"memory" = "RAM"
"threads" = "Threads"
"xrayStatus" = "Xray"
"stopXray" = "Parar"
"restartXray" = "Reiniciar"
"xraySwitch" = "Versão"
"xraySwitchClick" = "Escolha a versão para a qual deseja alternar."
"xraySwitchClickDesk" = "Escolha com cuidado, pois versões mais antigas podem não ser compatíveis com as configurações atuais."
"xrayStatusUnknown" = "Desconhecido"
"xrayStatusRunning" = "Em execução"
"xrayStatusStop" = "Parado"
"xrayStatusError" = "Erro"
"xrayErrorPopoverTitle" = "Ocorreu um erro ao executar o Xray"
"operationHours" = "Tempo de Atividade"
"systemLoad" = "Carga do Sistema"
"systemLoadDesc" = "Média de carga do sistema nos últimos 1, 5 e 15 minutos"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Статус системы"
"memory" = "Память"
"hard" = "Жесткий диск"
"cpu" = "ЦП"
"cpuCores" = "Ядра"
"logicalProcessors" = "Логические процессоры"
"frequency" = "Частота"
"swap" = "Файл подкачки"
"storage" = "Хранилище"
"storageUsed" = "Использовано"
"storageTotal" = "Всего"
"memory" = "ОЗУ"
"threads" = "Потоки"
"xrayStatus" = "Xray"
"stopXray" = "Остановить"
"restartXray" = "Перезапустить"
"xraySwitch" = "Выбор версии"
"xraySwitchClick" = "Выберите желаемую версию"
"xraySwitchClickDesk" = "Обратите внимание: старые версии могут не поддерживать текущие настройки"
"xrayStatusUnknown" = "Неизвестно"
"xrayStatusRunning" = "Запущен"
"xrayStatusStop" = "Остановлен"
"xrayStatusError" = "Ошибка"
"xrayErrorPopoverTitle" = "Произошла ошибка при запуске Xray"
"operationHours" = "Время работы системы"
"systemLoad" = "Нагрузка на систему"
"systemLoadDesc" = "Средняя загрузка системы за последние 1, 5 и 15 минут"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Genel Bakış"
"cpu" = "İşlemci"
"cpuCores" = "Çekirdekler"
"logicalProcessors" = "Mantıksal işlemciler"
"frequency" = "Frekans"
"swap" = "Takas"
"storage" = "Depolama"
"storageUsed" = "Kullanılan"
"storageTotal" = "Toplam"
"memory" = "RAM"
"hard" = "Disk"
"threads" = "İş parçacıkları"
"xrayStatus" = "Xray"
"stopXray" = "Durdur"
"restartXray" = "Yeniden Başlat"
"xraySwitch" = "Sürüm"
"xraySwitchClick" = "Geçiş yapmak istediğiniz sürümü seçin."
"xraySwitchClickDesk" = "Dikkatli seçin, eski sürümler mevcut yapılandırmalarla uyumlu olmayabilir."
"xrayStatusUnknown" = "Bilinmiyor"
"xrayStatusRunning" = "Çalışıyor"
"xrayStatusStop" = "Durduruldu"
"xrayStatusError" = "Hata"
"xrayErrorPopoverTitle" = "Xray çalıştırılırken bir hata oluştu"
"operationHours" = "Çalışma Süresi"
"systemLoad" = "Sistem Yükü"
"systemLoadDesc" = "Geçmiş 1, 5 ve 15 dakika için sistem yük ortalaması"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Огляд"
"memory" = "Пам'ять"
"hard" = "Диск"
"cpu" = "ЦП"
"cpuCores" = "Ядра"
"logicalProcessors" = "Логічні процесори"
"frequency" = "Частота"
"swap" = "Своп"
"storage" = "Сховище"
"storageUsed" = "Використано"
"storageTotal" = "Всього"
"memory" = "ОЗП"
"threads" = "Потоки"
"xrayStatus" = "Xray"
"stopXray" = "Зупинити"
"restartXray" = "Перезапустити"
"xraySwitch" = "Версія"
"xraySwitchClick" = "Виберіть версію, на яку ви хочете перейти."
"xraySwitchClickDesk" = "Вибирайте уважно, оскільки старіші версії можуть бути несумісними з поточними конфігураціями."
"xrayStatusUnknown" = "Невідомо"
"xrayStatusRunning" = "Запущено"
"xrayStatusStop" = "Зупинено"
"xrayStatusError" = "Помилка"
"xrayErrorPopoverTitle" = "Під час роботи Xray сталася помилка"
"operationHours" = "Час роботи"
"systemLoad" = "Завантаження системи"
"systemLoadDesc" = "Середнє завантаження системи за останні 1, 5 і 15 хвилин"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "Trạng thái hệ thống"
"memory" = "Ram"
"hard" = "Dung lượng"
"cpu" = "CPU"
"cpuCores" = "Nhân"
"logicalProcessors" = "Bộ xử lý logic"
"frequency" = "Tần số"
"swap" = "Swap"
"storage" = "Lưu trữ"
"storageUsed" = "Đã dùng"
"storageTotal" = "Tổng"
"memory" = "RAM"
"threads" = "Luồng"
"xrayStatus" = "Xray"
"stopXray" = "Dừng lại"
"restartXray" = "Khởi động lại"
"xraySwitch" = "Phiên bản"
"xraySwitchClick" = "Chọn phiên bản mà bạn muốn chuyển đổi sang."
"xraySwitchClickDesk" = "Hãy lựa chọn thận trọng, vì các phiên bản cũ có thể không tương thích với các cấu hình hiện tại."
"xrayStatusUnknown" = "Không xác định"
"xrayStatusRunning" = "Đang chạy"
"xrayStatusStop" = "Dừng"
"xrayStatusError" = "Lỗi"
"xrayErrorPopoverTitle" = "Đã xảy ra lỗi khi chạy Xray"
"operationHours" = "Thời gian hoạt động"
"systemLoad" = "Tải hệ thống"
"systemLoadDesc" = "trung bình tải hệ thống trong 1, 5 và 15 phút qua"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "系统状态"
"cpu" = "CPU"
"cpuCores" = "核心"
"logicalProcessors" = "逻辑处理器"
"frequency" = "频率"
"swap" = "交换分区"
"storage" = "存储"
"storageUsed" = "已用"
"storageTotal" = "总计"
"memory" = "内存"
"hard" = "磁盘"
"threads" = "线程"
"xrayStatus" = "Xray"
"stopXray" = "停止"
"restartXray" = "重启"
"xraySwitch" = "版本"
"xraySwitchClick" = "选择你要切换到的版本"
"xraySwitchClickDesk" = "请谨慎选择,因为较旧版本可能与当前配置不兼容"
"xrayStatusUnknown" = "未知"
"xrayStatusRunning" = "运行中"
"xrayStatusStop" = "停止"
"xrayStatusError" = "错误"
"xrayErrorPopoverTitle" = "运行Xray时发生错误"
"operationHours" = "系统正常运行时间"
"systemLoad" = "系统负载"
"systemLoadDesc" = "过去 1、5 和 15 分钟的系统平均负载"

View file

@ -91,14 +91,27 @@
[pages.index]
"title" = "系統狀態"
"cpu" = "CPU"
"cpuCores" = "核心"
"logicalProcessors" = "邏輯處理器"
"frequency" = "頻率"
"swap" = "交換空間"
"storage" = "儲存"
"storageUsed" = "已使用"
"storageTotal" = "總計"
"memory" = "記憶體"
"hard" = "磁碟"
"threads" = "執行緒"
"xrayStatus" = "Xray"
"stopXray" = "停止"
"restartXray" = "重啟"
"xraySwitch" = "版本"
"xraySwitchClick" = "選擇你要切換到的版本"
"xraySwitchClickDesk" = "請謹慎選擇,因為較舊版本可能與當前配置不相容"
"xrayStatusUnknown" = "未知"
"xrayStatusRunning" = "運行中"
"xrayStatusStop" = "停止"
"xrayStatusError" = "錯誤"
"xrayErrorPopoverTitle" = "執行Xray時發生錯誤"
"operationHours" = "系統正常執行時間"
"systemLoad" = "系統負載"
"systemLoadDesc" = "過去 1、5 和 15 分鐘的系統平均負載"