mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-04-19 21:42:24 +00:00
pagination and sub URI support #1300
This commit is contained in:
parent
549f230221
commit
5e47b4e949
14 changed files with 142 additions and 59 deletions
|
@ -56,44 +56,11 @@ func (a *SettingController) getAllSetting(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *SettingController) getDefaultSettings(c *gin.Context) {
|
func (a *SettingController) getDefaultSettings(c *gin.Context) {
|
||||||
type settingFunc func() (interface{}, error)
|
result, err := a.settingService.GetDefaultSettings(c.Request.Host)
|
||||||
|
|
||||||
settings := map[string]settingFunc{
|
|
||||||
"expireDiff": func() (interface{}, error) { return a.settingService.GetExpireDiff() },
|
|
||||||
"trafficDiff": func() (interface{}, error) { return a.settingService.GetTrafficDiff() },
|
|
||||||
"defaultCert": func() (interface{}, error) { return a.settingService.GetCertFile() },
|
|
||||||
"defaultKey": func() (interface{}, error) { return a.settingService.GetKeyFile() },
|
|
||||||
"tgBotEnable": func() (interface{}, error) { return a.settingService.GetTgbotenabled() },
|
|
||||||
"subEnable": func() (interface{}, error) { return a.settingService.GetSubEnable() },
|
|
||||||
"subPort": func() (interface{}, error) { return a.settingService.GetSubPort() },
|
|
||||||
"subPath": func() (interface{}, error) { return a.settingService.GetSubPath() },
|
|
||||||
"subDomain": func() (interface{}, error) { return a.settingService.GetSubDomain() },
|
|
||||||
"subKeyFile": func() (interface{}, error) { return a.settingService.GetSubKeyFile() },
|
|
||||||
"subCertFile": func() (interface{}, error) { return a.settingService.GetSubCertFile() },
|
|
||||||
"subEncrypt": func() (interface{}, error) { return a.settingService.GetSubEncrypt() },
|
|
||||||
"subShowInfo": func() (interface{}, error) { return a.settingService.GetSubShowInfo() },
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]interface{})
|
|
||||||
|
|
||||||
for key, fn := range settings {
|
|
||||||
value, err := fn()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
|
jsonMsg(c, I18nWeb(c, "pages.settings.toasts.getSettings"), err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
result[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
subTLS := false
|
|
||||||
if result["subKeyFile"] != "" || result["subCertFile"] != "" {
|
|
||||||
subTLS = true
|
|
||||||
}
|
|
||||||
result["subTLS"] = subTLS
|
|
||||||
|
|
||||||
delete(result, "subKeyFile")
|
|
||||||
delete(result, "subCertFile")
|
|
||||||
|
|
||||||
jsonObj(c, result, nil)
|
jsonObj(c, result, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ type AllSetting struct {
|
||||||
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
|
WebKeyFile string `json:"webKeyFile" form:"webKeyFile"`
|
||||||
WebBasePath string `json:"webBasePath" form:"webBasePath"`
|
WebBasePath string `json:"webBasePath" form:"webBasePath"`
|
||||||
SessionMaxAge int `json:"sessionMaxAge" form:"sessionMaxAge"`
|
SessionMaxAge int `json:"sessionMaxAge" form:"sessionMaxAge"`
|
||||||
|
PageSize int `json:"pageSize" form:"pageSize"`
|
||||||
ExpireDiff int `json:"expireDiff" form:"expireDiff"`
|
ExpireDiff int `json:"expireDiff" form:"expireDiff"`
|
||||||
TrafficDiff int `json:"trafficDiff" form:"trafficDiff"`
|
TrafficDiff int `json:"trafficDiff" form:"trafficDiff"`
|
||||||
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"`
|
TgBotEnable bool `json:"tgBotEnable" form:"tgBotEnable"`
|
||||||
|
@ -44,6 +45,7 @@ type AllSetting struct {
|
||||||
SubUpdates int `json:"subUpdates" form:"subUpdates"`
|
SubUpdates int `json:"subUpdates" form:"subUpdates"`
|
||||||
SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"`
|
SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"`
|
||||||
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"`
|
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"`
|
||||||
|
SubURI string `json:"subURI" form:"subURI"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AllSetting) CheckValid() error {
|
func (s *AllSetting) CheckValid() error {
|
||||||
|
@ -93,6 +95,12 @@ func (s *AllSetting) CheckValid() error {
|
||||||
if !strings.HasSuffix(s.WebBasePath, "/") {
|
if !strings.HasSuffix(s.WebBasePath, "/") {
|
||||||
s.WebBasePath += "/"
|
s.WebBasePath += "/"
|
||||||
}
|
}
|
||||||
|
if !strings.HasPrefix(s.SubPath, "/") {
|
||||||
|
s.SubPath = "/" + s.SubPath
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(s.SubPath, "/") {
|
||||||
|
s.SubPath += "/"
|
||||||
|
}
|
||||||
|
|
||||||
_, err := time.LoadLocation(s.TimeLocation)
|
_, err := time.LoadLocation(s.TimeLocation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -86,8 +86,7 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
genSubLink(subID) {
|
genSubLink(subID) {
|
||||||
const { domain: host, port, tls: isTLS, path: base } = app.subSettings;
|
return app.subSettings.subURI+subID+'?name='+subID;
|
||||||
return buildURL({ host, port, isTLS, base, path: subID+'?name='+remark });
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updated() {
|
updated() {
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :lg="24" :xl="12">
|
<a-col :lg="24" :xl="12">
|
||||||
<template v-if="type === 'text'">
|
<template v-if="type === 'text'">
|
||||||
<a-input :value="value" @input="$emit('input', $event.target.value)"></a-input>
|
<a-input :value="value" @input="$emit('input', $event.target.value)" :placeholder="placeholder"></a-input>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="type === 'number'">
|
<template v-else-if="type === 'number'">
|
||||||
<a-input-number :value="value" @change="value => $emit('input', value)" :min="min" style="width: 100%;"></a-input-number>
|
<a-input-number :value="value" :step="step" @change="value => $emit('input', value)" :min="min" style="width: 100%;"></a-input-number>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="type === 'switch'">
|
<template v-else-if="type === 'switch'">
|
||||||
<a-switch :checked="value" @change="value => $emit('input', value)"></a-switch>
|
<a-switch :checked="value" @change="value => $emit('input', value)"></a-switch>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
{{define "component/setting"}}
|
{{define "component/setting"}}
|
||||||
<script>
|
<script>
|
||||||
Vue.component('setting-list-item', {
|
Vue.component('setting-list-item', {
|
||||||
props: ["type", "title", "desc", "value", "min"],
|
props: ["type", "title", "desc", "value", "min", "step", "placeholder"],
|
||||||
template: `{{template "component/settingListItem"}}`,
|
template: `{{template "component/settingListItem"}}`,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -300,8 +300,7 @@
|
||||||
infoModal.visible = false;
|
infoModal.visible = false;
|
||||||
},
|
},
|
||||||
genSubLink(subID) {
|
genSubLink(subID) {
|
||||||
const { domain: host, port, tls: isTLS, path: base } = app.subSettings;
|
return app.subSettings.subURI+subID+'?name='+subID;
|
||||||
return buildURL({ host, port, isTLS, base, path: subID+'?name='+remark });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -173,14 +173,13 @@
|
||||||
<a-table :columns="isMobile ? mobileColums : columns" :row-key="dbInbound => dbInbound.id"
|
<a-table :columns="isMobile ? mobileColums : columns" :row-key="dbInbound => dbInbound.id"
|
||||||
:data-source="searchedInbounds"
|
:data-source="searchedInbounds"
|
||||||
:scroll="isMobile ? {} : { x: 1000 }"
|
:scroll="isMobile ? {} : { x: 1000 }"
|
||||||
:pagination="false"
|
:pagination=pagination(searchedInbounds)
|
||||||
:expand-icon-as-cell="false"
|
:expand-icon-as-cell="false"
|
||||||
:expand-row-by-click="false"
|
:expand-row-by-click="false"
|
||||||
:expand-icon-column-index="0"
|
:expand-icon-column-index="0"
|
||||||
:indent-size="0"
|
:indent-size="0"
|
||||||
:row-class-name="dbInbound => (dbInbound.isMultiUser() ? '' : 'hideExpandIcon')"
|
:row-class-name="dbInbound => (dbInbound.isMultiUser() ? '' : 'hideExpandIcon')"
|
||||||
style="margin-top: 10px"
|
style="margin-top: 10px">
|
||||||
@change="() => getDBInbounds()">
|
|
||||||
<template slot="action" slot-scope="text, dbInbound">
|
<template slot="action" slot-scope="text, dbInbound">
|
||||||
<a-icon type="edit" style="font-size: 22px" @click="openEditInbound(dbInbound.id);"></a-icon>
|
<a-icon type="edit" style="font-size: 22px" @click="openEditInbound(dbInbound.id);"></a-icon>
|
||||||
<a-dropdown :trigger="['click']">
|
<a-dropdown :trigger="['click']">
|
||||||
|
@ -416,7 +415,7 @@
|
||||||
:row-key="client => client.id"
|
:row-key="client => client.id"
|
||||||
:columns="isMobile ? innerMobileColumns : innerColumns"
|
:columns="isMobile ? innerMobileColumns : innerColumns"
|
||||||
:data-source="getInboundClients(record)"
|
:data-source="getInboundClients(record)"
|
||||||
:pagination="false"
|
:pagination=pagination(getInboundClients(record))
|
||||||
:style="isMobile ? 'margin: -16px -5px -17px;' : 'margin-left: 10px;'">
|
:style="isMobile ? 'margin: -16px -5px -17px;' : 'margin-left: 10px;'">
|
||||||
{{template "client_table"}}
|
{{template "client_table"}}
|
||||||
</a-table>
|
</a-table>
|
||||||
|
@ -547,12 +546,10 @@
|
||||||
refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000,
|
refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000,
|
||||||
subSettings: {
|
subSettings: {
|
||||||
enable : false,
|
enable : false,
|
||||||
port: 0,
|
subURI : ''
|
||||||
path: '',
|
|
||||||
domain: '',
|
|
||||||
tls: false
|
|
||||||
},
|
},
|
||||||
tgBotEnable: false,
|
tgBotEnable: false,
|
||||||
|
pageSize: 0,
|
||||||
isMobile: window.innerWidth <= 768,
|
isMobile: window.innerWidth <= 768,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -592,11 +589,9 @@
|
||||||
this.tgBotEnable = tgBotEnable;
|
this.tgBotEnable = tgBotEnable;
|
||||||
this.subSettings = {
|
this.subSettings = {
|
||||||
enable : subEnable,
|
enable : subEnable,
|
||||||
port: subPort,
|
subURI: subURI
|
||||||
path: subPath,
|
|
||||||
domain: subDomain,
|
|
||||||
tls: subTLS
|
|
||||||
};
|
};
|
||||||
|
this.pageSize = pageSize;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setInbounds(dbInbounds) {
|
setInbounds(dbInbounds) {
|
||||||
|
@ -1216,6 +1211,27 @@
|
||||||
this.spinning = false;
|
this.spinning = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
pagination(obj){
|
||||||
|
if (this.pageSize > 0 && obj.length>this.pageSize) {
|
||||||
|
// Set page options based on object size
|
||||||
|
sizeOptions = []
|
||||||
|
for (i=this.pageSize;i<=obj.length;i=i+this.pageSize) {
|
||||||
|
sizeOptions.push(i.toString());
|
||||||
|
}
|
||||||
|
// Add option to see all in one page
|
||||||
|
sizeOptions.push(i.toString());
|
||||||
|
|
||||||
|
p = {
|
||||||
|
showSizeChanger: true,
|
||||||
|
size: 'small',
|
||||||
|
position: 'bottom',
|
||||||
|
pageSize: this.pageSize,
|
||||||
|
pageSizeOptions: sizeOptions
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
onResize() {
|
onResize() {
|
||||||
this.isMobile = window.innerWidth <= 768;
|
this.isMobile = window.innerWidth <= 768;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,7 @@
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.privateKeyPath"}}' desc='{{ i18n "pages.settings.privateKeyPathDesc"}}' v-model="allSetting.webKeyFile"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.panelUrlPath"}}' desc='{{ i18n "pages.settings.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.panelUrlPath"}}' desc='{{ i18n "pages.settings.panelUrlPathDesc"}}' v-model="allSetting.webBasePath"></setting-list-item>
|
||||||
<setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="0"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.settings.sessionMaxAge" }}' desc='{{ i18n "pages.settings.sessionMaxAgeDesc" }}' v-model="allSetting.sessionMaxAge" :min="0"></setting-list-item>
|
||||||
|
<setting-list-item type="number" title='{{ i18n "pages.settings.pageSize" }}' desc='{{ i18n "pages.settings.pageSizeDesc" }}' v-model="allSetting.pageSize" :min="0" :step="5"></setting-list-item>
|
||||||
<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.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="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>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.timeZone"}}' desc='{{ i18n "pages.settings.timeZoneDesc"}}' v-model="allSetting.timeLocation"></setting-list-item>
|
||||||
|
@ -243,6 +244,7 @@
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subPath"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subPath"}}' desc='{{ i18n "pages.settings.subPathDesc"}}' v-model="allSetting.subPath"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.subCertPath"}}' desc='{{ i18n "pages.settings.subCertPathDesc"}}' v-model="allSetting.subCertFile"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subCertPath"}}' desc='{{ i18n "pages.settings.subCertPathDesc"}}' v-model="allSetting.subCertFile"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.subKeyPath"}}' desc='{{ i18n "pages.settings.subKeyPathDesc"}}' v-model="allSetting.subKeyFile"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subKeyPath"}}' desc='{{ i18n "pages.settings.subKeyPathDesc"}}' v-model="allSetting.subKeyFile"></setting-list-item>
|
||||||
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subURI"}}' desc='{{ i18n "pages.settings.subURIDesc"}}' v-model="allSetting.subURI" placeholder="(http|https)://domain[:port]/path/"></setting-list-item>
|
||||||
<setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.settings.subUpdates"}}' desc='{{ i18n "pages.settings.subUpdatesDesc"}}' v-model="allSetting.subUpdates"></setting-list-item>
|
||||||
</a-list>
|
</a-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
|
|
@ -31,6 +31,7 @@ var defaultValueMap = map[string]string{
|
||||||
"secret": random.Seq(32),
|
"secret": random.Seq(32),
|
||||||
"webBasePath": "/",
|
"webBasePath": "/",
|
||||||
"sessionMaxAge": "0",
|
"sessionMaxAge": "0",
|
||||||
|
"pageSize": "0",
|
||||||
"expireDiff": "0",
|
"expireDiff": "0",
|
||||||
"trafficDiff": "0",
|
"trafficDiff": "0",
|
||||||
"timeLocation": "Asia/Tehran",
|
"timeLocation": "Asia/Tehran",
|
||||||
|
@ -53,6 +54,7 @@ var defaultValueMap = map[string]string{
|
||||||
"subUpdates": "12",
|
"subUpdates": "12",
|
||||||
"subEncrypt": "true",
|
"subEncrypt": "true",
|
||||||
"subShowInfo": "true",
|
"subShowInfo": "true",
|
||||||
|
"subURI": "",
|
||||||
}
|
}
|
||||||
|
|
||||||
type SettingService struct {
|
type SettingService struct {
|
||||||
|
@ -406,6 +408,14 @@ func (s *SettingService) GetSubShowInfo() (bool, error) {
|
||||||
return s.getBool("subShowInfo")
|
return s.getBool("subShowInfo")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetSubURI() (string, error) {
|
||||||
|
return s.getString("subURI")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetPageSize() (int, error) {
|
||||||
|
return s.getInt("pageSize")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
|
func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {
|
||||||
if err := allSetting.CheckValid(); err != nil {
|
if err := allSetting.CheckValid(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -435,3 +445,61 @@ func (s *SettingService) GetDefaultXrayConfig() (interface{}, error) {
|
||||||
}
|
}
|
||||||
return jsonData, nil
|
return jsonData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
||||||
|
type settingFunc func() (interface{}, error)
|
||||||
|
settings := map[string]settingFunc{
|
||||||
|
"expireDiff": func() (interface{}, error) { return s.GetExpireDiff() },
|
||||||
|
"trafficDiff": func() (interface{}, error) { return s.GetTrafficDiff() },
|
||||||
|
"pageSize": func() (interface{}, error) { return s.GetPageSize() },
|
||||||
|
"defaultCert": func() (interface{}, error) { return s.GetCertFile() },
|
||||||
|
"defaultKey": func() (interface{}, error) { return s.GetKeyFile() },
|
||||||
|
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotenabled() },
|
||||||
|
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
||||||
|
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
|
||||||
|
for key, fn := range settings {
|
||||||
|
value, err := fn()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
result[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
if result["subEnable"].(bool) && result["subURI"].(string) == "" {
|
||||||
|
subURI := ""
|
||||||
|
subPort, _ := s.GetSubPort()
|
||||||
|
subPath, _ := s.GetSubPath()
|
||||||
|
subDomain, _ := s.GetSubDomain()
|
||||||
|
subKeyFile, _ := s.GetSubKeyFile()
|
||||||
|
subCertFile, _ := s.GetSubCertFile()
|
||||||
|
subTLS := false
|
||||||
|
if subKeyFile != "" && subCertFile != "" {
|
||||||
|
subTLS = true
|
||||||
|
}
|
||||||
|
if subDomain == "" {
|
||||||
|
subDomain = strings.Split(host, ":")[0]
|
||||||
|
}
|
||||||
|
if subTLS {
|
||||||
|
subURI = "https://"
|
||||||
|
} else {
|
||||||
|
subURI = "http://"
|
||||||
|
}
|
||||||
|
if (subPort == 443 && subTLS) || (subPort == 80 && !subTLS) {
|
||||||
|
subURI += subDomain
|
||||||
|
} else {
|
||||||
|
subURI += fmt.Sprintf("%s:%d", subDomain, subPort)
|
||||||
|
}
|
||||||
|
if subPath[0] == byte('/') {
|
||||||
|
subURI += subPath
|
||||||
|
} else {
|
||||||
|
subURI += "/" + subPath
|
||||||
|
}
|
||||||
|
result["subURI"] = subURI
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "Fill in an absolute path starting with."
|
"privateKeyPathDesc" = "Fill in an absolute path starting with."
|
||||||
"panelUrlPath" = "Panel URL Root Path"
|
"panelUrlPath" = "Panel URL Root Path"
|
||||||
"panelUrlPathDesc" = "Must start with '/' and end with."
|
"panelUrlPathDesc" = "Must start with '/' and end with."
|
||||||
|
"pageSize" = "Pagination size"
|
||||||
|
"pageSizeDesc" = "Define page size for inbounds table. Set 0 to disable"
|
||||||
"oldUsername" = "Current Username"
|
"oldUsername" = "Current Username"
|
||||||
"currentPassword" = "Current Password"
|
"currentPassword" = "Current Password"
|
||||||
"newUsername" = "New Username"
|
"newUsername" = "New Username"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "Encrypt the returned configs in subscription"
|
"subEncryptDesc" = "Encrypt the returned configs in subscription"
|
||||||
"subShowInfo" = "Show usage info"
|
"subShowInfo" = "Show usage info"
|
||||||
"subShowInfoDesc" = "Show remianed traffic and date after config name"
|
"subShowInfoDesc" = "Show remianed traffic and date after config name"
|
||||||
|
"subURI" = "Reverse Proxy URI"
|
||||||
|
"subURIDesc" = "Change base URI of subscription URL for using on behind of proxies"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Xray Settings"
|
"title" = "Xray Settings"
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "Complete con una ruta absoluta que comience con."
|
"privateKeyPathDesc" = "Complete con una ruta absoluta que comience con."
|
||||||
"panelUrlPath" = "Ruta Raíz de la URL del Panel"
|
"panelUrlPath" = "Ruta Raíz de la URL del Panel"
|
||||||
"panelUrlPathDesc" = "Debe empezar con '/' y terminar con."
|
"panelUrlPathDesc" = "Debe empezar con '/' y terminar con."
|
||||||
|
"pageSize" = "Tamaño de paginación"
|
||||||
|
"pageSizeDesc" = "Defina el tamaño de página para la tabla de entradas. Establezca 0 para desactivar"
|
||||||
"oldUsername" = "Nombre de Usuario Actual"
|
"oldUsername" = "Nombre de Usuario Actual"
|
||||||
"currentPassword" = "Contraseña Actual"
|
"currentPassword" = "Contraseña Actual"
|
||||||
"newUsername" = "Nuevo Nombre de Usuario"
|
"newUsername" = "Nuevo Nombre de Usuario"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "Encriptar las configuraciones devueltas en la suscripción."
|
"subEncryptDesc" = "Encriptar las configuraciones devueltas en la suscripción."
|
||||||
"subShowInfo" = "Mostrar información de uso"
|
"subShowInfo" = "Mostrar información de uso"
|
||||||
"subShowInfoDesc" = "Mostrar tráfico restante y fecha después del nombre de configuración."
|
"subShowInfoDesc" = "Mostrar tráfico restante y fecha después del nombre de configuración."
|
||||||
|
"subURI" = "URI de proxy inverso"
|
||||||
|
"subURIDesc" = "Cambiar el URI base de la URL de suscripción para usar detrás de los servidores proxy"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Xray Configuración"
|
"title" = "Xray Configuración"
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "باید یک مسیر مطلق باشد که با / شروع می شود "
|
"privateKeyPathDesc" = "باید یک مسیر مطلق باشد که با / شروع می شود "
|
||||||
"panelUrlPath" = "آدرس روت پنل"
|
"panelUrlPath" = "آدرس روت پنل"
|
||||||
"panelUrlPathDesc" = "باید با '/' شروع شود و با '/' تمام شود"
|
"panelUrlPathDesc" = "باید با '/' شروع شود و با '/' تمام شود"
|
||||||
|
"pageSize" = "اندازه صفحه بندی جدول"
|
||||||
|
"pageSizeDesc" = "اندازه صفحه را برای جدول سرویس ها تعریف کنید. 0: غیرفعال"
|
||||||
"oldUsername" = "نام کاربری فعلی"
|
"oldUsername" = "نام کاربری فعلی"
|
||||||
"currentPassword" = "رمز عبور فعلی"
|
"currentPassword" = "رمز عبور فعلی"
|
||||||
"newUsername" = "نام کاربری جدید"
|
"newUsername" = "نام کاربری جدید"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "رمزگذاری کانفیگ های بازگشتی سابسکریپشن"
|
"subEncryptDesc" = "رمزگذاری کانفیگ های بازگشتی سابسکریپشن"
|
||||||
"subShowInfo" = "نمایش اطلاعات مصرف"
|
"subShowInfo" = "نمایش اطلاعات مصرف"
|
||||||
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در هر کانفیگ نمایش میدهد"
|
"subShowInfoDesc" = "ترافیک و زمان باقیمانده را در هر کانفیگ نمایش میدهد"
|
||||||
|
"subURI" = "آدرس پایه پروکسی معکوس"
|
||||||
|
"subURIDesc" = "آدرس پایه سابسکریپشن را برای استفاده در پشت پراکسی ها تغییر میدهد"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "الگوها"
|
"title" = "الگوها"
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "Введите полный путь, начинающийся с"
|
"privateKeyPathDesc" = "Введите полный путь, начинающийся с"
|
||||||
"panelUrlPath" = "Корневой путь URL адреса панели"
|
"panelUrlPath" = "Корневой путь URL адреса панели"
|
||||||
"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на"
|
"panelUrlPathDesc" = "Должен начинаться с '/' и заканчиваться на"
|
||||||
|
"pageSize" = "Размер нумерации страниц"
|
||||||
|
"pageSizeDesc" = "Определить размер страницы для входящей таблицы. Установите 0, чтобы отключить"
|
||||||
"oldUsername" = "Текущее имя пользователя"
|
"oldUsername" = "Текущее имя пользователя"
|
||||||
"currentPassword" = "Текущий пароль"
|
"currentPassword" = "Текущий пароль"
|
||||||
"newUsername" = "Новое имя пользователя"
|
"newUsername" = "Новое имя пользователя"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "Шифровать возвращенные конфиги в подписке"
|
"subEncryptDesc" = "Шифровать возвращенные конфиги в подписке"
|
||||||
"subShowInfo" = "Показать информацию об использовании"
|
"subShowInfo" = "Показать информацию об использовании"
|
||||||
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
|
"subShowInfoDesc" = "Показывать восстановленный трафик и дату после имени конфигурации"
|
||||||
|
"subURI" = "URI обратного прокси"
|
||||||
|
"subURIDesc" = "Изменить базовый URI URL-адреса подписки для использования за прокси-серверами"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Xray Настройки"
|
"title" = "Xray Настройки"
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với."
|
"privateKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với."
|
||||||
"panelUrlPath" = "Đường dẫn gốc URL Bảng điều khiển"
|
"panelUrlPath" = "Đường dẫn gốc URL Bảng điều khiển"
|
||||||
"panelUrlPathDesc" = "Phải bắt đầu bằng '/' và kết thúc bằng."
|
"panelUrlPathDesc" = "Phải bắt đầu bằng '/' và kết thúc bằng."
|
||||||
|
"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"
|
||||||
"oldUsername" = "Tên người dùng hiện tại"
|
"oldUsername" = "Tên người dùng hiện tại"
|
||||||
"currentPassword" = "Mật khẩu hiện tại"
|
"currentPassword" = "Mật khẩu hiện tại"
|
||||||
"newUsername" = "Tên người dùng mới"
|
"newUsername" = "Tên người dùng mới"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "Mã hóa các cấu hình được trả về trong đăng ký"
|
"subEncryptDesc" = "Mã hóa các cấu hình được trả về trong đăng ký"
|
||||||
"subShowInfo" = "Hiển thị thông tin sử dụng"
|
"subShowInfo" = "Hiển thị thông tin sử dụng"
|
||||||
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
||||||
|
"subURI" = "URI proxy ngược"
|
||||||
|
"subURIDesc" = "Thay đổi URI cơ sở của URL đăng ký để sử dụng ở phía sau proxy"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Xray Cài đặt"
|
"title" = "Xray Cài đặt"
|
||||||
|
|
|
@ -238,6 +238,8 @@
|
||||||
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
|
"privateKeyPathDesc" = "填写一个 '/' 开头的绝对路径"
|
||||||
"panelUrlPath" = "面板 url 根路径"
|
"panelUrlPath" = "面板 url 根路径"
|
||||||
"panelUrlPathDesc" = "必须以 '/' 开头,以 '/' 结尾"
|
"panelUrlPathDesc" = "必须以 '/' 开头,以 '/' 结尾"
|
||||||
|
"pageSize" = "分页大小"
|
||||||
|
"pageSizeDesc" = "定义入站表的页面大小。设置 0 表示禁用"
|
||||||
"oldUsername" = "原用户名"
|
"oldUsername" = "原用户名"
|
||||||
"currentPassword" = "原密码"
|
"currentPassword" = "原密码"
|
||||||
"newUsername" = "新用户名"
|
"newUsername" = "新用户名"
|
||||||
|
@ -285,6 +287,8 @@
|
||||||
"subEncryptDesc" = "在订阅中加密返回的配置"
|
"subEncryptDesc" = "在订阅中加密返回的配置"
|
||||||
"subShowInfo" = "显示使用信息"
|
"subShowInfo" = "显示使用信息"
|
||||||
"subShowInfoDesc" = "在配置名称后显示剩余流量和日期"
|
"subShowInfoDesc" = "在配置名称后显示剩余流量和日期"
|
||||||
|
"subURI" = "反向代理 URI"
|
||||||
|
"subURIDesc" = "更改订阅 URL 的基本 URI 以在代理后面使用"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Xray 设置"
|
"title" = "Xray 设置"
|
||||||
|
|
Loading…
Reference in a new issue