diff --git a/docker-compose.yml b/docker-compose.yml index 2e57169f..978fa2fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,16 @@ -version: '3.9' +--- +version: "3.9" + services: xui: image: alireza7/x-ui container_name: x-ui + hostname: yourhostname volumes: - $PWD/db/:/etc/x-ui/ - $PWD/cert/:/root/cert/ + environment: + XRAY_VMESS_AEAD_FORCED: "false" + tty: true + network_mode: host restart: unless-stopped - ports: - - 54321:54321 - - 443:443 diff --git a/web/assets/css/custom.css b/web/assets/css/custom.css index 99461563..7773f36d 100644 --- a/web/assets/css/custom.css +++ b/web/assets/css/custom.css @@ -1,5 +1,23 @@ -#app { +html, +body { height: 100vh; + width: 100vw; + margin: 0; + padding: 0; + overflow: hidden; +} + +#app { + height: 100%; + min-height: 100vh; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: 0; + padding: 0; + overflow: auto; } .ant-space { @@ -10,6 +28,12 @@ display: none; } +@media (max-width: 768px) { + .ant-layout-sider { + display: none; + } +} + .ant-card { border-radius: 30px; } @@ -216,6 +240,7 @@ .ant-card-dark .ant-input-group-addon { color: hsla(0,0%,100%,.65); background-color: #262f3d; + border: 1px solid rgb(0 150 112 / 0%); } .ant-card-dark .ant-list-item-meta-title, @@ -253,6 +278,10 @@ background-color: #1a212a; } +.ant-input-number { + min-width: 100px; +} + .ant-card-dark .ant-input, .ant-card-dark .ant-input-number, .ant-card-dark .ant-input-number-handler-wrap, @@ -262,6 +291,7 @@ .ant-card-dark .ant-calendar-picker-clear { color: hsla(0,0%,100%,.65); background-color: #193752; + border: 1px solid rgba(0, 65, 150, 0); } .ant-card-dark .ant-select-disabled .ant-select-selection { diff --git a/web/assets/js/axios-init.js b/web/assets/js/axios-init.js index bd55c3cf..b864b714 100644 --- a/web/assets/js/axios-init.js +++ b/web/assets/js/axios-init.js @@ -2,7 +2,7 @@ axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; axios.interceptors.request.use( - config => { + (config) => { if (config.data instanceof FormData) { config.headers['Content-Type'] = 'multipart/form-data'; } else { @@ -12,5 +12,5 @@ axios.interceptors.request.use( } return config; }, - error => Promise.reject(error) + (error) => Promise.reject(error), ); diff --git a/web/assets/js/util/common.js b/web/assets/js/util/common.js index f411148b..43bf77ef 100644 --- a/web/assets/js/util/common.js +++ b/web/assets/js/util/common.js @@ -69,48 +69,48 @@ function debounce(fn, delay) { } function getCookie(cname) { - let name = cname + '='; + let name = cname + "="; let decodedCookie = decodeURIComponent(document.cookie); - let ca = decodedCookie.split(';'); + let ca = decodedCookie.split(";"); for (let i = 0; i < ca.length; i++) { let c = ca[i]; - while (c.charAt(0) == ' ') { + while (c.charAt(0) == " ") { c = c.substring(1); } if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } } - return ''; + return ""; } function setCookie(cname, cvalue, exdays) { const d = new Date(); d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000); - let expires = 'expires=' + d.toUTCString(); - document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/'; + let expires = "expires=" + d.toUTCString(); + document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/"; } function usageColor(data, threshold, total) { switch (true) { case data === null: - return 'blue'; + return "blue"; case total <= 0: - return 'blue'; + return "blue"; case data < total - threshold: - return 'cyan'; + return "cyan"; case data < total: - return 'orange'; + return "orange"; default: - return 'red'; + return "red"; } } -function areAllItemsExist(array1, array2) { +function doAllItemsExist(array1, array2) { for (let i = 0; i < array1.length; i++) { - if (!array2.includes(array1[i])) { - return false; - } + if (!array2.includes(array1[i])) { + return false; + } } return true; - } \ No newline at end of file +} diff --git a/web/assets/js/util/date-util.js b/web/assets/js/util/date-util.js index e451df32..b330ccbd 100644 --- a/web/assets/js/util/date-util.js +++ b/web/assets/js/util/date-util.js @@ -128,7 +128,6 @@ Date.prototype.formatDateTime = function (split = ' ') { }; class DateUtil { - // String string to date object static parseDate(str) { return new Date(str.replace(/-/g, '/')); @@ -144,4 +143,4 @@ class DateUtil { date.setMinTime(); return date; } -} \ No newline at end of file +} diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js index a6dd9dd4..b56207ab 100644 --- a/web/assets/js/util/utils.js +++ b/web/assets/js/util/utils.js @@ -144,7 +144,7 @@ class RandomUtil { return string; } - static randomShadowsocksPassword(){ + static randomShadowsocksPassword() { let array = new Uint8Array(32); window.crypto.getRandomValues(array); return btoa(String.fromCharCode.apply(null, array)); @@ -299,4 +299,4 @@ class ObjectUtil { } return true; } -} \ No newline at end of file +} diff --git a/web/controller/setting.go b/web/controller/setting.go index 10129d17..623a34ce 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -43,7 +43,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) { func (a *SettingController) getAllSetting(c *gin.Context) { allSetting, err := a.settingService.GetAllSetting() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } jsonObj(c, allSetting, nil) @@ -52,22 +52,22 @@ func (a *SettingController) getAllSetting(c *gin.Context) { func (a *SettingController) getDefaultSettings(c *gin.Context) { expireDiff, err := a.settingService.GetExpireDiff() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } trafficDiff, err := a.settingService.GetTrafficDiff() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } defaultCert, err := a.settingService.GetCertFile() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } defaultKey, err := a.settingService.GetKeyFile() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } result := map[string]interface{}{ @@ -83,18 +83,18 @@ func (a *SettingController) updateSetting(c *gin.Context) { allSetting := &entity.AllSetting{} err := c.ShouldBind(allSetting) if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.modifySetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err) return } err = a.settingService.UpdateAllSetting(allSetting) - jsonMsg(c, I18n(c, "pages.settings.toasts.modifySetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err) } func (a *SettingController) updateUser(c *gin.Context) { form := &updateUserForm{} err := c.ShouldBind(form) if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.modifySetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.modifySettings"), err) return } user := session.GetLoginUser(c) @@ -123,7 +123,7 @@ func (a *SettingController) restartPanel(c *gin.Context) { func (a *SettingController) getDefaultXrayConfig(c *gin.Context) { defaultJsonConfig, err := a.settingService.GetDefaultXrayConfig() if err != nil { - jsonMsg(c, I18n(c, "pages.settings.toasts.getSetting"), err) + jsonMsg(c, I18n(c, "pages.settings.toasts.getSettings"), err) return } jsonObj(c, defaultJsonConfig, nil) diff --git a/web/controller/xui.go b/web/controller/xui.go index fc3ca5f8..1844181d 100644 --- a/web/controller/xui.go +++ b/web/controller/xui.go @@ -23,7 +23,7 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) { g.GET("/", a.index) g.GET("/inbounds", a.inbounds) - g.GET("/setting", a.setting) + g.GET("/settings", a.settings) a.inboundController = NewInboundController(g) a.settingController = NewSettingController(g) @@ -37,6 +37,6 @@ func (a *XUIController) inbounds(c *gin.Context) { html(c, "inbounds.html", "pages.inbounds.title", nil) } -func (a *XUIController) setting(c *gin.Context) { - html(c, "setting.html", "pages.settings.title", nil) +func (a *XUIController) settings(c *gin.Context) { + html(c, "settings.html", "pages.settings.title", nil) } diff --git a/web/html/common/prompt_modal.html b/web/html/common/prompt_modal.html index 6b64bc95..23bdca64 100644 --- a/web/html/common/prompt_modal.html +++ b/web/html/common/prompt_modal.html @@ -36,11 +36,11 @@ }, confirm() {}, open({ - title='', - type='text', - value='', - okText='{{ i18n "sure"}}', - confirm=() => {}, + title = '', + type = 'text', + value = '', + okText = '{{ i18n "sure"}}', + confirm = () => {}, }) { this.title = title; this.type = type; diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 06ca07a8..76ab7b41 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -23,7 +23,7 @@ qrcode: null, clipboard: null, visible: false, - show: function (title='', content='', dbInbound=new DBInbound(), copyText='', clientName = null) { + show: function (title = '', content = '', dbInbound = new DBInbound(), copyText = '', clientName = null) { this.title = title; this.content = content; this.dbInbound = dbInbound; diff --git a/web/html/common/text_modal.html b/web/html/common/text_modal.html index 649f73dd..1514051b 100644 --- a/web/html/common/text_modal.html +++ b/web/html/common/text_modal.html @@ -21,7 +21,7 @@ qrcode: null, clipboard: null, visible: false, - show: function (title='', content='', fileName='') { + show: function (title = '', content = '', fileName = '') { this.title = title; this.content = content; this.fileName = fileName; diff --git a/web/html/login.html b/web/html/login.html index b98059e2..b040b0fc 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -50,7 +50,7 @@ -

{{ i18n "pages.login.title" }}

+

{{ i18n "pages.login.title" }}

@@ -63,10 +63,9 @@ - - - + + @@ -101,6 +100,7 @@ {{template "js" .}} {{template "component/themeSwitcher" .}} +{{template "component/password" .}} +{{end}} \ No newline at end of file diff --git a/web/html/xui/form/protocol/shadowsocks.html b/web/html/xui/form/protocol/shadowsocks.html index 58becb5a..fdf2f93c 100644 --- a/web/html/xui/form/protocol/shadowsocks.html +++ b/web/html/xui/form/protocol/shadowsocks.html @@ -1,7 +1,7 @@ {{define "form/shadowsocks"}} - +
@@ -47,7 +47,7 @@
- {{ i18n "pages.inbounds.totalFlow" }}(GB) + {{ i18n "pages.inbounds.totalFlow" }} (GB)