mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-05 01:36:19 +00:00
Merge cd83708c17
into bbcab768ca
This commit is contained in:
commit
cdc9231929
24 changed files with 1521 additions and 162 deletions
|
@ -20,6 +20,7 @@ type SubService struct {
|
|||
address string
|
||||
showInfo bool
|
||||
remarkModel string
|
||||
datepicker string
|
||||
inboundService service.InboundService
|
||||
settingService service.SettingService
|
||||
}
|
||||
|
@ -39,6 +40,10 @@ func (s *SubService) GetSubs(subId string, host string, showInfo bool) ([]string
|
|||
if err != nil {
|
||||
s.remarkModel = "-ieo"
|
||||
}
|
||||
s.datepicker, err = s.settingService.GetDatepicker()
|
||||
if err != nil {
|
||||
s.datepicker = "gregorian"
|
||||
}
|
||||
for _, inbound := range inbounds {
|
||||
clients, err := s.inboundService.GetClients(inbound)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,6 +12,7 @@ class AllSetting {
|
|||
this.expireDiff = "";
|
||||
this.trafficDiff = "";
|
||||
this.remarkModel = "-ieo";
|
||||
this.datepicker = "gregorian";
|
||||
this.tgBotEnable = false;
|
||||
this.tgBotToken = "";
|
||||
this.tgBotChatId = "";
|
||||
|
|
1252
web/assets/moment/moment-jalali.min.js
vendored
Normal file
1252
web/assets/moment/moment-jalali.min.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1
web/assets/persian-datepicker/persian-datepicker.min.css
vendored
Normal file
1
web/assets/persian-datepicker/persian-datepicker.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
web/assets/persian-datepicker/persian-datepicker.min.js
vendored
Normal file
1
web/assets/persian-datepicker/persian-datepicker.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -47,6 +47,7 @@ type AllSetting struct {
|
|||
SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"`
|
||||
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"`
|
||||
SubURI string `json:"subURI" form:"subURI"`
|
||||
Datepicker string `json:"datepicker" form:"datepicker"`
|
||||
}
|
||||
|
||||
func (s *AllSetting) CheckValid() error {
|
||||
|
|
|
@ -104,8 +104,10 @@
|
|||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
<a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme" v-model="clientsBulkModal.expiryTime"></a-date-picker>
|
||||
<persian-datepicker v-else :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
value="clientsBulkModal.expiryTime" v-model="clientsBulkModal.expiryTime"></persian-datepicker>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="clientsBulkModal.expiryTime != 0">
|
||||
<template slot="label">
|
||||
|
@ -234,6 +236,9 @@
|
|||
get delayedExpireDays() {
|
||||
return this.clientsBulkModal.expiryTime < 0 ? this.clientsBulkModal.expiryTime / -86400000 : 0;
|
||||
},
|
||||
get datepicker() {
|
||||
return app.datepicker;
|
||||
},
|
||||
set delayedExpireDays(days) {
|
||||
this.clientsBulkModal.expiryTime = -86400000 * days;
|
||||
},
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
get isEdit() {
|
||||
return this.clientModal.isEdit;
|
||||
},
|
||||
get datepicker() {
|
||||
return app.datepicker;
|
||||
},
|
||||
get isTrafficExhausted() {
|
||||
if (!clientStats) return false
|
||||
if (clientStats.total <= 0) return false
|
||||
|
|
59
web/html/xui/component/persianDatepicker.html
Normal file
59
web/html/xui/component/persianDatepicker.html
Normal file
|
@ -0,0 +1,59 @@
|
|||
{{define "component/persianDatepickerTemplate"}}
|
||||
<template>
|
||||
<div>
|
||||
<a-input :value="value" type="text" v-model="date" data-jdp class="persian-datepicker"
|
||||
@input="$emit('input', convertToGregorian($event.target.value)); jalaliDatepicker.hide();"
|
||||
placeholder="انتخاب تاریخ">
|
||||
<template #addonAfter>
|
||||
<a-icon type="calendar" style="font-size: 16px;"/>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
</template>
|
||||
{{end}}
|
||||
|
||||
{{define "component/persianDatepicker"}}
|
||||
<link rel="stylesheet" href="{{ .base_path }}assets/persian-datepicker/persian-datepicker.min.css"/>
|
||||
<script src="{{ .base_path }}assets/moment/moment-jalali.min.js"></script>
|
||||
<script src="{{ .base_path }}assets/persian-datepicker/persian-datepicker.min.js"></script>
|
||||
<script>
|
||||
|
||||
const persianDatepicker = {};
|
||||
|
||||
Vue.component('persian-datepicker', {
|
||||
props: ['dropdown-class-name', 'format', 'value'],
|
||||
template: `{{template "component/persianDatepickerTemplate"}}`,
|
||||
data() {
|
||||
return {
|
||||
date: '',
|
||||
persianDatepicker,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value: function (date) {
|
||||
this.date = this.convertToJalalian(date)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.date = this.convertToJalalian(this.value)
|
||||
this.listenToDatepicker()
|
||||
},
|
||||
methods: {
|
||||
convertToGregorian(date) {
|
||||
return date ? moment(moment(date, 'jYYYY/jMM/jDD HH:mm:ss').format('YYYY-MM-DD HH:mm:ss')) : null
|
||||
},
|
||||
convertToJalalian(date) {
|
||||
return date && moment.isMoment(date) ? date.format('jYYYY/jMM/jDD HH:mm:ss') : null
|
||||
},
|
||||
listenToDatepicker() {
|
||||
jalaliDatepicker.startWatch({
|
||||
time: true,
|
||||
hideAfterChange: true,
|
||||
useDropDownYears: false,
|
||||
changeMonthRotateYear: true,
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
|
@ -150,8 +150,10 @@
|
|||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
<a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme" v-model="client._expiryTime"></a-date-picker>
|
||||
<persian-datepicker v-else :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
value="client._expiryTime" v-model="client._expiryTime"></persian-datepicker>
|
||||
<a-tag color="red" v-if="isEdit && isExpiry">Expired</a-tag>
|
||||
</a-form-item>
|
||||
<a-form-item v-if="client.expiryTime != 0">
|
||||
|
|
|
@ -54,9 +54,11 @@
|
|||
<a-icon type="question-circle"></a-icon>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss"
|
||||
<a-date-picker 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>
|
||||
<persian-datepicker v-else :dropdown-class-name="themeSwitcher.currentTheme"
|
||||
value="dbInbound._expiryTime" v-model="dbInbound._expiryTime"></persian-datepicker>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
get client() {
|
||||
return inModal.inbound.clients[0];
|
||||
},
|
||||
get datepicker() {
|
||||
return app.datepicker;
|
||||
},
|
||||
get delayedExpireDays() {
|
||||
return this.client && this.client.expiryTime < 0 ? this.client.expiryTime / -86400000 : 0;
|
||||
},
|
||||
|
|
|
@ -446,6 +446,7 @@
|
|||
<script src="{{ .base_path }}assets/js/model/xray.js?{{ .cur_ver }}"></script>
|
||||
<script src="{{ .base_path }}assets/js/model/dbinbound.js?{{ .cur_ver }}"></script>
|
||||
{{template "component/themeSwitcher" .}}
|
||||
{{template "component/persianDatepicker" .}}
|
||||
<script>
|
||||
const columns = [{
|
||||
title: "ID",
|
||||
|
@ -539,6 +540,7 @@
|
|||
data: {
|
||||
siderDrawer,
|
||||
themeSwitcher,
|
||||
persianDatepicker,
|
||||
spinning: false,
|
||||
inbounds: [],
|
||||
dbInbounds: [],
|
||||
|
@ -560,6 +562,7 @@
|
|||
subURI : ''
|
||||
},
|
||||
remarkModel: '-ieo',
|
||||
datepicker: 'gregorian',
|
||||
tgBotEnable: false,
|
||||
pageSize: 0,
|
||||
isMobile: window.innerWidth <= 768,
|
||||
|
@ -605,6 +608,7 @@
|
|||
};
|
||||
this.pageSize = pageSize;
|
||||
this.remarkModel = remarkModel;
|
||||
this.datepicker = datepicker;
|
||||
}
|
||||
},
|
||||
setInbounds(dbInbounds) {
|
||||
|
|
|
@ -138,6 +138,27 @@
|
|||
<setting-list-item type="number" title='{{ i18n "pages.settings.expireTimeDiff" }}' desc='{{ i18n "pages.settings.expireTimeDiffDesc" }}' v-model="allSetting.expireDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="number" title='{{ i18n "pages.settings.trafficDiff" }}' desc='{{ i18n "pages.settings.trafficDiffDesc" }}' v-model="allSetting.trafficDiff" :min="0"></setting-list-item>
|
||||
<setting-list-item type="text" title='{{ i18n "pages.settings.timeZone"}}' desc='{{ i18n "pages.settings.timeZoneDesc"}}' v-model="allSetting.timeLocation"></setting-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta title='{{ i18n "pages.settings.datepicker"}}'>
|
||||
<template slot="description">{{ i18n "pages.settings.datepickerDescription"}}</template>
|
||||
</a-list-item-meta>
|
||||
</a-col>
|
||||
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<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>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
<a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
|
@ -197,7 +218,7 @@
|
|||
<td>
|
||||
<a-form-item>
|
||||
<password-input v-model="user.newPassword" style="width: 200px"></password-input>
|
||||
</a-form-item>
|
||||
</a-form-item>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
@ -311,6 +332,7 @@
|
|||
showAlert: false,
|
||||
remarkModels: {i:'Inbound',e:'Email',o:'Other'},
|
||||
remarkSeparators: [' ','-','_','@',':','~','|',',','.','/'],
|
||||
datepickerList: [{name:'Gregorian (Standard)', value: 'gregorian'}, {name:'Jalalian (شمسی)', value: 'jalalian'}],
|
||||
remarkSample: '',
|
||||
get remarkModel() {
|
||||
rm = this.allSetting.remarkModel;
|
||||
|
@ -328,11 +350,17 @@
|
|||
this.allSetting.remarkModel = value + this.allSetting.remarkModel.substring(1);
|
||||
this.changeRemarkSample();
|
||||
},
|
||||
get datepicker() {
|
||||
return this.allSetting.datepicker ? this.allSetting.datepicker : 'gregorian';
|
||||
},
|
||||
set datepicker(value) {
|
||||
this.allSetting.datepicker = value;
|
||||
},
|
||||
changeRemarkSample(){
|
||||
sample = []
|
||||
this.remarkModel.forEach(r => sample.push(this.remarkModels[r]));
|
||||
this.remarkSample = sample.length == 0 ? '' : sample.join(this.remarkSeparator);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loading(spinning = true) {
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
<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">
|
||||
:overlay-class-name="themeSwitcher.currentTheme">
|
||||
<span slot="title" style="font-size: 12pt">Error in running xray-core</span>
|
||||
<template slot="content">
|
||||
<p style="max-width: 400px" v-for="line in restartResult.split('\n')">[[ line ]]</p>
|
||||
|
@ -83,15 +83,15 @@
|
|||
<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
|
||||
message='{{ i18n "pages.settings.infoDesc" }}'
|
||||
show-icon
|
||||
>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
<a-tabs class="ant-card-dark-box-nohover" default-active-key="tpl-1"
|
||||
@change="(activeKey) => { if(activeKey == 'tpl-4') this.changeCode(); }"
|
||||
:class="themeSwitcher.currentTheme">
|
||||
@change="(activeKey) => { if(activeKey == 'tpl-4') this.changeCode(); }"
|
||||
:class="themeSwitcher.currentTheme">
|
||||
<a-tab-pane key="tpl-1" tab='{{ i18n "pages.xray.basicTemplate"}}'>
|
||||
<a-space direction="horizontal" style="padding: 20px 20px">
|
||||
<a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button>
|
||||
|
@ -109,16 +109,16 @@
|
|||
<a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.FreedomStrategy" }}'
|
||||
description='{{ i18n "pages.xray.FreedomStrategyDesc" }}'/>
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.FreedomStrategy" }}'
|
||||
description='{{ i18n "pages.xray.FreedomStrategyDesc" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select
|
||||
v-model="freedomStrategy"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||
style="width: 100%">
|
||||
v-model="freedomStrategy"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||
style="width: 100%">
|
||||
<a-select-option v-for="s in outboundDomainStrategies" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
|
@ -127,22 +127,22 @@
|
|||
</a-list-item>
|
||||
<a-row style="padding: 20px">
|
||||
<a-col :lg="24" :xl="12">
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.RoutingStrategy" }}'
|
||||
description='{{ i18n "pages.xray.RoutingStrategyDesc" }}'/>
|
||||
<a-list-item-meta
|
||||
title='{{ i18n "pages.xray.RoutingStrategy" }}'
|
||||
description='{{ i18n "pages.xray.RoutingStrategyDesc" }}'/>
|
||||
</a-col>
|
||||
<a-col :lg="24" :xl="12">
|
||||
<template>
|
||||
<a-select
|
||||
v-model="routingStrategy"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||
style="width: 100%">
|
||||
v-model="routingStrategy"
|
||||
:dropdown-class-name="themeSwitcher.currentTheme"
|
||||
style="width: 100%">
|
||||
<a-select-option v-for="s in routingDomainStrategies" :value="s">[[ s ]]</a-select-option>
|
||||
</a-select>
|
||||
</template>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-list-item>
|
||||
</a-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.blockConfigs"}}'>
|
||||
<a-row :xs="24" :sm="24" :lg="12">
|
||||
|
@ -175,7 +175,7 @@
|
|||
<setting-list-item type="switch" title='{{ i18n "pages.xray.ChinaDomain"}}' desc='{{ i18n "pages.xray.ChinaDomainDesc"}}' v-model="ChinaDomainSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.RussiaIp"}}' desc='{{ i18n "pages.xray.RussiaIpDesc"}}' v-model="RussiaIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.RussiaDomain"}}' desc='{{ i18n "pages.xray.RussiaDomainDesc"}}' v-model="RussiaDomainSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.VNIp"}}' desc='{{ i18n "pages.xray.VNIpDesc"}}' v-model="VNIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.VNIp"}}' desc='{{ i18n "pages.xray.VNIpDesc"}}' v-model="VNIpSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.VNDomain"}}' desc='{{ i18n "pages.xray.VNDomainDesc"}}' v-model="VNDomainSettings"></setting-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.directCountryConfigs"}}'>
|
||||
|
@ -193,8 +193,8 @@
|
|||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectChinaDomain"}}' desc='{{ i18n "pages.xray.DirectChinaDomainDesc"}}' v-model="ChinaDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectRussiaIp"}}' desc='{{ i18n "pages.xray.DirectRussiaIpDesc"}}' v-model="RussiaIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectRussiaDomain"}}' desc='{{ i18n "pages.xray.DirectRussiaDomainDesc"}}' v-model="RussiaDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNIp"}}' desc='{{ i18n "pages.xray.DirectVNIpDesc"}}' v-model="VNIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNDomain"}}' desc='{{ i18n "pages.xray.DirectVNDomainDesc"}}' v-model="VNDomainDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNIp"}}' desc='{{ i18n "pages.xray.DirectVNIpDesc"}}' v-model="VNIpDirectSettings"></setting-list-item>
|
||||
<setting-list-item type="switch" title='{{ i18n "pages.xray.DirectVNDomain"}}' desc='{{ i18n "pages.xray.DirectVNDomainDesc"}}' v-model="VNDomainDirectSettings"></setting-list-item>
|
||||
</a-collapse-panel>
|
||||
<a-collapse-panel header='{{ i18n "pages.xray.ipv4Configs"}}'>
|
||||
<a-row :xs="24" :sm="24" :lg="12">
|
||||
|
@ -226,15 +226,15 @@
|
|||
</a-tab-pane>
|
||||
<a-tab-pane key="tpl-2" tab='{{ i18n "pages.xray.Routings"}}' style="padding-top: 20px;">
|
||||
<a-alert type="warning" style="margin-bottom: 10px; width: fit-content"
|
||||
message='{{ i18n "pages.xray.RoutingsDesc"}}' show-icon></a-alert>
|
||||
message='{{ i18n "pages.xray.RoutingsDesc"}}' show-icon></a-alert>
|
||||
<a-button type="primary" icon="plus" @click="addRule">{{ i18n "pages.xray.rules.add" }}</a-button>
|
||||
<a-table :columns="isMobile ? rulesMobileColumns : rulesColumns" bordered
|
||||
:row-key="r => r.key"
|
||||
:data-source="routingRuleData"
|
||||
:scroll="isMobile ? {} : { x: 1000 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-top: 10px;'">
|
||||
:row-key="r => r.key"
|
||||
:data-source="routingRuleData"
|
||||
:scroll="isMobile ? {} : { x: 1000 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-top: 10px;'">
|
||||
<template slot="action" slot-scope="text, rule, index">
|
||||
[[ index+1 ]]
|
||||
<a-dropdown :trigger="['click']">
|
||||
|
@ -287,8 +287,8 @@
|
|||
</template>
|
||||
<template slot="info" slot-scope="text, rule, index">
|
||||
<a-popover placement="bottomRight"
|
||||
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
||||
:overlay-class-name="themeSwitcher.currentTheme" trigger="click">
|
||||
v-if="(rule.source+rule.sourcePort+rule.network+rule.protocol+rule.attrs+rule.ip+rule.domain+rule.port).length>0"
|
||||
:overlay-class-name="themeSwitcher.currentTheme" trigger="click">
|
||||
<template slot="content">
|
||||
<table cellpadding="2" style="max-width: 300px;">
|
||||
<tr v-if="rule.source">
|
||||
|
@ -339,12 +339,12 @@
|
|||
<a-col :sm="24" :md="12">
|
||||
<p style="margin: 10px;">{{ i18n "pages.xray.Outbounds"}}</p>
|
||||
<a-table :columns="outboundColumns" bordered
|
||||
:row-key="r => r.key"
|
||||
:data-source="outboundData"
|
||||
:scroll="isMobile ? {} : { x: 200 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 5px' : 'margin-right: 1px;'">
|
||||
:row-key="r => r.key"
|
||||
:data-source="outboundData"
|
||||
:scroll="isMobile ? {} : { x: 200 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 5px' : 'margin-right: 1px;'">
|
||||
<template slot="action" slot-scope="text, outbound, index">
|
||||
[[ index+1 ]]
|
||||
<a-dropdown :trigger="['click']">
|
||||
|
@ -378,12 +378,12 @@
|
|||
<a-col :sm="24" :md="12" v-if="reverseData.length>0">
|
||||
<p style="margin: 10px;">{{ i18n "pages.xray.outbound.reverse"}}</p>
|
||||
<a-table :columns="reverseColumns" bordered
|
||||
:row-key="r => r.key"
|
||||
:data-source="reverseData"
|
||||
:scroll="isMobile ? {} : { x: 200 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
:row-key="r => r.key"
|
||||
:data-source="reverseData"
|
||||
:scroll="isMobile ? {} : { x: 200 }"
|
||||
:pagination="false"
|
||||
:indent-size="0"
|
||||
:style="isMobile ? 'padding: 5px 0' : 'margin-left: 1px;'">
|
||||
<template slot="action" slot-scope="text, reverse, index">
|
||||
[[ index+1 ]]
|
||||
<a-dropdown :trigger="['click']">
|
||||
|
@ -428,22 +428,22 @@
|
|||
{{template "outModal"}}
|
||||
{{template "reverseModal"}}
|
||||
<script>
|
||||
const rulesColumns = [
|
||||
const rulesColumns = [
|
||||
{ title: "#", align: 'center', width: 15, scopedSlots: { customRender: 'action' } },
|
||||
{ title: '{{ i18n "pages.xray.rules.source"}}', children: [
|
||||
{ title: 'IP', dataIndex: "source", align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'port', dataIndex: 'sourcePort', align: 'center', width: 10, ellipsis: true } ]},
|
||||
{ title: 'IP', dataIndex: "source", align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'port', dataIndex: 'sourcePort', align: 'center', width: 10, ellipsis: true } ]},
|
||||
{ title: '{{ i18n "pages.inbounds.network"}}', children: [
|
||||
{ title: 'L4', dataIndex: 'network', align: 'center', width: 10 },
|
||||
{ title: 'Protocol', dataIndex: 'protocol', align: 'center', width: 10, ellipsis: true },
|
||||
{ title: 'Attrs', dataIndex: 'attrs', align: 'center', width: 20, ellipsis: true } ]},
|
||||
{ title: 'L4', dataIndex: 'network', align: 'center', width: 10 },
|
||||
{ title: 'Protocol', dataIndex: 'protocol', align: 'center', width: 10, ellipsis: true },
|
||||
{ title: 'Attrs', dataIndex: 'attrs', align: 'center', width: 20, ellipsis: true } ]},
|
||||
{ title: '{{ i18n "pages.xray.rules.dest"}}', children: [
|
||||
{ title: 'IP', dataIndex: 'ip', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Domain', dataIndex: 'domain', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Port', dataIndex: 'port', align: 'center', width: 10, ellipsis: true }]},
|
||||
{ title: 'IP', dataIndex: 'ip', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Domain', dataIndex: 'domain', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Port', dataIndex: 'port', align: 'center', width: 10, ellipsis: true }]},
|
||||
{ title: '{{ i18n "pages.xray.rules.inbound"}}', children: [
|
||||
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
||||
{ title: 'Inbound Tag', dataIndex: 'inboundTag', align: 'center', width: 20, ellipsis: true },
|
||||
{ title: 'Client Email', dataIndex: 'user', align: 'center', width: 20, ellipsis: true }]},
|
||||
{ title: '{{ i18n "pages.xray.rules.outbound"}}', dataIndex: 'outboundTag', align: 'center', width: 20 },
|
||||
];
|
||||
|
||||
|
@ -538,7 +538,7 @@
|
|||
cn: ["geoip:cn"],
|
||||
ir: ["ext:geoip_IR.dat:ir"],
|
||||
ru: ["geoip:ru"],
|
||||
vn: ["ext:geoip_VN.dat:vn"],
|
||||
vn: ["ext:geoip_VN.dat:vn"],
|
||||
},
|
||||
domains: {
|
||||
ads: [
|
||||
|
@ -568,11 +568,11 @@
|
|||
"regexp:.*\\.xn--mgba3a4f16a$", // .ایران
|
||||
"ext:geosite_IR.dat:ir"
|
||||
],
|
||||
vn: [
|
||||
"regexp:.*\\.vn$",
|
||||
vn: [
|
||||
"regexp:.*\\.vn$",
|
||||
"ext:geosite_VN.dat:vn",
|
||||
"ext:geosite_VN.dat:ads"
|
||||
]
|
||||
]
|
||||
},
|
||||
familyProtectDNS: {
|
||||
"servers": [
|
||||
|
@ -620,10 +620,10 @@
|
|||
},
|
||||
async getXrayResult() {
|
||||
const msg = await HttpUtil.get("/panel/xray/getXrayResult");
|
||||
if(msg.success){
|
||||
this.restartResult=msg.obj;
|
||||
if(msg.obj.length > 1) Vue.prototype.$message.error(msg.obj);
|
||||
}
|
||||
if(msg.success){
|
||||
this.restartResult=msg.obj;
|
||||
if(msg.obj.length > 1) Vue.prototype.$message.error(msg.obj);
|
||||
}
|
||||
},
|
||||
async fetchUserSecret() {
|
||||
this.loading(true);
|
||||
|
@ -661,9 +661,9 @@
|
|||
},
|
||||
async toggleToken(value) {
|
||||
if (value) {
|
||||
await this.getNewSecret();
|
||||
await this.getNewSecret();
|
||||
} else {
|
||||
this.user.loginSecret = "";
|
||||
this.user.loginSecret = "";
|
||||
}
|
||||
},
|
||||
async resetXrayConfigToDefault() {
|
||||
|
@ -902,7 +902,7 @@
|
|||
newRules = newTemplateSettings.routing.rules.filter(r => r.outboundTag != oldData.tag);
|
||||
}
|
||||
newTemplateSettings.routing.rules = newRules;
|
||||
|
||||
|
||||
this.templateSettings = newTemplateSettings;
|
||||
},
|
||||
addRule(){
|
||||
|
@ -1321,7 +1321,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
VNIpSettings: {
|
||||
VNIpSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.vn, this.blockedIPs);
|
||||
},
|
||||
|
@ -1417,7 +1417,7 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
VNIpDirectSettings: {
|
||||
VNIpDirectSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.ips.vn, this.directIPs);
|
||||
},
|
||||
|
@ -1440,7 +1440,7 @@
|
|||
this.directDomains = this.directDomains.filter(data => !this.settingsData.domains.vn.includes(data));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
GoogleWARPSettings: {
|
||||
get: function () {
|
||||
return doAllItemsExist(this.settingsData.domains.google, this.warpDomains);
|
||||
|
@ -1493,4 +1493,4 @@
|
|||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
|
@ -4,9 +4,9 @@
|
|||
:ok-text="ruleModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme">
|
||||
<a-form :colon="false" :label-col="{ md: {span:6} }" :wrapper-col="{ md: {span:14} }">
|
||||
<a-form-item label='Domain Matcher'>
|
||||
<a-select v-model="ruleModal.rule.domainMatcher" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="dm in ['','hybrid','linear']" :value="dm">[[ dm ]]</a-select-option>
|
||||
</a-select>
|
||||
<a-select v-model="ruleModal.rule.domainMatcher" :dropdown-class-name="themeSwitcher.currentTheme">
|
||||
<a-select-option v-for="dm in ['','hybrid','linear']" :value="dm">[[ dm ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<template slot="label">
|
||||
|
@ -107,7 +107,7 @@
|
|||
<a-select-option v-for="tag in ruleModal.outboundTags" :value="tag">[[ tag ]]</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</table>
|
||||
</table>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
<script>
|
||||
|
@ -214,11 +214,11 @@
|
|||
|
||||
for (const [key, value] of Object.entries(rule)) {
|
||||
if (
|
||||
value !== null &&
|
||||
value !== undefined &&
|
||||
!(Array.isArray(value) && value.length === 0) &&
|
||||
!(typeof value === 'object' && Object.keys(value).length === 0) &&
|
||||
value !== ''
|
||||
value !== null &&
|
||||
value !== undefined &&
|
||||
!(Array.isArray(value) && value.length === 0) &&
|
||||
!(typeof value === 'object' && Object.keys(value).length === 0) &&
|
||||
value !== ''
|
||||
) {
|
||||
newRule[key] = value;
|
||||
}
|
||||
|
@ -236,4 +236,4 @@
|
|||
});
|
||||
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
|
@ -56,6 +56,7 @@ var defaultValueMap = map[string]string{
|
|||
"subEncrypt": "true",
|
||||
"subShowInfo": "true",
|
||||
"subURI": "",
|
||||
"datepicker": "gregorian",
|
||||
}
|
||||
|
||||
type SettingService struct {
|
||||
|
@ -417,6 +418,10 @@ func (s *SettingService) GetSubURI() (string, error) {
|
|||
return s.getString("subURI")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetDatepicker() (string, error) {
|
||||
return s.getString("datepicker")
|
||||
}
|
||||
|
||||
func (s *SettingService) GetPageSize() (int, error) {
|
||||
return s.getInt("pageSize")
|
||||
}
|
||||
|
@ -463,6 +468,7 @@ func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
|||
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
||||
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
||||
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
||||
"datepicker": func() (interface{}, error) { return s.GetDatepicker() },
|
||||
}
|
||||
|
||||
result := make(map[string]interface{})
|
||||
|
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "Pagination Size"
|
||||
"pageSizeDesc" = "Define page size for inbounds table. Set 0 to disable"
|
||||
"remarkModel" = "Remark Model and Seperation Charachter"
|
||||
"datepicker" = "Datepicker"
|
||||
"datepickerDescription" = "Selector calendar type specifies the expiration date"
|
||||
"sampleRemark" = "Sample Remark"
|
||||
"oldUsername" = "Current Username"
|
||||
"currentPassword" = "Current Password"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }} : Enabled successfully."
|
||||
"disableSuccess" = "✅ {{ .Email }} : Disabled successfully."
|
||||
"askToAddUserId" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram user id in your configuration(s).\r\n\r\nYour user id: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>\r\n\r\nYour user id: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Your configuration is not found!\r\nPlease ask your Admin to use your telegram username or user id in your configuration(s).\r\n\r\nYour username: <b>@{{ .TgUserName }}</b>\r\n\r\nYour user id: <b>{{ .TgUserID }}</b>"
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "Tamaño de paginación"
|
||||
"pageSizeDesc" = "Defina el tamaño de página para la tabla de entradas. Establezca 0 para desactivar"
|
||||
"remarkModel" = "Modelo de observación y carácter de separación"
|
||||
"datepicker" = "selector de fechas"
|
||||
"datepickerDescription" = "El tipo de calendario selector especifica la fecha de vencimiento"
|
||||
"sampleRemark" = "Observación de muestra"
|
||||
"oldUsername" = "Nombre de Usuario Actual"
|
||||
"currentPassword" = "Contraseña Actual"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }} : Habilitado exitosamente."
|
||||
"disableSuccess" = "✅ {{ .Email }} : Deshabilitado exitosamente."
|
||||
"askToAddUserId" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu ID de usuario: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su nombre de usuario o ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu nombre de usuario: <b>@{{ .TgUserName }}</b>\r\n\r\nSu ID de usuario: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "¡No se encuentra su configuración!\r\nPor favor, pídale a su administrador que use su nombre de usuario o ID de usuario de Telegram en su(s) configuración(es).\r\n\r\nSu nombre de usuario: <b>@{{ .TgUserName }}</b>\r\n\r\nSu ID de usuario: <b>{{ .TgUserID }}</b>"
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "اندازه صفحه بندی جدول"
|
||||
"pageSizeDesc" = "اندازه صفحه را برای جدول سرویس ها تعریف کنید. 0: غیرفعال"
|
||||
"remarkModel" = "نام کانفیگ و جداکننده"
|
||||
"datepicker" = "انتخاب کننده تاریخ"
|
||||
"datepickerDescription" = "نوع تقویم انتخاب کننده تاریخ انقضا را مشخص میکند "
|
||||
"sampleRemark" = "نمونه نام"
|
||||
"oldUsername" = "نام کاربری فعلی"
|
||||
"currentPassword" = "رمز عبور فعلی"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }} : با موفقیت فعال شد."
|
||||
"disableSuccess" = "✅ {{ .Email }} : با موفقیت غیرفعال شد."
|
||||
"askToAddUserId" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nشناسه کاربری شما: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که نام کاربری یا شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nنام کاربری شما: <b>@{{ .TgUserName }}</b>\r\n\r\nشناسه کاربری شما: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "پیکربندی شما یافت نشد!\r\nلطفاً از مدیر خود بخواهید که نام کاربری یا شناسه کاربر تلگرام خود را در پیکربندی (های) خود استفاده کند.\r\n\r\nنام کاربری شما: <b>@{{ .TgUserName }}</b>\r\n\r\nشناسه کاربری شما: <b>{{ .TgUserID }}</b>"
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "Размер нумерации страниц"
|
||||
"pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить"
|
||||
"remarkModel" = "Модель примечания и символ разделения"
|
||||
"datepicker" = "выбор даты"
|
||||
"datepickerDescription" = "Тип календаря выбора указывает дату истечения срока действия."
|
||||
"sampleRemark" = "Пример замечания"
|
||||
"oldUsername" = "Текущее имя пользователя"
|
||||
"currentPassword" = "Текущий пароль"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }}: Включено успешно."
|
||||
"disableSuccess" = "✅ {{ .Email }}: Отключено успешно."
|
||||
"askToAddUserId" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваш идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаш идентификатор пользователя: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваше имя пользователя или идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаше имя пользователя: <b>@{{ .TgUserName }}</b>\r\n\r\nВаш идентификатор пользователя: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Ваша конфигурация не найдена!\r\nПожалуйста, попросите администратора использовать ваше имя пользователя или идентификатор пользователя Telegram в ваших конфигурациях.\r\n\r\nВаше имя пользователя: <b>@{{ .TgUserName }}</b>\r\n\r\nВаш идентификатор пользователя: <b>{{ .TgUserID }}</b>"
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "Kích thước phân trang"
|
||||
"pageSizeDesc" = "Xác định kích thước trang cho bảng gửi đến. Đặt 0 để tắt"
|
||||
"remarkModel" = "Ghi chú mô hình và ký tự phân tách"
|
||||
"datepicker" = "bảng chọn ngày"
|
||||
"datepickerDescription" = "Loại lịch chọn chỉ định ngày hết hạn"
|
||||
"sampleRemark" = "Nhận xét mẫu"
|
||||
"oldUsername" = "Tên người dùng hiện tại"
|
||||
"currentPassword" = "Mật khẩu hiện tại"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }} : Đã Bật Thành Công."
|
||||
"disableSuccess" = "✅ {{ .Email }} : Đã Tắt Thành Công."
|
||||
"askToAddUserId" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nID người dùng của bạn: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng tên người dùng hoặc ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nTên người dùng của bạn: <b>@{{ .TgUserName }}</b>\r\n\r\nID người dùng của bạn: <b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "Cấu hình của bạn không được tìm thấy!\r\nVui lòng yêu cầu Quản trị viên sử dụng tên người dùng hoặc ID người dùng telegram của bạn trong cấu hình của bạn.\r\n\r\nTên người dùng của bạn: <b>@{{ .TgUserName }}</b>\r\n\r\nID người dùng của bạn: <b>{{ .TgUserID }}</b>"
|
|
@ -246,6 +246,8 @@
|
|||
"pageSize" = "分页大小"
|
||||
"pageSizeDesc" = "定义入站表的页面大小。设置 0 表示禁用"
|
||||
"remarkModel" = "备注模型和分隔符"
|
||||
"datepicker" = "日期选择器"
|
||||
"datepickerDescription" = "选择器日历类型指定到期日期"
|
||||
"sampleRemark" = "备注示例"
|
||||
"oldUsername" = "原用户名"
|
||||
"currentPassword" = "原密码"
|
||||
|
@ -422,7 +424,7 @@
|
|||
"loginSecurity" = "登录安全"
|
||||
"loginSecurityDesc" = "在用户登录页面中切换附加步骤"
|
||||
"secretToken" = "密钥"
|
||||
"secretTokenDesc" = "复制此密钥并将其保存在安全的地方;没有这个你将无法登录。这也无法从 x-ui 命令工具中恢复"
|
||||
"secretTokenDesc" = "复制此密钥并将其保存在安全的地方;没有这个你将无法登录。这也无法从 x-ui 命令工具中恢复"
|
||||
|
||||
[pages.settings.toasts]
|
||||
"modifySettings" = "修改设置"
|
||||
|
@ -549,4 +551,4 @@
|
|||
"enableSuccess" = "✅ {{ .Email }}:已成功启用。"
|
||||
"disableSuccess" = "✅ {{ .Email }}:已成功禁用。"
|
||||
"askToAddUserId" = "未找到您的配置!\r\n请向管理员询问,在您的配置中使用您的 Telegram 用户ID。\r\n\r\n您的用户ID:<b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "未找到您的配置!\r\n请向管理员询问,在您的配置中使用您的 Telegram 用户名或用户ID。\r\n\r\n您的用户名:<b>@{{ .TgUserName }}</b>\r\n\r\n您的用户ID:<b>{{ .TgUserID }}</b>"
|
||||
"askToAddUserName" = "未找到您的配置!\r\n请向管理员询问,在您的配置中使用您的 Telegram 用户名或用户ID。\r\n\r\n您的用户名:<b>@{{ .TgUserName }}</b>\r\n\r\n您的用户ID:<b>{{ .TgUserID }}</b>"
|
118
x-ui.sh
118
x-ui.sh
|
@ -54,10 +54,6 @@ elif [[ "${release}" == "debian" ]]; then
|
|||
if [[ ${os_version} -lt 10 ]]; then
|
||||
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "almalinux" ]]; then
|
||||
if [[ ${os_version} -lt 9 ]]; then
|
||||
echo -e "${red} Please use Almalinux 9 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "arch" ]]; then
|
||||
echo "Your OS is ArchLinux"
|
||||
elif [[ "${release}" == "manjaro" ]]; then
|
||||
|
@ -104,7 +100,7 @@ before_show_menu() {
|
|||
}
|
||||
|
||||
install() {
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/alirahimi818/3x-ui/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
if [[ $# == 0 ]]; then
|
||||
start
|
||||
|
@ -123,31 +119,13 @@ update() {
|
|||
fi
|
||||
return 0
|
||||
fi
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/alirahimi818/3x-ui/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
LOGI "Update is complete, Panel has automatically restarted "
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
custom_version() {
|
||||
echo "Enter the panel version (like 2.0.0):"
|
||||
read panel_version
|
||||
|
||||
if [ -z "$panel_version" ]; then
|
||||
echo "Panel version cannot be empty. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
download_link="https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh"
|
||||
|
||||
# Use the entered panel version in the download link
|
||||
install_command="bash <(curl -Ls $download_link) v$panel_version"
|
||||
|
||||
echo "Downloading and installing panel version $panel_version..."
|
||||
eval $install_command
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n"
|
||||
if [[ $? != 0 ]]; then
|
||||
|
@ -375,7 +353,7 @@ enable_bbr() {
|
|||
}
|
||||
|
||||
update_shell() {
|
||||
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh
|
||||
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/alirahimi818/3x-ui/raw/main/x-ui.sh
|
||||
if [[ $? != 0 ]]; then
|
||||
echo ""
|
||||
LOGE "Failed to download script, Please check whether the machine can connect Github"
|
||||
|
@ -1057,37 +1035,36 @@ show_menu() {
|
|||
${green}3X-ui Panel Management Script${plain}
|
||||
${green}0.${plain} Exit Script
|
||||
————————————————
|
||||
${green}1.${plain} Install
|
||||
${green}2.${plain} Update
|
||||
${green}3.${plain} Custom Version
|
||||
${green}4.${plain} Uninstall
|
||||
${green}1.${plain} Install x-ui
|
||||
${green}2.${plain} Update x-ui
|
||||
${green}3.${plain} Uninstall x-ui
|
||||
————————————————
|
||||
${green}5.${plain} Reset Username & Password & Secret Token
|
||||
${green}6.${plain} Reset Settings
|
||||
${green}7.${plain} Change Port
|
||||
${green}8.${plain} View Current Settings
|
||||
${green}4.${plain} Reset Username & Password & Secret Token
|
||||
${green}5.${plain} Reset Panel Settings
|
||||
${green}6.${plain} Change Panel Port
|
||||
${green}7.${plain} View Current Panel Settings
|
||||
————————————————
|
||||
${green}9.${plain} Start
|
||||
${green}10.${plain} Stop
|
||||
${green}11.${plain} Restart
|
||||
${green}12.${plain} Check Status
|
||||
${green}13.${plain} Check Logs
|
||||
${green}8.${plain} Start x-ui
|
||||
${green}9.${plain} Stop x-ui
|
||||
${green}10.${plain} Restart x-ui
|
||||
${green}11.${plain} Check x-ui Status
|
||||
${green}12.${plain} Check x-ui Logs
|
||||
————————————————
|
||||
${green}14.${plain} Enable x-ui On System Startup
|
||||
${green}15.${plain} Disable x-ui On System Startup
|
||||
${green}13.${plain} Enable x-ui On System Startup
|
||||
${green}14.${plain} Disable x-ui On System Startup
|
||||
————————————————
|
||||
${green}16.${plain} SSL Certificate Management
|
||||
${green}17.${plain} Cloudflare SSL Certificate
|
||||
${green}18.${plain} IP Limit Management
|
||||
${green}19.${plain} WARP Management
|
||||
${green}15.${plain} SSL Certificate Management
|
||||
${green}16.${plain} Cloudflare SSL Certificate
|
||||
${green}17.${plain} IP Limit Management
|
||||
${green}18.${plain} WARP Management
|
||||
————————————————
|
||||
${green}20.${plain} Enable BBR
|
||||
${green}21.${plain} Update Geo Files
|
||||
${green}22.${plain} Active Firewall and open ports
|
||||
${green}23.${plain} Speedtest by Ookla
|
||||
${green}19.${plain} Enable BBR
|
||||
${green}20.${plain} Update Geo Files
|
||||
${green}21.${plain} Active Firewall and open ports
|
||||
${green}22.${plain} Speedtest by Ookla
|
||||
"
|
||||
show_status
|
||||
echo && read -p "Please enter your selection [0-23]: " num
|
||||
echo && read -p "Please enter your selection [0-22]: " num
|
||||
|
||||
case "${num}" in
|
||||
0)
|
||||
|
@ -1100,70 +1077,67 @@ show_menu() {
|
|||
check_install && update
|
||||
;;
|
||||
3)
|
||||
check_install && custom_version
|
||||
;;
|
||||
4)
|
||||
check_install && uninstall
|
||||
;;
|
||||
5)
|
||||
4)
|
||||
check_install && reset_user
|
||||
;;
|
||||
6)
|
||||
5)
|
||||
check_install && reset_config
|
||||
;;
|
||||
7)
|
||||
6)
|
||||
check_install && set_port
|
||||
;;
|
||||
8)
|
||||
7)
|
||||
check_install && check_config
|
||||
;;
|
||||
9)
|
||||
8)
|
||||
check_install && start
|
||||
;;
|
||||
10)
|
||||
9)
|
||||
check_install && stop
|
||||
;;
|
||||
11)
|
||||
10)
|
||||
check_install && restart
|
||||
;;
|
||||
12)
|
||||
11)
|
||||
check_install && status
|
||||
;;
|
||||
13)
|
||||
12)
|
||||
check_install && show_log
|
||||
;;
|
||||
14)
|
||||
13)
|
||||
check_install && enable
|
||||
;;
|
||||
15)
|
||||
14)
|
||||
check_install && disable
|
||||
;;
|
||||
16)
|
||||
15)
|
||||
ssl_cert_issue_main
|
||||
;;
|
||||
17)
|
||||
16)
|
||||
ssl_cert_issue_CF
|
||||
;;
|
||||
18)
|
||||
17)
|
||||
iplimit_main
|
||||
;;
|
||||
19)
|
||||
18)
|
||||
warp_cloudflare
|
||||
;;
|
||||
20)
|
||||
19)
|
||||
enable_bbr
|
||||
;;
|
||||
21)
|
||||
20)
|
||||
update_geo
|
||||
;;
|
||||
22)
|
||||
21)
|
||||
open_ports
|
||||
;;
|
||||
23)
|
||||
22)
|
||||
run_speedtest
|
||||
;;
|
||||
*)
|
||||
LOGE "Please enter the correct number [0-23]"
|
||||
LOGE "Please enter the correct number [0-22]"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue