mirror of
				https://github.com/MHSanaei/3x-ui.git
				synced 2025-10-31 04:12:51 +00:00 
			
		
		
		
	Merge pull request #381 from hamid-gh98/main
[FIX] bug logout path + [UPDATE] login UI and more ...
This commit is contained in:
		
						commit
						30a5f66f26
					
				
					 37 changed files with 1348 additions and 1208 deletions
				
			
		
							
								
								
									
										2
									
								
								web/assets/ant-design-vue@1.7.2/antd.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								web/assets/ant-design-vue@1.7.2/antd.min.css
									
									
									
									
										vendored
									
									
								
							|  | @ -992,7 +992,7 @@ to{transform:scale(0) translate(50%,-50%);opacity:0} | ||||||
| .ant-menu-item>.ant-badge>a{color:rgba(0,0,0,.65)} | .ant-menu-item>.ant-badge>a{color:rgba(0,0,0,.65)} | ||||||
| .ant-menu-item>.ant-badge>a:hover{color:#1890ff} | .ant-menu-item>.ant-badge>a:hover{color:#1890ff} | ||||||
| .ant-menu-item-divider{height:1px;overflow:hidden;line-height:0;background-color:#e8e8e8} | .ant-menu-item-divider{height:1px;overflow:hidden;line-height:0;background-color:#e8e8e8} | ||||||
| .ant-menu-item-active,.ant-menu-item:hover,.ant-menu-submenu-active,.ant-menu-submenu-title:hover,.ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open{color:#fff;background-image: linear-gradient(90deg,#99999980 0,#8888889e 100%);border-radius: 0.5rem} | .ant-menu-item-active,.ant-menu-item:hover,.ant-menu-submenu-active,.ant-menu-submenu-title:hover,.ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open{color:#2d2d2d;background-image: linear-gradient(90deg,#99999980 0,#8888889e 100%);border-radius: 0.5rem} | ||||||
| .ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px} | .ant-menu-horizontal .ant-menu-item,.ant-menu-horizontal .ant-menu-submenu{margin-top:-1px} | ||||||
| .ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent} | .ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu .ant-menu-submenu-title:hover{background-color:transparent} | ||||||
| .ant-menu-item-selected,.ant-menu-item-selected>a,.ant-menu-item-selected>a:hover{color:#1890ff} | .ant-menu-item-selected,.ant-menu-item-selected>a,.ant-menu-item-selected>a:hover{color:#1890ff} | ||||||
|  |  | ||||||
|  | @ -1,5 +1,23 @@ | ||||||
| #app { | html, | ||||||
|  | body { | ||||||
|     height: 100vh; |     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 { | .ant-space { | ||||||
|  | @ -180,12 +198,12 @@ | ||||||
| 
 | 
 | ||||||
| .ant-card-dark:hover { | .ant-card-dark:hover { | ||||||
|     border-color: #e8e8e8; |     border-color: #e8e8e8; | ||||||
|     box-shadow: 0 1px 10px -1px rgb(154 175 238); |     box-shadow: 0 1px 10px -1px rgb(76, 88, 126); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .ant-card-bordered:hover { | /* .ant-card-bordered:hover { | ||||||
|     /*box-shadow: 0 3px 12px -0.8px #0000005c;*/ |     box-shadow: 0 3px 12px -0.8px #0000005c; | ||||||
| } | } */ | ||||||
| 
 | 
 | ||||||
| .ant-card-dark .ant-table-thead th { | .ant-card-dark .ant-table-thead th { | ||||||
|     color: hsla(0,0%,100%,.65); |     color: hsla(0,0%,100%,.65); | ||||||
|  | @ -203,6 +221,7 @@ | ||||||
| .ant-card-dark .ant-input-group-addon { | .ant-card-dark .ant-input-group-addon { | ||||||
|     color: hsla(0,0%,100%,.65); |     color: hsla(0,0%,100%,.65); | ||||||
|     background-color: #262f3d; |     background-color: #262f3d; | ||||||
|  |     border: 1px solid rgb(0 150 112 / 0%); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .ant-card-dark .ant-list-item-meta-title, | .ant-card-dark .ant-list-item-meta-title, | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded | ||||||
| axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; | axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; | ||||||
| 
 | 
 | ||||||
| axios.interceptors.request.use( | axios.interceptors.request.use( | ||||||
|     config => { |     (config) => { | ||||||
|         if (config.data instanceof FormData) { |         if (config.data instanceof FormData) { | ||||||
|             config.headers['Content-Type'] = 'multipart/form-data'; |             config.headers['Content-Type'] = 'multipart/form-data'; | ||||||
|         } else { |         } else { | ||||||
|  | @ -12,5 +12,5 @@ axios.interceptors.request.use( | ||||||
|         } |         } | ||||||
|         return config; |         return config; | ||||||
|     }, |     }, | ||||||
|     error => Promise.reject(error) |     (error) => Promise.reject(error), | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | @ -1,41 +1,41 @@ | ||||||
| const supportLangs = [ | const supportLangs = [ | ||||||
|     { |     { | ||||||
|        name : "English", |         name: 'English', | ||||||
|        value : "en-US", |         value: 'en-US', | ||||||
|        icon : "🇺🇸" |         icon: '🇺🇸', | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         name : "Farsi", |         name: 'Farsi', | ||||||
|         value : "fa_IR", |         value: 'fa_IR', | ||||||
|         icon : "🇮🇷" |         icon: '🇮🇷', | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         name : "汉语", |         name: '汉语', | ||||||
|         value : "zh-Hans", |         value: 'zh-Hans', | ||||||
|         icon : "🇨🇳" |         icon: '🇨🇳', | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         name : "Russian", |         name: 'Russian', | ||||||
|         value : "ru_RU", |         value: 'ru_RU', | ||||||
|         icon : "🇷🇺" |         icon: '🇷🇺', | ||||||
|     }, |     }, | ||||||
| ] | ]; | ||||||
| 
 | 
 | ||||||
| function getLang() { | function getLang() { | ||||||
|     let lang = getCookie('lang') |     let lang = getCookie('lang'); | ||||||
| 
 | 
 | ||||||
|     if (!lang) { |     if (!lang) { | ||||||
|         if (window.navigator) { |         if (window.navigator) { | ||||||
|             lang = window.navigator.language || window.navigator.userLanguage; |             lang = window.navigator.language || window.navigator.userLanguage; | ||||||
| 
 | 
 | ||||||
|             if (isSupportLang(lang)) { |             if (isSupportLang(lang)) { | ||||||
|                 setCookie('lang' , lang , 150) |                 setCookie('lang', lang, 150); | ||||||
|             } else { |             } else { | ||||||
|                 setCookie('lang' , 'en-US' , 150) |                 setCookie('lang', 'en-US', 150); | ||||||
|                 window.location.reload(); |                 window.location.reload(); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             setCookie('lang' , 'en-US' , 150) |             setCookie('lang', 'en-US', 150); | ||||||
|             window.location.reload(); |             window.location.reload(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -44,12 +44,11 @@ function getLang(){ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function setLang(lang) { | function setLang(lang) { | ||||||
| 
 |  | ||||||
|     if (!isSupportLang(lang)) { |     if (!isSupportLang(lang)) { | ||||||
|         lang = 'en-US'; |         lang = 'en-US'; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     setCookie('lang' , lang , 150) |     setCookie('lang', lang, 150); | ||||||
|     window.location.reload(); |     window.location.reload(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -62,28 +61,3 @@ function isSupportLang(lang){ | ||||||
| 
 | 
 | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function getCookie(cname) { |  | ||||||
|     let name = cname + "="; |  | ||||||
|     let decodedCookie = decodeURIComponent(document.cookie); |  | ||||||
|     let ca = decodedCookie.split(';'); |  | ||||||
|     for(let i = 0; i <ca.length; i++) { |  | ||||||
|         let c = ca[i]; |  | ||||||
|         while (c.charAt(0) == ' ') { |  | ||||||
|             c = c.substring(1); |  | ||||||
|         } |  | ||||||
|         if (c.indexOf(name) == 0) { |  | ||||||
|             return c.substring(name.length, c.length); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     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=/"; |  | ||||||
| } |  | ||||||
|  | @ -57,13 +57,36 @@ function toFixed(num, n) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function debounce(fn, delay) { | function debounce(fn, delay) { | ||||||
|     var timeoutID = null |     var timeoutID = null; | ||||||
|     return function () { |     return function () { | ||||||
|       clearTimeout(timeoutID) |         clearTimeout(timeoutID); | ||||||
|       var args = arguments |         var args = arguments; | ||||||
|       var that = this |         var that = this; | ||||||
|         timeoutID = setTimeout(function () { |         timeoutID = setTimeout(function () { | ||||||
|         fn.apply(that, args) |             fn.apply(that, args); | ||||||
|       }, delay) |         }, delay); | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getCookie(cname) { | ||||||
|  |     let name = cname + '='; | ||||||
|  |     let decodedCookie = decodeURIComponent(document.cookie); | ||||||
|  |     let ca = decodedCookie.split(';'); | ||||||
|  |     for (let i = 0; i < ca.length; i++) { | ||||||
|  |         let c = ca[i]; | ||||||
|  |         while (c.charAt(0) == ' ') { | ||||||
|  |             c = c.substring(1); | ||||||
|  |         } | ||||||
|  |         if (c.indexOf(name) == 0) { | ||||||
|  |             return c.substring(name.length, c.length); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     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=/'; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -128,14 +128,13 @@ Date.prototype.formatDateTime = function (split = ' ') { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class DateUtil { | class DateUtil { | ||||||
| 
 |  | ||||||
|     // 字符串转 Date 对象
 |     // 字符串转 Date 对象
 | ||||||
|     static parseDate(str) { |     static parseDate(str) { | ||||||
|         return new Date(str.replace(/-/g, '/')); |         return new Date(str.replace(/-/g, '/')); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static formatMillis(millis) { |     static formatMillis(millis) { | ||||||
|         return moment(millis).format('YYYY-M-D H:m:s') |         return moment(millis).format('YYYY-M-D H:m:s'); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     static firstDayOfMonth() { |     static firstDayOfMonth() { | ||||||
|  |  | ||||||
|  | @ -68,13 +68,11 @@ class HttpUtil { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class PromiseUtil { | class PromiseUtil { | ||||||
| 
 |  | ||||||
|     static async sleep(timeout) { |     static async sleep(timeout) { | ||||||
|         await new Promise(resolve => { |         await new Promise(resolve => { | ||||||
|             setTimeout(resolve, timeout) |             setTimeout(resolve, timeout) | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const seq = [ | const seq = [ | ||||||
|  | @ -95,7 +93,6 @@ const shortIdSeq = [ | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| class RandomUtil { | class RandomUtil { | ||||||
| 
 |  | ||||||
|     static randomIntRange(min, max) { |     static randomIntRange(min, max) { | ||||||
|         return parseInt(Math.random() * (max - min) + min, 10); |         return parseInt(Math.random() * (max - min) + min, 10); | ||||||
|     } |     } | ||||||
|  | @ -153,7 +150,7 @@ class RandomUtil { | ||||||
|     static randomText() { |     static randomText() { | ||||||
|         var chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; |         var chars = 'abcdefghijklmnopqrstuvwxyz1234567890'; | ||||||
|         var string = ''; |         var string = ''; | ||||||
|         var len = 6 + Math.floor(Math.random() * 5) |         var len = 6 + Math.floor(Math.random() * 5); | ||||||
|         for (var ii = 0; ii < len; ii++) { |         for (var ii = 0; ii < len; ii++) { | ||||||
|             string += chars[Math.floor(Math.random() * chars.length)]; |             string += chars[Math.floor(Math.random() * chars.length)]; | ||||||
|         } |         } | ||||||
|  | @ -162,7 +159,7 @@ class RandomUtil { | ||||||
| 
 | 
 | ||||||
|     static randowShortId() { |     static randowShortId() { | ||||||
|         let str = ''; |         let str = ''; | ||||||
|         str += this.randomShortIdSeq(8) |         str += this.randomShortIdSeq(8); | ||||||
|         return str; |         return str; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -174,7 +171,6 @@ class RandomUtil { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ObjectUtil { | class ObjectUtil { | ||||||
| 
 |  | ||||||
|     static getPropIgnoreCase(obj, prop) { |     static getPropIgnoreCase(obj, prop) { | ||||||
|         for (const name in obj) { |         for (const name in obj) { | ||||||
|             if (!obj.hasOwnProperty(name)) { |             if (!obj.hasOwnProperty(name)) { | ||||||
|  | @ -322,5 +318,4 @@ class ObjectUtil { | ||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "promptModal"}} | {{define "promptModal"}} | ||||||
| <a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title" | <a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title" | ||||||
|          :closable="true" @ok="promptModal.ok" :mask-closable="false" |          :closable="true" @ok="promptModal.ok" :mask-closable="false" | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :ok-text="promptModal.okText" cancel-text='{{ i18n "cancel" }}'> |          :ok-text="promptModal.okText" cancel-text='{{ i18n "cancel" }}'> | ||||||
|     <a-input id="prompt-modal-input" :type="promptModal.type" |     <a-input id="prompt-modal-input" :type="promptModal.type" | ||||||
|              v-model="promptModal.value" |              v-model="promptModal.value" | ||||||
|  |  | ||||||
|  | @ -1,10 +1,12 @@ | ||||||
| {{define "qrcodeModal"}} | {{define "qrcodeModal"}} | ||||||
| <a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title" | <a-modal id="qrcode-modal" v-model="qrModal.visible" :title="qrModal.title" | ||||||
|          :closable="true" |          :closable="true" | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :footer="null" |          :footer="null" | ||||||
|          width="300px"> |          width="300px"> | ||||||
|     <a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;" >{{ i18n "pages.inbounds.clickOnQRcode" }}</a-tag> |     <a-tag color="green" style="margin-bottom: 10px;display: block;text-align: center;"> | ||||||
|  |         {{ i18n "pages.inbounds.clickOnQRcode" }} | ||||||
|  |     </a-tag> | ||||||
|     <canvas @click="copyToClipboard()" id="qrCode" style="width: 100%; height: 100%;"></canvas> |     <canvas @click="copyToClipboard()" id="qrCode" style="width: 100%; height: 100%;"></canvas> | ||||||
| </a-modal> | </a-modal> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "textModal"}} | {{define "textModal"}} | ||||||
| <a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title" | <a-modal id="text-modal" v-model="txtModal.visible" :title="txtModal.title" | ||||||
|          :closable="true" ok-text='{{ i18n "copy" }}' cancel-text='{{ i18n "close" }}' |          :closable="true" ok-text='{{ i18n "copy" }}' cancel-text='{{ i18n "close" }}' | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :ok-button-props="{attrs:{id:'txt-modal-ok-btn'}}"> |          :ok-button-props="{attrs:{id:'txt-modal-ok-btn'}}"> | ||||||
|     <a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" type="primary" style="margin-bottom: 10px;" |     <a-button v-if="!ObjectUtil.isEmpty(txtModal.fileName)" type="primary" style="margin-bottom: 10px;" | ||||||
|               :href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)" |               :href="'data:application/text;charset=utf-8,' + encodeURIComponent(txtModal.content)" | ||||||
|  |  | ||||||
|  | @ -18,6 +18,12 @@ | ||||||
|         border-radius: 30px; |         border-radius: 30px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     .ant-input-group-addon { | ||||||
|  |         border-radius: 0 30px 30px 0; | ||||||
|  |         width: 50px; | ||||||
|  |         font-size: 18px; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     .ant-input-affix-wrapper .ant-input-prefix { |     .ant-input-affix-wrapper .ant-input-prefix { | ||||||
|         left: 23px; |         left: 23px; | ||||||
|     } |     } | ||||||
|  | @ -26,20 +32,26 @@ | ||||||
|         padding-left: 50px; |         padding-left: 50px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     .selectLang{ |     .centered { | ||||||
|         display: flex; |         display: flex; | ||||||
|         text-align: center; |         text-align: center; | ||||||
|  |         align-items: center; | ||||||
|         justify-content: center; |         justify-content: center; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     .title { | ||||||
|  |         font-size: 32px; | ||||||
|  |         font-weight: bold; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| </style> | </style> | ||||||
| <body> | <body> | ||||||
| <a-layout id="app" v-cloak> | <a-layout id="app" v-cloak :class="themeSwitcher.darkClass"> | ||||||
|     <transition name="list" appear> |     <transition name="list" appear> | ||||||
|         <a-layout-content> |         <a-layout-content> | ||||||
|             <a-row type="flex" justify="center"> |             <a-row type="flex" justify="center"> | ||||||
|                 <a-col :xs="22" :sm="20" :md="16" :lg="12" :xl="8"> |                 <a-col :xs="22" :sm="20" :md="16" :lg="12" :xl="8"> | ||||||
|                     <h1>{{ i18n "pages.login.title" }}</h1> |                     <h1 class="title">{{ i18n "pages.login.title" }}</h1> | ||||||
|                 </a-col> |                 </a-col> | ||||||
|             </a-row> |             </a-row> | ||||||
|             <a-row type="flex" justify="center"> |             <a-row type="flex" justify="center"> | ||||||
|  | @ -48,34 +60,32 @@ | ||||||
|                         <a-form-item> |                         <a-form-item> | ||||||
|                             <a-input v-model.trim="user.username" placeholder='{{ i18n "username" }}' |                             <a-input v-model.trim="user.username" placeholder='{{ i18n "username" }}' | ||||||
|                                      @keydown.enter.native="login" autofocus> |                                      @keydown.enter.native="login" autofocus> | ||||||
|                                 <a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)"/> |                                 <a-icon slot="prefix" type="user" :style="'font-size: 16px;' + themeSwitcher.textStyle" /> | ||||||
|                             </a-input> |                             </a-input> | ||||||
|                         </a-form-item> |                         </a-form-item> | ||||||
|                         <a-form-item> |                         <a-form-item> | ||||||
|                             <a-input type="password" v-model.trim="user.password" |                             <password-input icon="lock" v-model.trim="user.password" | ||||||
|                                             placeholder='{{ i18n "password" }}' @keydown.enter.native="login"> |                                             placeholder='{{ i18n "password" }}' @keydown.enter.native="login"> | ||||||
|                                 <a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/> |                             </password-input> | ||||||
|                             </a-input> |  | ||||||
|                         </a-form-item> |                         </a-form-item> | ||||||
|                         <a-form-item v-if="secretEnable"> |                         <a-form-item v-if="secretEnable"> | ||||||
|                             <a-input type="text" placeholder='{{ i18n "secretToken" }}' v-model.trim="user.loginSecret" @keydown.enter.native="login"> |                             <password-input icon="key" v-model.trim="user.loginSecret" | ||||||
|                             <a-icon slot="prefix" type="key" style="color: rgba(0,0,0,.25)"/> |                                             placeholder='{{ i18n "secretToken" }}' @keydown.enter.native="login"> | ||||||
|  |                             </password-input> | ||||||
|                         </a-input> |                         </a-input> | ||||||
|                         </a-form-item> |                         </a-form-item> | ||||||
|                         <a-form-item> |                         <a-form-item> | ||||||
|                             <a-button block @click="login" :loading="loading">{{ i18n "login" }}</a-button> |                             <a-row justify="center" class="centered"> | ||||||
|  |                                 <a-button type="primary" :loading="loading" @click="login" :icon="loading ? 'poweroff' : undefined" | ||||||
|  |                                           :style="loading ? { width: '50px' } : { display: 'block', width: '100%' }"> | ||||||
|  |                                     [[ loading ? '' : '{{ i18n "login" }}' ]] | ||||||
|  |                                 </a-button> | ||||||
|  |                             </a-row> | ||||||
|                         </a-form-item> |                         </a-form-item> | ||||||
|                         <a-form-item> |                         <a-form-item> | ||||||
| 
 |                             <a-row justify="center" class="centered"> | ||||||
|                             <a-row justify="center" class="selectLang"> |                                 <a-col :span="12"> | ||||||
|                                 <a-col :span="5"><span>Language :</span></a-col> |                                     <a-select ref="selectLang" v-model="lang" @change="setLang(lang)" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
| 
 |  | ||||||
|                                 <a-col :span="7"> |  | ||||||
|                                     <a-select |  | ||||||
|                                             ref="selectLang" |  | ||||||
|                                             v-model="lang" |  | ||||||
|                                             @change="setLang(lang)" |  | ||||||
|                                     > |  | ||||||
|                                         <a-select-option :value="l.value" label="English" v-for="l in supportLangs"> |                                         <a-select-option :value="l.value" label="English" v-for="l in supportLangs"> | ||||||
|                                             <span role="img" aria-label="l.name" v-text="l.icon"></span> |                                             <span role="img" aria-label="l.name" v-text="l.icon"></span> | ||||||
|                                               <span v-text="l.name"></span> |                                               <span v-text="l.name"></span> | ||||||
|  | @ -84,6 +94,11 @@ | ||||||
|                                 </a-col> |                                 </a-col> | ||||||
|                             </a-row> |                             </a-row> | ||||||
|                         </a-form-item> |                         </a-form-item> | ||||||
|  |                         <a-form-item> | ||||||
|  |                             <a-row justify="center" class="centered"> | ||||||
|  |                                 <theme-switch /> | ||||||
|  |                             </a-row> | ||||||
|  |                         </a-form-item> | ||||||
|                     </a-form> |                     </a-form> | ||||||
|                 </a-col> |                 </a-col> | ||||||
|             </a-row> |             </a-row> | ||||||
|  | @ -91,22 +106,22 @@ | ||||||
|     </transition> |     </transition> | ||||||
| </a-layout> | </a-layout> | ||||||
| {{template "js" .}} | {{template "js" .}} | ||||||
|  | {{template "component/themeSwitcher" .}} | ||||||
|  | {{template "component/password" .}} | ||||||
| <script> | <script> | ||||||
|     const leftColor = RandomUtil.randomIntRange(0x222222, 0xFFFFFF / 2).toString(16); | 
 | ||||||
|     const rightColor = RandomUtil.randomIntRange(0xFFFFFF / 2, 0xDDDDDD).toString(16); |  | ||||||
|     const deg = RandomUtil.randomIntRange(0, 360); |  | ||||||
|     const background = `linear-gradient(${deg}deg, #${leftColor} 10%, #${rightColor} 100%)`; |  | ||||||
|     document.querySelector('#app').style.background = background; |  | ||||||
|     const app = new Vue({ |     const app = new Vue({ | ||||||
|         delimiters: ['[[', ']]'], |         delimiters: ['[[', ']]'], | ||||||
|         el: '#app', |         el: '#app', | ||||||
|         data: { |         data: { | ||||||
|  |             themeSwitcher, | ||||||
|             loading: false, |             loading: false, | ||||||
|             user: new User(), |             user: new User(), | ||||||
|             secretEnable: false, |             secretEnable: false, | ||||||
|             lang: "" |             lang: "" | ||||||
|         }, |         }, | ||||||
|         created() { |         created() { | ||||||
|  |             this.updateBackground(); | ||||||
|             this.lang = getLang(); |             this.lang = getLang(); | ||||||
|             this.secretEnable = this.getSecretStatus(); |             this.secretEnable = this.getSecretStatus(); | ||||||
|         }, |         }, | ||||||
|  | @ -127,9 +142,22 @@ | ||||||
|                     this.secretEnable = msg.obj; |                     this.secretEnable = msg.obj; | ||||||
|                     return msg.obj; |                     return msg.obj; | ||||||
|                 } |                 } | ||||||
|             } |             }, | ||||||
|         } |             updateBackground() { | ||||||
|  |                 const leftColor = RandomUtil.randomIntRange(0x222222, 0xFFFFFF / 2).toString(16); | ||||||
|  |                 const rightColor = RandomUtil.randomIntRange(0xFFFFFF / 2, 0xDDDDDD).toString(16); | ||||||
|  |                 const deg = RandomUtil.randomIntRange(0, 360); | ||||||
|  |                 const background = `linear-gradient(${deg}deg, #${leftColor} 10%, #${rightColor} 100%)`; | ||||||
|  |                 document.querySelector('#app').style.background = this.themeSwitcher.isDarkTheme ? colors.dark.bg : background; | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |         watch: { | ||||||
|  |             'themeSwitcher.isDarkTheme'(newVal, oldVal) { | ||||||
|  |                 this.updateBackground(); | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
| </script> | </script> | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  | @ -1,11 +1,11 @@ | ||||||
| {{define "clientsBulkModal"}} | {{define "clientsBulkModal"}} | ||||||
| <a-modal id="client-bulk-modal" v-model="clientsBulkModal.visible" :title="clientsBulkModal.title" @ok="clientsBulkModal.ok" | <a-modal id="client-bulk-modal" v-model="clientsBulkModal.visible" :title="clientsBulkModal.title" @ok="clientsBulkModal.ok" | ||||||
|          :confirm-loading="clientsBulkModal.confirmLoading" :closable="true" :mask-closable="false" |          :confirm-loading="clientsBulkModal.confirmLoading" :closable="true" :mask-closable="false" | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}'> |          :ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}'> | ||||||
|     <a-form layout="inline"> |     <a-form layout="inline"> | ||||||
|         <a-form-item label='{{ i18n "pages.client.method" }}'> |         <a-form-item label='{{ i18n "pages.client.method" }}'> | ||||||
|             <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |             <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" style="width: 350px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                 <a-select-option :value="0">Random</a-select-option> |                 <a-select-option :value="0">Random</a-select-option> | ||||||
|                 <a-select-option :value="1">Random+Prefix</a-select-option> |                 <a-select-option :value="1">Random+Prefix</a-select-option> | ||||||
|                 <a-select-option :value="2">Random+Prefix+Num</a-select-option> |                 <a-select-option :value="2">Random+Prefix+Num</a-select-option> | ||||||
|  | @ -71,13 +71,13 @@ | ||||||
|         </a-form-item> |         </a-form-item> | ||||||
|         <br> |         <br> | ||||||
|         <a-form-item v-if="clientsBulkModal.inbound.xtls" label="Flow"> |         <a-form-item v-if="clientsBulkModal.inbound.xtls" label="Flow"> | ||||||
|             <a-select v-model="clientsBulkModal.flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |             <a-select v-model="clientsBulkModal.flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                 <a-select-option value="">{{ i18n "none" }}</a-select-option> |                 <a-select-option value="">{{ i18n "none" }}</a-select-option> | ||||||
|                 <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |                 <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|             </a-select> |             </a-select> | ||||||
|         </a-form-item> |         </a-form-item> | ||||||
|         <a-form-item v-if="clientsBulkModal.inbound.canEnableTlsFlow()" label="Flow" layout="inline"> |         <a-form-item v-if="clientsBulkModal.inbound.canEnableTlsFlow()" label="Flow" layout="inline"> | ||||||
|             <a-select v-model="clientsBulkModal.flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |             <a-select v-model="clientsBulkModal.flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                 <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> |                 <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> | ||||||
|                 <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |                 <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|             </a-select> |             </a-select> | ||||||
|  | @ -113,7 +113,7 @@ | ||||||
|                 </a-tooltip> |                 </a-tooltip> | ||||||
|             </span> |             </span> | ||||||
|             <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |             <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                            :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                            :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                            v-model="clientsBulkModal.expiryTime" style="width: 300px;"></a-date-picker> |                            v-model="clientsBulkModal.expiryTime" style="width: 300px;"></a-date-picker> | ||||||
|         </a-form-item> |         </a-form-item> | ||||||
|     </a-form> |     </a-form> | ||||||
|  | @ -173,7 +173,12 @@ | ||||||
|             } |             } | ||||||
|             ObjectUtil.execute(clientsBulkModal.confirm, clients, clientsBulkModal.dbInbound.id); |             ObjectUtil.execute(clientsBulkModal.confirm, clients, clientsBulkModal.dbInbound.id); | ||||||
|         }, |         }, | ||||||
|         show({ title='', okText='{{ i18n "sure" }}', dbInbound=null, confirm=(inbound, dbInbound)=>{} }) { |         show({ | ||||||
|  |             title = '', | ||||||
|  |             okText = '{{ i18n "sure" }}', | ||||||
|  |             dbInbound = null, | ||||||
|  |             confirm = (inbound, dbInbound) => { } | ||||||
|  |         }) { | ||||||
|             this.visible = true; |             this.visible = true; | ||||||
|             this.title = title; |             this.title = title; | ||||||
|             this.okText = okText; |             this.okText = okText; | ||||||
|  | @ -235,5 +240,6 @@ | ||||||
|             }, |             }, | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
| </script> | </script> | ||||||
| {{end}} | {{end}} | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "clientsModal"}} | {{define "clientsModal"}} | ||||||
| <a-modal id="client-modal" v-model="clientModal.visible" :title="clientModal.title" @ok="clientModal.ok" | <a-modal id="client-modal" v-model="clientModal.visible" :title="clientModal.title" @ok="clientModal.ok" | ||||||
|          :confirm-loading="clientModal.confirmLoading" :closable="true" :mask-closable="false" |          :confirm-loading="clientModal.confirmLoading" :closable="true" :mask-closable="false" | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :ok-text="clientModal.okText" cancel-text='{{ i18n "close" }}'> |          :ok-text="clientModal.okText" cancel-text='{{ i18n "close" }}'> | ||||||
|     {{template "form/client"}} |     {{template "form/client"}} | ||||||
| </a-modal> | </a-modal> | ||||||
|  | @ -159,7 +159,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', |                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', |                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: async () => { |                     onOk: async () => { | ||||||
|  | @ -175,5 +175,6 @@ | ||||||
|             }, |             }, | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
| </script> | </script> | ||||||
| {{end}} | {{end}} | ||||||
|  |  | ||||||
|  | @ -23,17 +23,14 @@ | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| {{define "commonSider"}} | {{define "commonSider"}} | ||||||
| <a-layout-sider :theme="siderDrawer.theme" id="sider" collapsible breakpoint="md" collapsed-width="0"> | <a-layout-sider :theme="themeSwitcher.currentTheme" id="sider" collapsible breakpoint="md" collapsed-width="0"> | ||||||
|     <a-menu :theme="siderDrawer.theme" mode="inline" selected-keys=""> |     <a-menu :theme="themeSwitcher.currentTheme" mode="inline" selected-keys=""> | ||||||
|         <a-menu-item mode="inline"> |         <a-menu-item mode="inline"> | ||||||
|             <a-icon type="bg-colors"></a-icon> |             <a-icon type="bg-colors"></a-icon> | ||||||
|             <a-switch :default-checked="siderDrawer.isDarkTheme" |             <theme-switch /> | ||||||
|             checked-children="☀" |  | ||||||
|             un-checked-children="🌙" |  | ||||||
|             @change="siderDrawer.changeTheme()"></a-switch> |  | ||||||
|         </a-menu-item> |         </a-menu-item> | ||||||
|     </a-menu> |     </a-menu> | ||||||
|     <a-menu :theme="siderDrawer.theme" mode="inline" :selected-keys="['{{ .request_uri }}']" |     <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" | ||||||
|             @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> |             @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> | ||||||
|         {{template "menuItems" .}} |         {{template "menuItems" .}} | ||||||
|     </a-menu> |     </a-menu> | ||||||
|  | @ -41,32 +38,25 @@ | ||||||
| <a-drawer id="sider-drawer" placement="left" :closable="false" | <a-drawer id="sider-drawer" placement="left" :closable="false" | ||||||
|           @close="siderDrawer.close()" |           @close="siderDrawer.close()" | ||||||
|           :visible="siderDrawer.visible" |           :visible="siderDrawer.visible" | ||||||
|           :wrap-class-name="siderDrawer.isDarkTheme ? 'ant-drawer-dark' : ''" |           :wrap-class-name="themeSwitcher.darkDrawerClass" | ||||||
|           :wrap-style="{ padding: 0 }"> |           :wrap-style="{ padding: 0 }"> | ||||||
|     <div class="drawer-handle" @click="siderDrawer.change()" slot="handle"> |     <div class="drawer-handle" @click="siderDrawer.change()" slot="handle"> | ||||||
|         <a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon> |         <a-icon :type="siderDrawer.visible ? 'close' : 'menu-fold'"></a-icon> | ||||||
|     </div> |     </div> | ||||||
|     <a-menu :theme="siderDrawer.theme" mode="inline" selected-keys=""> |     <a-menu :theme="themeSwitcher.currentTheme" mode="inline" selected-keys=""> | ||||||
|         <a-menu-item mode="inline"> |         <a-menu-item mode="inline"> | ||||||
|             <a-icon type="bg-colors"></a-icon> |             <a-icon type="bg-colors"></a-icon> | ||||||
|             <a-switch :default-checked="siderDrawer.isDarkTheme" |             <theme-switch /> | ||||||
|             checked-children="☀" |  | ||||||
|             un-checked-children="🌙" |  | ||||||
|             @change="siderDrawer.changeTheme()"></a-switch> |  | ||||||
|         </a-menu-item> |         </a-menu-item> | ||||||
|     </a-menu> |     </a-menu> | ||||||
|     <a-menu :theme="siderDrawer.theme" mode="inline" :selected-keys="['{{ .request_uri }}']" |     <a-menu :theme="themeSwitcher.currentTheme" mode="inline" :selected-keys="['{{ .request_uri }}']" | ||||||
|         @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> |         @click="({key}) => key.startsWith('http') ? window.open(key) : location.href = key"> | ||||||
|         {{template "menuItems" .}} |         {{template "menuItems" .}} | ||||||
|     </a-menu> |     </a-menu> | ||||||
| </a-drawer> | </a-drawer> | ||||||
| <script> | <script> | ||||||
|     const darkClass = "ant-card-dark"; |  | ||||||
|     const bgDarkStyle = "background-color: #242c3a"; |  | ||||||
|     const siderDrawer = { |     const siderDrawer = { | ||||||
|         visible: false, |         visible: false, | ||||||
|         collapsed: false, |  | ||||||
|         isDarkTheme: localStorage.getItem("dark-mode") === 'false' ? false : true, |  | ||||||
|         show() { |         show() { | ||||||
|             this.visible = true; |             this.visible = true; | ||||||
|         }, |         }, | ||||||
|  | @ -76,17 +66,6 @@ | ||||||
|         change() { |         change() { | ||||||
|             this.visible = !this.visible; |             this.visible = !this.visible; | ||||||
|         }, |         }, | ||||||
|         toggleCollapsed() { |  | ||||||
|             this.collapsed = !this.collapsed; |  | ||||||
|         }, |  | ||||||
|         changeTheme() { |  | ||||||
|             this.isDarkTheme = ! this.isDarkTheme; |  | ||||||
|             localStorage.setItem("dark-mode", this.isDarkTheme); |  | ||||||
|         }, |  | ||||||
|         get theme() { |  | ||||||
|             return this.isDarkTheme ? 'dark' : 'light'; |  | ||||||
|         } |  | ||||||
|     }; |     }; | ||||||
| 
 |  | ||||||
| </script> | </script> | ||||||
| {{end}} | {{end}} | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								web/html/xui/component/password.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								web/html/xui/component/password.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | {{define "component/passwordInput"}} | ||||||
|  | <template> | ||||||
|  |     <a-input :value="value" :type="showPassword ? 'text' : 'password'" | ||||||
|  |             :placeholder="placeholder" | ||||||
|  |             @input="$emit('input', $event.target.value)"> | ||||||
|  |         <template v-if="icon" #prefix> | ||||||
|  |             <a-icon :type="icon" :style="'font-size: 16px;' + themeSwitcher.textStyle" /> | ||||||
|  |         </template> | ||||||
|  |         <template #addonAfter> | ||||||
|  |             <a-icon :type="showPassword ? 'eye-invisible' : 'eye'" | ||||||
|  |                     @click="toggleShowPassword" | ||||||
|  |                     :style="'font-size: 16px;' + themeSwitcher.textStyle" /> | ||||||
|  |         </template> | ||||||
|  |     </a-input> | ||||||
|  | </template> | ||||||
|  | {{end}} | ||||||
|  | 
 | ||||||
|  | {{define "component/password"}} | ||||||
|  | <script> | ||||||
|  |   Vue.component('password-input', { | ||||||
|  |     props: ["title", "value", "placeholder", "icon"], | ||||||
|  |     template: `{{template "component/passwordInput"}}`, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         showPassword: false, | ||||||
|  |       }; | ||||||
|  |     }, | ||||||
|  |     methods: { | ||||||
|  |       toggleShowPassword() { | ||||||
|  |         this.showPassword = !this.showPassword; | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |   }); | ||||||
|  | </script> | ||||||
|  | {{end}} | ||||||
							
								
								
									
										58
									
								
								web/html/xui/component/themeSwitch.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								web/html/xui/component/themeSwitch.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | ||||||
|  | {{define "component/themeSwitchTemplate"}} | ||||||
|  | <template> | ||||||
|  |   <a-switch :default-checked="themeSwitcher.isDarkTheme" | ||||||
|  |             checked-children="☀" | ||||||
|  |             un-checked-children="🌙" | ||||||
|  |             @change="themeSwitcher.toggleTheme()"> | ||||||
|  |   </a-switch> | ||||||
|  | </template> | ||||||
|  | {{end}} | ||||||
|  | 
 | ||||||
|  | {{define "component/themeSwitcher"}} | ||||||
|  | <script> | ||||||
|  |   const colors = { | ||||||
|  |     dark: { | ||||||
|  |       bg: "#242c3a", | ||||||
|  |       text: "hsla(0,0%,100%,.65)" | ||||||
|  |     }, | ||||||
|  |     light: { | ||||||
|  |       bg: '#f0f2f5', | ||||||
|  |       text: "rgba(0, 0, 0, 0.7)", | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   function createThemeSwitcher() { | ||||||
|  |     const isDarkTheme = localStorage.getItem('dark-mode') === 'true'; | ||||||
|  |     const theme = isDarkTheme ? 'dark' : 'light'; | ||||||
|  |     return { | ||||||
|  |       isDarkTheme, | ||||||
|  |       bgStyle: `background: ${colors[theme].bg};`, | ||||||
|  |       textStyle: `color: ${colors[theme].text};`, | ||||||
|  |       darkClass: isDarkTheme ? 'ant-card-dark' : '', | ||||||
|  |       darkCardClass: isDarkTheme ? 'ant-card-dark' : '', | ||||||
|  |       darkDrawerClass: isDarkTheme ? 'ant-drawer-dark' : '', | ||||||
|  |       get currentTheme() { | ||||||
|  |         return this.isDarkTheme ? 'dark' : 'light'; | ||||||
|  |       }, | ||||||
|  |       toggleTheme() { | ||||||
|  |         this.isDarkTheme = !this.isDarkTheme; | ||||||
|  |         this.theme = this.isDarkTheme ? 'dark' : 'light'; | ||||||
|  |         localStorage.setItem('dark-mode', this.isDarkTheme); | ||||||
|  |         this.bgStyle = `background: ${colors[this.theme].bg};`; | ||||||
|  |         this.textStyle = `color: ${colors[this.theme].text};`; | ||||||
|  |         this.darkClass = this.isDarkTheme ? 'ant-card-dark' : ''; | ||||||
|  |         this.darkCardClass = this.isDarkTheme ? 'ant-card-dark' : ''; | ||||||
|  |         this.darkDrawerClass = this.isDarkTheme ? 'ant-drawer-dark' : ''; | ||||||
|  |       }, | ||||||
|  |     }; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const themeSwitcher = createThemeSwitcher(); | ||||||
|  | 
 | ||||||
|  |   Vue.component('theme-switch', { | ||||||
|  |     props: [], | ||||||
|  |     template: `{{template "component/themeSwitchTemplate"}}`, | ||||||
|  |     data: () => ({ themeSwitcher }), | ||||||
|  |   }); | ||||||
|  | </script> | ||||||
|  | {{end}} | ||||||
|  | @ -1,7 +1,9 @@ | ||||||
| {{define "form/client"}} | {{define "form/client"}} | ||||||
| <a-form layout="inline" v-if="client"> | <a-form layout="inline" v-if="client"> | ||||||
|     <template v-if="isEdit"> |     <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="margin-bottom: 10px;display: block;text-align: center;"> | ||||||
|  |             Account is (Expired|Traffic Ended) And Disabled | ||||||
|  |         </a-tag> | ||||||
|     </template> |     </template> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.enable" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.enable" }}'> | ||||||
|         <a-switch v-model="client.enable"></a-switch> |         <a-switch v-model="client.enable"></a-switch> | ||||||
|  | @ -20,7 +22,8 @@ | ||||||
|         <a-input v-model.trim="client.email" style="width: 200px;"></a-input> |         <a-input v-model.trim="client.email" style="width: 200px;"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="Password" v-if="inbound.protocol === Protocols.TROJAN || inbound.protocol === Protocols.SHADOWSOCKS"> |     <a-form-item label="Password" v-if="inbound.protocol === Protocols.TROJAN || inbound.protocol === Protocols.SHADOWSOCKS"> | ||||||
|         <a-icon v-if="inbound.protocol === Protocols.SHADOWSOCKS" @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon> |         <a-icon v-if="inbound.protocol === Protocols.SHADOWSOCKS" | ||||||
|  |                 @click="client.password = RandomUtil.randomShadowsocksPassword()" type="sync"> </a-icon> | ||||||
|         <a-input v-model.trim="client.password" style="width: 300px;"></a-input> |         <a-input v-model.trim="client.password" style="width: 300px;"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <br> |     <br> | ||||||
|  | @ -85,19 +88,22 @@ | ||||||
| 			</a-tooltip> | 			</a-tooltip> | ||||||
| 		</span> | 		</span> | ||||||
| 		<a-form layout="block"> | 		<a-form layout="block"> | ||||||
| 			<a-textarea id="clientIPs" readonly @click="getDBClientIps(client.email,$event)" placeholder="Click To Get IPs"  :auto-size="{ minRows: 2, maxRows: 10 }"> | 			<a-textarea id="clientIPs" readonly  | ||||||
|  |                         @click="getDBClientIps(client.email,$event)" | ||||||
|  |                         placeholder="Click To Get IPs" | ||||||
|  |                         :auto-size="{ minRows: 2, maxRows: 10 }"> | ||||||
| 			</a-textarea> | 			</a-textarea> | ||||||
| 		</a-form> | 		</a-form> | ||||||
| 	</a-form-item> | 	</a-form-item> | ||||||
|     <br> |     <br> | ||||||
|     <a-form-item v-if="inbound.xtls" label="Flow"> |     <a-form-item v-if="inbound.xtls" label="Flow"> | ||||||
|         <a-select v-model="client.flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="client.flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="">{{ i18n "none" }}</a-select-option> |             <a-select-option value="">{{ i18n "none" }}</a-select-option> | ||||||
|             <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="Flow"> |     <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="Flow"> | ||||||
|         <a-select v-model="client.flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="client.flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> |             <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> | ||||||
|             <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|  | @ -114,7 +120,8 @@ | ||||||
|         </span> |         </span> | ||||||
|         <a-input-number v-model="client._totalGB" :min="0"></a-input-number> |         <a-input-number v-model="client._totalGB" :min="0"></a-input-number> | ||||||
|         <template v-if="isEdit && clientStats"> |         <template v-if="isEdit && clientStats"> | ||||||
|             <br><span> {{ i18n "usage" }}:</span> |             <br> | ||||||
|  |             <span> {{ i18n "usage" }}:</span> | ||||||
|             <a-tag :color="statsColor"> |             <a-tag :color="statsColor"> | ||||||
|                 [[ sizeFormat(clientStats.up) ]] /  |                 [[ sizeFormat(clientStats.up) ]] /  | ||||||
|                 [[ sizeFormat(clientStats.down) ]] |                 [[ sizeFormat(clientStats.down) ]] | ||||||
|  | @ -122,7 +129,8 @@ | ||||||
|             </a-tag> |             </a-tag> | ||||||
|             <a-tooltip> |             <a-tooltip> | ||||||
|                 <template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template> |                 <template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template> | ||||||
|                 <a-icon type="retweet" @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)" v-if="client.email.length > 0"></a-icon> |                 <a-icon type="retweet" @click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)" | ||||||
|  |                         v-if="client.email.length > 0"></a-icon> | ||||||
|             </a-tooltip> |             </a-tooltip> | ||||||
|         </template>         |         </template>         | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -145,7 +153,7 @@ | ||||||
|             </a-tooltip> |             </a-tooltip> | ||||||
|         </span> |         </span> | ||||||
|         <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |         <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                        :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                        :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                        v-model="client._expiryTime" style="width: 170px;"></a-date-picker> |                        v-model="client._expiryTime" style="width: 170px;"></a-date-picker> | ||||||
|         <a-tag color="red" v-if="isExpiry">Expired</a-tag> |         <a-tag color="red" v-if="isExpiry">Expired</a-tag> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
|         <a-switch v-model="dbInbound.enable"></a-switch> |         <a-switch v-model="dbInbound.enable"></a-switch> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "protocol" }}'> |     <a-form-item label='{{ i18n "protocol" }}'> | ||||||
|         <a-select v-model="inbound.protocol" style="width: 160px;" :disabled="isEdit" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.protocol" style="width: 160px;" :disabled="isEdit" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option v-for="p in Protocols" :key="p" :value="p">[[ p ]]</a-select-option> |             <a-select-option v-for="p in Protocols" :key="p" :value="p">[[ p ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -52,7 +52,7 @@ | ||||||
|             </a-tooltip> |             </a-tooltip> | ||||||
|         </span> |         </span> | ||||||
|         <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |         <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                        :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                        :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                        v-model="dbInbound._expiryTime" style="width: 300px;"></a-date-picker> |                        v-model="dbInbound._expiryTime" style="width: 300px;"></a-date-picker> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
| </a-form> | </a-form> | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <br> |     <br> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.network"}}'> |     <a-form-item label='{{ i18n "pages.inbounds.network"}}'> | ||||||
|         <a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="tcp,udp">TCP+UDP</a-select-option> |             <a-select-option value="tcp,udp">TCP+UDP</a-select-option> | ||||||
|             <a-select-option value="tcp">TCP</a-select-option> |             <a-select-option value="tcp">TCP</a-select-option> | ||||||
|             <a-select-option value="udp">UDP</a-select-option> |             <a-select-option value="udp">UDP</a-select-option> | ||||||
|  |  | ||||||
|  | @ -86,7 +86,7 @@ | ||||||
|                     </a-tooltip> |                     </a-tooltip> | ||||||
|                 </span> |                 </span> | ||||||
|                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                                 :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                                 :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> |                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|         </a-collapse-panel> |         </a-collapse-panel> | ||||||
|  | @ -106,7 +106,7 @@ | ||||||
| </a-form> | </a-form> | ||||||
| <a-form layout="inline"> | <a-form layout="inline"> | ||||||
|     <a-form-item label='{{ i18n "encryption" }}'> |     <a-form-item label='{{ i18n "encryption" }}'> | ||||||
|         <a-select v-model="inbound.settings.method" style="width: 250px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.settings.method" style="width: 250px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option> |             <a-select-option v-for="method in SSMethods" :value="method">[[ method ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -114,7 +114,7 @@ | ||||||
|         <a-input v-model.trim="inbound.settings.password" style="width: 250px;"></a-input> |         <a-input v-model.trim="inbound.settings.password" style="width: 250px;"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.network" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.network" }}'> | ||||||
|         <a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.settings.network" style="width: 100px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="tcp,udp">TCP+UDP</a-select-option> |             <a-select-option value="tcp,udp">TCP+UDP</a-select-option> | ||||||
|             <a-select-option value="tcp">TCP</a-select-option> |             <a-select-option value="tcp">TCP</a-select-option> | ||||||
|             <a-select-option value="udp">UDP</a-select-option> |             <a-select-option value="udp">UDP</a-select-option> | ||||||
|  |  | ||||||
|  | @ -17,8 +17,7 @@ | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.enable" }} udp'> |     <a-form-item label='{{ i18n "pages.inbounds.enable" }} udp'> | ||||||
|         <a-switch v-model="inbound.settings.udp"></a-switch> |         <a-switch v-model="inbound.settings.udp"></a-switch> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item v-if="inbound.settings.udp" |     <a-form-item v-if="inbound.settings.udp" label="IP"> | ||||||
|                  label="IP"> |  | ||||||
|         <a-input v-model.trim="inbound.settings.ip"></a-input> |         <a-input v-model.trim="inbound.settings.ip"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
| </a-form> | </a-form> | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|             <br> |             <br> | ||||||
|             <a-form-item v-if="inbound.xtls" label="Flow"> |             <a-form-item v-if="inbound.xtls" label="Flow"> | ||||||
|                 <a-select v-model="client.flow" style="width: 150px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                 <a-select v-model="client.flow" style="width: 150px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                     <a-select-option value="">{{ i18n "none" }}</a-select-option> |                     <a-select-option value="">{{ i18n "none" }}</a-select-option> | ||||||
|                     <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |                     <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|                 </a-select> |                 </a-select> | ||||||
|  | @ -91,7 +91,7 @@ | ||||||
|                     </a-tooltip> |                     </a-tooltip> | ||||||
|                 </span> |                 </span> | ||||||
|                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                                 :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                                 :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> |                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|         </a-collapse-panel> |         </a-collapse-panel> | ||||||
|  | @ -113,8 +113,7 @@ | ||||||
|     <a-form layout="inline"> |     <a-form layout="inline"> | ||||||
|         <a-form-item label="Fallbacks"> |         <a-form-item label="Fallbacks"> | ||||||
|             <a-row> |             <a-row> | ||||||
|                 <a-button type="primary" size="small" |                 <a-button type="primary" size="small" @click="inbound.settings.addTrojanFallback()"> | ||||||
|                         @click="inbound.settings.addTrojanFallback()"> |  | ||||||
|                     + |                     + | ||||||
|                 </a-button> |                 </a-button> | ||||||
|             </a-row> |             </a-row> | ||||||
|  |  | ||||||
|  | @ -55,13 +55,13 @@ | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|             <br> |             <br> | ||||||
|             <a-form-item v-if="inbound.xtls" label="Flow"> |             <a-form-item v-if="inbound.xtls" label="Flow"> | ||||||
|                 <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                 <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                     <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> |                     <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> | ||||||
|                     <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |                     <a-select-option v-for="key in XTLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|                 </a-select> |                 </a-select> | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|             <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="Flow"> |             <a-form-item v-else-if="inbound.canEnableTlsFlow()" label="Flow"> | ||||||
|                 <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 200px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                 <a-select v-model="inbound.settings.vlesses[index].flow" style="width: 200px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                     <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> |                     <a-select-option value="" selected>{{ i18n "none" }}</a-select-option> | ||||||
|                     <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> |                     <a-select-option v-for="key in TLS_FLOW_CONTROL" :value="key">[[ key ]]</a-select-option> | ||||||
|                 </a-select> |                 </a-select> | ||||||
|  | @ -97,7 +97,7 @@ | ||||||
|                     </a-tooltip> |                     </a-tooltip> | ||||||
|                 </span> |                 </span> | ||||||
|                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                                :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                                :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                                v-model="client._expiryTime" style="width: 170px;"></a-date-picker> |                                v-model="client._expiryTime" style="width: 170px;"></a-date-picker> | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|         </a-collapse-panel>      |         </a-collapse-panel>      | ||||||
|  | @ -119,8 +119,7 @@ | ||||||
|     <a-form layout="inline"> |     <a-form layout="inline"> | ||||||
|         <a-form-item label="Fallbacks"> |         <a-form-item label="Fallbacks"> | ||||||
|             <a-row> |             <a-row> | ||||||
|                 <a-button type="primary" size="small" |                 <a-button type="primary" size="small" @click="inbound.settings.addFallback()"> | ||||||
|                         @click="inbound.settings.addFallback()"> |  | ||||||
|                     + |                     + | ||||||
|                 </a-button> |                 </a-button> | ||||||
|             </a-row> |             </a-row> | ||||||
|  |  | ||||||
|  | @ -90,7 +90,7 @@ | ||||||
|                     </a-tooltip> |                     </a-tooltip> | ||||||
|                 </span> |                 </span> | ||||||
|                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" |                 <a-date-picker :show-time="{ format: 'HH:mm:ss' }" format="YYYY-MM-DD HH:mm:ss" | ||||||
|                                 :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                                 :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> |                                 v-model="client._expiryTime" style="width: 170px;"></a-date-picker> | ||||||
|             </a-form-item> |             </a-form-item> | ||||||
|         </a-collapse-panel>      |         </a-collapse-panel>      | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "form/streamKCP"}} | {{define "form/streamKCP"}} | ||||||
| <a-form layout="inline"> | <a-form layout="inline"> | ||||||
|     <a-form-item label='{{ i18n "camouflage" }}'> |     <a-form-item label='{{ i18n "camouflage" }}'> | ||||||
|         <a-select v-model="inbound.stream.kcp.type" style="width: 280px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.kcp.type" style="width: 280px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="none">None (Not Camouflage)</a-select-option> |             <a-select-option value="none">None (Not Camouflage)</a-select-option> | ||||||
|             <a-select-option value="srtp">SRTP (Camouflage Video Call)</a-select-option> |             <a-select-option value="srtp">SRTP (Camouflage Video Call)</a-select-option> | ||||||
|             <a-select-option value="utp">UTP (Camouflage BT Download)</a-select-option> |             <a-select-option value="utp">UTP (Camouflage BT Download)</a-select-option> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "form/streamQUIC"}} | {{define "form/streamQUIC"}} | ||||||
| <a-form layout="inline"> | <a-form layout="inline"> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.quic.encryption" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.quic.encryption" }}'> | ||||||
|         <a-select v-model="inbound.stream.quic.security" style="width: 165px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.quic.security" style="width: 165px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="none">none</a-select-option> |             <a-select-option value="none">none</a-select-option> | ||||||
|             <a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option> |             <a-select-option value="aes-128-gcm">aes-128-gcm</a-select-option> | ||||||
|             <a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option> |             <a-select-option value="chacha20-poly1305">chacha20-poly1305</a-select-option> | ||||||
|  | @ -11,7 +11,7 @@ | ||||||
|         <a-input v-model.trim="inbound.stream.quic.key"></a-input> |         <a-input v-model.trim="inbound.stream.quic.key"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "camouflage" }}'> |     <a-form-item label='{{ i18n "camouflage" }}'> | ||||||
|         <a-select v-model="inbound.stream.quic.type" style="width: 280px;" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.quic.type" style="width: 280px;" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="none">none (not camouflage)</a-select-option> |             <a-select-option value="none">none (not camouflage)</a-select-option> | ||||||
|             <a-select-option value="srtp">srtp (camouflage video call)</a-select-option> |             <a-select-option value="srtp">srtp (camouflage video call)</a-select-option> | ||||||
|             <a-select-option value="utp">utp (camouflage BT download)</a-select-option> |             <a-select-option value="utp">utp (camouflage BT download)</a-select-option> | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| <!-- select stream network --> | <!-- select stream network --> | ||||||
| <a-form layout="inline"> | <a-form layout="inline"> | ||||||
|     <a-form-item label='{{ i18n "transmission" }}'> |     <a-form-item label='{{ i18n "transmission" }}'> | ||||||
|         <a-select v-model="inbound.stream.network" @change="streamNetworkChange" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.network" @change="streamNetworkChange" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="tcp">TCP</a-select-option> |             <a-select-option value="tcp">TCP</a-select-option> | ||||||
|             <a-select-option value="kcp">KCP</a-select-option> |             <a-select-option value="kcp">KCP</a-select-option> | ||||||
|             <a-select-option value="ws">WS</a-select-option> |             <a-select-option value="ws">WS</a-select-option> | ||||||
|  |  | ||||||
|  | @ -13,8 +13,7 @@ | ||||||
| </a-form> | </a-form> | ||||||
| 
 | 
 | ||||||
| <!-- tcp request --> | <!-- tcp request --> | ||||||
| <a-form v-if="inbound.stream.tcp.type === 'http'" | <a-form v-if="inbound.stream.tcp.type === 'http'" layout="inline"> | ||||||
|         layout="inline"> |  | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestVersion" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.requestVersion" }}'> | ||||||
|         <a-input v-model.trim="inbound.stream.tcp.request.version"></a-input> |         <a-input v-model.trim="inbound.stream.tcp.request.version"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -28,8 +27,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'> | ||||||
|         <a-row> |         <a-row> | ||||||
|             <a-button size="small" |             <a-button size="small" @click="inbound.stream.tcp.request.addHeader('Host', 'xxx.com')"> | ||||||
|                       @click="inbound.stream.tcp.request.addHeader('Host', 'xxx.com')"> |  | ||||||
|                 + |                 + | ||||||
|             </a-button> |             </a-button> | ||||||
|         </a-row> |         </a-row> | ||||||
|  | @ -39,8 +37,7 @@ | ||||||
|             <a-input style="width: 50%" v-model.trim="header.value" |             <a-input style="width: 50%" v-model.trim="header.value" | ||||||
|                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> |                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> | ||||||
|                 <template slot="addonAfter"> |                 <template slot="addonAfter"> | ||||||
|                     <a-button size="small" |                     <a-button size="small" @click="inbound.stream.tcp.request.removeHeader(index)"> | ||||||
|                               @click="inbound.stream.tcp.request.removeHeader(index)"> |  | ||||||
|                         - |                         - | ||||||
|                     </a-button> |                     </a-button> | ||||||
|                 </template> |                 </template> | ||||||
|  | @ -50,8 +47,7 @@ | ||||||
| </a-form> | </a-form> | ||||||
| 
 | 
 | ||||||
| <!-- tcp response --> | <!-- tcp response --> | ||||||
| <a-form v-if="inbound.stream.tcp.type === 'http'" | <a-form v-if="inbound.stream.tcp.type === 'http'" layout="inline"> | ||||||
|         layout="inline"> |  | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseVersion" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseVersion" }}'> | ||||||
|         <a-input v-model.trim="inbound.stream.tcp.response.version"></a-input> |         <a-input v-model.trim="inbound.stream.tcp.response.version"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -63,8 +59,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.tcp.responseHeader" }}'> | ||||||
|         <a-row> |         <a-row> | ||||||
|             <a-button size="small" |             <a-button size="small" @click="inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')"> | ||||||
|                       @click="inbound.stream.tcp.response.addHeader('Content-Type', 'application/octet-stream')"> |  | ||||||
|                 + |                 + | ||||||
|             </a-button> |             </a-button> | ||||||
|         </a-row> |         </a-row> | ||||||
|  | @ -74,8 +69,7 @@ | ||||||
|             <a-input style="width: 50%" v-model.trim="header.value" |             <a-input style="width: 50%" v-model.trim="header.value" | ||||||
|                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> |                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> | ||||||
|                 <template slot="addonAfter"> |                 <template slot="addonAfter"> | ||||||
|                     <a-button size="small" |                     <a-button size="small" @click="inbound.stream.tcp.response.removeHeader(index)"> | ||||||
|                               @click="inbound.stream.tcp.response.removeHeader(index)"> |  | ||||||
|                         - |                         - | ||||||
|                     </a-button> |                     </a-button> | ||||||
|                 </template> |                 </template> | ||||||
|  |  | ||||||
|  | @ -10,8 +10,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'> |     <a-form-item label='{{ i18n "pages.inbounds.stream.general.requestHeader" }}'> | ||||||
|         <a-row> |         <a-row> | ||||||
|             <a-button size="small" |             <a-button size="small" @click="inbound.stream.ws.addHeader('Host', '')"> | ||||||
|                       @click="inbound.stream.ws.addHeader('Host', '')"> |  | ||||||
|                 + |                 + | ||||||
|             </a-button> |             </a-button> | ||||||
|         </a-row> |         </a-row> | ||||||
|  | @ -21,8 +20,7 @@ | ||||||
|             <a-input style="width: 50%" v-model.trim="header.value" |             <a-input style="width: 50%" v-model.trim="header.value" | ||||||
|                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> |                      addon-before='{{ i18n "pages.inbounds.stream.general.value" }}'> | ||||||
|                 <template slot="addonAfter"> |                 <template slot="addonAfter"> | ||||||
|                     <a-button size="small" |                     <a-button size="small" @click="inbound.stream.ws.removeHeader(index)"> | ||||||
|                               @click="inbound.stream.ws.removeHeader(index)"> |  | ||||||
|                         - |                         - | ||||||
|                     </a-button> |                     </a-button> | ||||||
|                 </template> |                 </template> | ||||||
|  |  | ||||||
|  | @ -37,18 +37,18 @@ | ||||||
|         <a-input v-model.trim="inbound.stream.tls.server" style="width: 250px"></a-input> |         <a-input v-model.trim="inbound.stream.tls.server" style="width: 250px"></a-input> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="CipherSuites"> |     <a-form-item label="CipherSuites"> | ||||||
|         <a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value="">auto</a-select-option> |             <a-select-option value="">auto</a-select-option> | ||||||
|             <a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="MinVersion"> |     <a-form-item label="MinVersion"> | ||||||
|         <a-select v-model="inbound.stream.tls.minVersion" style="width: 60px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.tls.minVersion" style="width: 60px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="MaxVersion"> |     <a-form-item label="MaxVersion"> | ||||||
|         <a-select v-model="inbound.stream.tls.maxVersion" style="width: 60px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |         <a-select v-model="inbound.stream.tls.maxVersion" style="width: 60px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  | @ -57,7 +57,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="uTLS"> |     <a-form-item label="uTLS"> | ||||||
|         <a-select v-model="inbound.stream.tls.settings.fingerprint" |         <a-select v-model="inbound.stream.tls.settings.fingerprint" | ||||||
|                   style="width: 170px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                   style="width: 170px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option value=''>None</a-select-option> |             <a-select-option value=''>None</a-select-option> | ||||||
|             <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|  | @ -147,7 +147,7 @@ | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|     <a-form-item label="uTLS"> |     <a-form-item label="uTLS"> | ||||||
|         <a-select v-model="inbound.stream.reality.settings.fingerprint"  |         <a-select v-model="inbound.stream.reality.settings.fingerprint"  | ||||||
|                     style="width: 135px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                     style="width: 135px" :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|             <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option> |             <a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option> | ||||||
|         </a-select> |         </a-select> | ||||||
|     </a-form-item> |     </a-form-item> | ||||||
|  |  | ||||||
|  | @ -29,7 +29,9 @@ | ||||||
|     <a-tag v-if="!isClientEnabled(record, client.email)" color="red">{{ i18n "depleted" }}</a-tag> |     <a-tag v-if="!isClientEnabled(record, client.email)" color="red">{{ i18n "depleted" }}</a-tag> | ||||||
| </template>                                     | </template>                                     | ||||||
| <template slot="traffic" slot-scope="text, client"> | <template slot="traffic" slot-scope="text, client"> | ||||||
|     <a-tag color="blue">[[ sizeFormat(getUpStats(record, client.email)) ]] / [[ sizeFormat(getDownStats(record, client.email)) ]]</a-tag> |     <a-tag color="blue"> | ||||||
|  |         [[ sizeFormat(getUpStats(record, client.email)) ]] / [[ sizeFormat(getDownStats(record, client.email)) ]] | ||||||
|  |     </a-tag> | ||||||
|     <template v-if="client._totalGB > 0"> |     <template v-if="client._totalGB > 0"> | ||||||
|         <a-tag v-if="isTrafficExhausted(record, client.email)" color="red">[[client._totalGB]] GB</a-tag> |         <a-tag v-if="isTrafficExhausted(record, client.email)" color="red">[[client._totalGB]] GB</a-tag> | ||||||
|         <a-tag v-else color="cyan">[[client._totalGB]] GB</a-tag> |         <a-tag v-else color="cyan">[[client._totalGB]] GB</a-tag> | ||||||
|  | @ -42,7 +44,9 @@ | ||||||
|             [[ DateUtil.formatMillis(client._expiryTime) ]] |             [[ DateUtil.formatMillis(client._expiryTime) ]] | ||||||
|         </a-tag> |         </a-tag> | ||||||
|     </template> |     </template> | ||||||
|     <a-tag v-else-if="client.expiryTime < 0" color="cyan">[[ client._expiryTime ]] {{ i18n "pages.client.days" }}</a-tag> |     <a-tag v-else-if="client.expiryTime < 0" color="cyan"> | ||||||
|  |         [[ client._expiryTime ]] {{ i18n "pages.client.days" }} | ||||||
|  |     </a-tag> | ||||||
|     <a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag> |     <a-tag v-else color="green">{{ i18n "indefinite" }}</a-tag> | ||||||
| </template> | </template> | ||||||
| {{end}} | {{end}} | ||||||
|  | @ -3,12 +3,13 @@ | ||||||
|     v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}' |     v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}' | ||||||
|     :closable="true" |     :closable="true" | ||||||
|     :mask-closable="true" |     :mask-closable="true" | ||||||
|     :class="siderDrawer.isDarkTheme ? darkClass : ''" |     :class="themeSwitcher.darkCardClass" | ||||||
|     :footer="null" |     :footer="null" | ||||||
|     width="600px" |     width="600px" | ||||||
|     > |     > | ||||||
|     <table style="margin-bottom: 10px; width: 100%;"> |     <table style="margin-bottom: 10px; width: 100%;"> | ||||||
|         <tr><td> |         <tr> | ||||||
|  |             <td> | ||||||
|                 <table> |                 <table> | ||||||
|                     <tr><td>{{ i18n "protocol" }}</td><td><a-tag color="green">[[ dbInbound.protocol ]]</a-tag></td></tr> |                     <tr><td>{{ i18n "protocol" }}</td><td><a-tag color="green">[[ dbInbound.protocol ]]</a-tag></td></tr> | ||||||
|                     <tr><td>{{ i18n "pages.inbounds.address" }}</td><td><a-tag color="blue">[[ dbInbound.address ]]</a-tag></td></tr> |                     <tr><td>{{ i18n "pages.inbounds.address" }}</td><td><a-tag color="blue">[[ dbInbound.address ]]</a-tag></td></tr> | ||||||
|  | @ -20,6 +21,7 @@ | ||||||
|                     <tr> |                     <tr> | ||||||
|                         <td>{{ i18n "transmission" }}</td><td><a-tag color="green">[[ inbound.network ]]</a-tag></td> |                         <td>{{ i18n "transmission" }}</td><td><a-tag color="green">[[ inbound.network ]]</a-tag></td> | ||||||
|                     </tr> |                     </tr> | ||||||
|  | 
 | ||||||
|                     <template v-if="inbound.isTcp || inbound.isWs || inbound.isH2"> |                     <template v-if="inbound.isTcp || inbound.isWs || inbound.isH2"> | ||||||
|                         <tr v-if="inbound.host"><td>{{ i18n "host" }}</td><td><a-tag color="green">[[ inbound.host ]]</a-tag></td></tr> |                         <tr v-if="inbound.host"><td>{{ i18n "host" }}</td><td><a-tag color="green">[[ inbound.host ]]</a-tag></td></tr> | ||||||
|                         <tr v-else><td>{{ i18n "host" }}</td><td><a-tag color="orange">{{ i18n "none" }}</a-tag></td></tr> |                         <tr v-else><td>{{ i18n "host" }}</td><td><a-tag color="orange">{{ i18n "none" }}</a-tag></td></tr> | ||||||
|  | @ -44,7 +46,8 @@ | ||||||
|                         <tr><td>grpc multiMode</td><td><a-tag color="green">[[ inbound.stream.grpc.multiMode ]]</a-tag></td></tr> |                         <tr><td>grpc multiMode</td><td><a-tag color="green">[[ inbound.stream.grpc.multiMode ]]</a-tag></td></tr> | ||||||
|                     </template> |                     </template> | ||||||
|                 </table> |                 </table> | ||||||
|         </td></tr> |             </td> | ||||||
|  |         </tr> | ||||||
|         <tr colspan="2" v-if="dbInbound.hasLink()"> |         <tr colspan="2" v-if="dbInbound.hasLink()"> | ||||||
|             <td v-if="inbound.tls"> |             <td v-if="inbound.tls"> | ||||||
|                 tls: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br /> |                 tls: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br /> | ||||||
|  | @ -58,7 +61,8 @@ | ||||||
|                 reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br /> |                 reality: <a-tag color="green">{{ i18n "enabled" }}</a-tag><br /> | ||||||
|                 reality {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag> |                 reality {{ i18n "domainName" }}: <a-tag :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag> | ||||||
|             </td> |             </td> | ||||||
|                 <td v-else>tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag> |             <td v-else> | ||||||
|  |                 tls: <a-tag color="red">{{ i18n "disabled" }}</a-tag> | ||||||
|             </td> |             </td> | ||||||
|         </tr> |         </tr> | ||||||
|     </table> |     </table> | ||||||
|  | @ -124,7 +128,8 @@ | ||||||
|                 <th>{{ i18n "encryption" }}</th> |                 <th>{{ i18n "encryption" }}</th> | ||||||
|                 <th>{{ i18n "password" }}</th> |                 <th>{{ i18n "password" }}</th> | ||||||
|                 <th>{{ i18n "pages.inbounds.network" }}</th> |                 <th>{{ i18n "pages.inbounds.network" }}</th> | ||||||
|             </tr><tr> |             </tr> | ||||||
|  |             <tr> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.method ]]</a-tag></td> | ||||||
|                 <td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td> |                 <td><a-tag color="blue">[[ inbound.settings.password ]]</a-tag></td> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td> | ||||||
|  | @ -136,7 +141,8 @@ | ||||||
|                 <th>{{ i18n "pages.inbounds.destinationPort" }}</th> |                 <th>{{ i18n "pages.inbounds.destinationPort" }}</th> | ||||||
|                 <th>{{ i18n "pages.inbounds.network" }}</th> |                 <th>{{ i18n "pages.inbounds.network" }}</th> | ||||||
|                 <th>FollowRedirect</th> |                 <th>FollowRedirect</th> | ||||||
|             </tr><tr> |             </tr> | ||||||
|  |             <tr> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.address ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.address ]]</a-tag></td> | ||||||
|                 <td><a-tag color="blue">[[ inbound.settings.port ]]</a-tag></td> |                 <td><a-tag color="blue">[[ inbound.settings.port ]]</a-tag></td> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.network ]]</a-tag></td> | ||||||
|  | @ -149,15 +155,18 @@ | ||||||
|                 <th>{{ i18n "password" }} Auth</th> |                 <th>{{ i18n "password" }} Auth</th> | ||||||
|                 <th>{{ i18n "pages.inbounds.enable" }} udp</th> |                 <th>{{ i18n "pages.inbounds.enable" }} udp</th> | ||||||
|                 <th>IP</th> |                 <th>IP</th> | ||||||
|             </tr><tr> |             </tr> | ||||||
|  |             <tr> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.auth ]]</a-tag></td> | ||||||
|                 <td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td> |                 <td><a-tag color="blue">[[ inbound.settings.udp]]</a-tag></td> | ||||||
|                 <td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td> |                 <td><a-tag color="green">[[ inbound.settings.ip ]]</a-tag></td> | ||||||
|             </tr><tr v-if="inbound.settings.auth == 'password'"> |             </tr> | ||||||
|  |             <tr v-if="inbound.settings.auth == 'password'"> | ||||||
|                 <td> </td> |                 <td> </td> | ||||||
|                 <td>{{ i18n "username" }}</td> |                 <td>{{ i18n "username" }}</td> | ||||||
|                 <td>{{ i18n "password" }}</td> |                 <td>{{ i18n "password" }}</td> | ||||||
|             </tr><tr v-for="account,index in inbound.settings.accounts"> |             </tr> | ||||||
|  |             <tr v-for="account,index in inbound.settings.accounts"> | ||||||
|                 <td><a-tag color="green">[[ index ]]</a-tag></td> |                 <td><a-tag color="green">[[ index ]]</a-tag></td> | ||||||
|                 <td><a-tag color="blue">[[ account.user ]]</a-tag></td> |                 <td><a-tag color="blue">[[ account.user ]]</a-tag></td> | ||||||
|                 <td><a-tag color="green">[[ account.pass ]]</a-tag></td> |                 <td><a-tag color="green">[[ account.pass ]]</a-tag></td> | ||||||
|  | @ -169,7 +178,8 @@ | ||||||
|                 <th> </th> |                 <th> </th> | ||||||
|                 <th>{{ i18n "username" }}</th> |                 <th>{{ i18n "username" }}</th> | ||||||
|                 <th>{{ i18n "password" }}</th> |                 <th>{{ i18n "password" }}</th> | ||||||
|             </tr><tr v-for="account,index in inbound.settings.accounts"> |             </tr> | ||||||
|  |             <tr v-for="account,index in inbound.settings.accounts"> | ||||||
|                 <td><a-tag color="green">[[ index ]]</a-tag></td> |                 <td><a-tag color="green">[[ index ]]</a-tag></td> | ||||||
|                 <td><a-tag color="blue">[[ account.user ]]</a-tag></td> |                 <td><a-tag color="blue">[[ account.user ]]</a-tag></td> | ||||||
|                 <td><a-tag color="green">[[ account.pass ]]</a-tag></td> |                 <td><a-tag color="green">[[ account.pass ]]</a-tag></td> | ||||||
|  | @ -184,6 +194,7 @@ | ||||||
|     </div> |     </div> | ||||||
| </a-modal> | </a-modal> | ||||||
| <script> | <script> | ||||||
|  | 
 | ||||||
|     const infoModal = { |     const infoModal = { | ||||||
|         visible: false, |         visible: false, | ||||||
|         inbound: new Inbound(), |         inbound: new Inbound(), | ||||||
|  | @ -268,7 +279,6 @@ | ||||||
|                 else return 'red' |                 else return 'red' | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|          |  | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| {{define "inboundModal"}} | {{define "inboundModal"}} | ||||||
| <a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok" | <a-modal id="inbound-modal" v-model="inModal.visible" :title="inModal.title" @ok="inModal.ok" | ||||||
|          :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false" |          :confirm-loading="inModal.confirmLoading" :closable="true" :mask-closable="false" | ||||||
|          :class="siderDrawer.isDarkTheme ? darkClass : ''" |          :class="themeSwitcher.darkCardClass" | ||||||
|          :ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'> |          :ok-text="inModal.okText" cancel-text='{{ i18n "close" }}'> | ||||||
|     {{template "form/inbound"}} |     {{template "form/inbound"}} | ||||||
| </a-modal> | </a-modal> | ||||||
|  |  | ||||||
|  | @ -12,10 +12,11 @@ | ||||||
|         margin-top: 10px; |         margin-top: 10px; | ||||||
|     } |     } | ||||||
| </style> | </style> | ||||||
|  | 
 | ||||||
| <body> | <body> | ||||||
| <a-layout id="app" v-cloak> | <a-layout id="app" v-cloak> | ||||||
|     {{ template "commonSider" . }} |     {{ template "commonSider" . }} | ||||||
|     <a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''"> |     <a-layout id="content-layout" :style="themeSwitcher.bgStyle"> | ||||||
|         <a-layout-content> |         <a-layout-content> | ||||||
|             <a-spin :spinning="spinning" :delay="500" tip="loading"> |             <a-spin :spinning="spinning" :delay="500" tip="loading"> | ||||||
|                 <transition name="list" appear> |                 <transition name="list" appear> | ||||||
|  | @ -24,7 +25,7 @@ | ||||||
|                     </a-tag> |                     </a-tag> | ||||||
|                 </transition> |                 </transition> | ||||||
|                 <transition name="list" appear> |                 <transition name="list" appear> | ||||||
|                     <a-card hoverable style="margin-bottom: 20px;" :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                     <a-card hoverable style="margin-bottom: 20px;" :class="themeSwitcher.darkCardClass"> | ||||||
|                         <a-row> |                         <a-row> | ||||||
|                             <a-col :xs="24" :sm="24" :lg="12"> |                             <a-col :xs="24" :sm="24" :lg="12"> | ||||||
|                                 {{ i18n "pages.inbounds.totalDownUp" }}: |                                 {{ i18n "pages.inbounds.totalDownUp" }}: | ||||||
|  | @ -41,19 +42,19 @@ | ||||||
|                             <a-col :xs="24" :sm="24" :lg="12"> |                             <a-col :xs="24" :sm="24" :lg="12"> | ||||||
|                                 {{ i18n "clients" }}: |                                 {{ i18n "clients" }}: | ||||||
|                                 <a-tag color="green">[[ total.clients ]]</a-tag> |                                 <a-tag color="green">[[ total.clients ]]</a-tag> | ||||||
|                                 <a-popover title='{{ i18n "disabled" }}' :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                 <a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                     <template slot="content"> |                                     <template slot="content"> | ||||||
|                                         <p v-for="clientEmail in total.deactive">[[ clientEmail ]]</p> |                                         <p v-for="clientEmail in total.deactive">[[ clientEmail ]]</p> | ||||||
|                                     </template> |                                     </template> | ||||||
|                                     <a-tag v-if="total.deactive.length">[[ total.deactive.length ]]</a-tag> |                                     <a-tag v-if="total.deactive.length">[[ total.deactive.length ]]</a-tag> | ||||||
|                                 </a-popover> |                                 </a-popover> | ||||||
|                                 <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                 <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                     <template slot="content"> |                                     <template slot="content"> | ||||||
|                                         <p v-for="clientEmail in total.depleted">[[ clientEmail ]]</p> |                                         <p v-for="clientEmail in total.depleted">[[ clientEmail ]]</p> | ||||||
|                                     </template> |                                     </template> | ||||||
|                                     <a-tag color="red" v-if="total.depleted.length">[[ total.depleted.length ]]</a-tag> |                                     <a-tag color="red" v-if="total.depleted.length">[[ total.depleted.length ]]</a-tag> | ||||||
|                                 </a-popover> |                                 </a-popover> | ||||||
|                                 <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                 <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                     <template slot="content"> |                                     <template slot="content"> | ||||||
|                                         <p v-for="clientEmail in total.expiring">[[ clientEmail ]]</p> |                                         <p v-for="clientEmail in total.expiring">[[ clientEmail ]]</p> | ||||||
|                                     </template> |                                     </template> | ||||||
|  | @ -64,14 +65,14 @@ | ||||||
|                     </a-card> |                     </a-card> | ||||||
|                 </transition> |                 </transition> | ||||||
|                 <transition name="list" appear> |                 <transition name="list" appear> | ||||||
|                     <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                     <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                         <div slot="title"> |                         <div slot="title"> | ||||||
|                             <a-row> |                             <a-row> | ||||||
|                                 <a-col :xs="24" :sm="24" :lg="12"> |                                 <a-col :xs="24" :sm="24" :lg="12"> | ||||||
|                                     <a-button type="primary" icon="plus" @click="openAddInbound">{{ i18n "pages.inbounds.addInbound" }}</a-button> |                                     <a-button type="primary" icon="plus" @click="openAddInbound">{{ i18n "pages.inbounds.addInbound" }}</a-button> | ||||||
|                                     <a-dropdown :trigger="['click']"> |                                     <a-dropdown :trigger="['click']"> | ||||||
|                                         <a-button type="primary" icon="menu">{{ i18n "pages.inbounds.generalActions" }}</a-button> |                                         <a-button type="primary" icon="menu">{{ i18n "pages.inbounds.generalActions" }}</a-button> | ||||||
|                                         <a-menu slot="overlay" @click="a => generalActions(a)" :theme="siderDrawer.theme"> |                                         <a-menu slot="overlay" @click="a => generalActions(a)" :theme="themeSwitcher.currentTheme"> | ||||||
|                                             <a-menu-item key="export"> |                                             <a-menu-item key="export"> | ||||||
|                                                 <a-icon type="export"></a-icon> |                                                 <a-icon type="export"></a-icon> | ||||||
|                                                 {{ i18n "pages.inbounds.export" }} |                                                 {{ i18n "pages.inbounds.export" }} | ||||||
|  | @ -96,7 +97,7 @@ | ||||||
|                                               style="width: 65px;" |                                               style="width: 65px;" | ||||||
|                                               v-if="isRefreshEnabled" |                                               v-if="isRefreshEnabled" | ||||||
|                                               @change="changeRefreshInterval" |                                               @change="changeRefreshInterval" | ||||||
|                                               :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                                               :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                                         <a-select-option v-for="key in [5,10,30,60]" :value="key*1000">[[ key ]]s</a-select-option> |                                         <a-select-option v-for="key in [5,10,30,60]" :value="key*1000">[[ key ]]s</a-select-option> | ||||||
|                                     </a-select> |                                     </a-select> | ||||||
|                                     <a-icon type="sync" :spin="refreshing" @click="manualRefresh" style="margin: 0 5px;"></a-icon> |                                     <a-icon type="sync" :spin="refreshing" @click="manualRefresh" style="margin: 0 5px;"></a-icon> | ||||||
|  | @ -115,7 +116,7 @@ | ||||||
|                                 <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']"> | ||||||
|                                     <a @click="e => e.preventDefault()">{{ i18n "pages.inbounds.operate" }}</a> |                                     <a @click="e => e.preventDefault()">{{ i18n "pages.inbounds.operate" }}</a> | ||||||
|                                     <a-menu slot="overlay" @click="a => clickAction(a, dbInbound)" :theme="siderDrawer.theme"> |                                     <a-menu slot="overlay" @click="a => clickAction(a, dbInbound)" :theme="themeSwitcher.currentTheme"> | ||||||
|                                         <a-menu-item key="edit"> |                                         <a-menu-item key="edit"> | ||||||
|                                             <a-icon type="edit"></a-icon> |                                             <a-icon type="edit"></a-icon> | ||||||
|                                             {{ i18n "edit" }} |                                             {{ i18n "edit" }} | ||||||
|  | @ -174,19 +175,19 @@ | ||||||
|                             <template slot="clients" slot-scope="text, dbInbound"> |                             <template slot="clients" slot-scope="text, dbInbound"> | ||||||
|                                 <template v-if="clientCount[dbInbound.id]"> |                                 <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="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                     <a-popover title='{{ i18n "disabled" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                         <template slot="content"> |                                         <template slot="content"> | ||||||
|                                             <p v-for="clientEmail in clientCount[dbInbound.id].deactive">[[ clientEmail ]]</p> |                                             <p v-for="clientEmail in clientCount[dbInbound.id].deactive">[[ clientEmail ]]</p> | ||||||
|                                         </template> |                                         </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> | ||||||
|                                     <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                     <a-popover title='{{ i18n "depleted" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                         <template slot="content"> |                                         <template slot="content"> | ||||||
|                                             <p v-for="clientEmail in clientCount[dbInbound.id].depleted">[[ clientEmail ]]</p> |                                             <p v-for="clientEmail in clientCount[dbInbound.id].depleted">[[ clientEmail ]]</p> | ||||||
|                                         </template> |                                         </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> | ||||||
|                                     <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="siderDrawer.isDarkTheme ? 'ant-dark' : ''"> |                                     <a-popover title='{{ i18n "depletingSoon" }}' :overlay-class-name="themeSwitcher.darkClass"> | ||||||
|                                         <template slot="content"> |                                         <template slot="content"> | ||||||
|                                             <p v-for="clientEmail in clientCount[dbInbound.id].expiring">[[ clientEmail ]]</p> |                                             <p v-for="clientEmail in clientCount[dbInbound.id].expiring">[[ clientEmail ]]</p> | ||||||
|                                         </template> |                                         </template> | ||||||
|  | @ -244,6 +245,7 @@ | ||||||
|     </a-layout> |     </a-layout> | ||||||
| </a-layout> | </a-layout> | ||||||
| {{template "js" .}} | {{template "js" .}} | ||||||
|  | {{template "component/themeSwitcher" .}} | ||||||
| <script> | <script> | ||||||
| 
 | 
 | ||||||
|     const columns = [{ |     const columns = [{ | ||||||
|  | @ -315,7 +317,7 @@ | ||||||
|         delimiters: ['[[', ']]'], |         delimiters: ['[[', ']]'], | ||||||
|         el: '#app', |         el: '#app', | ||||||
|         data: { |         data: { | ||||||
|             siderDrawer, |             themeSwitcher, | ||||||
|             spinning: false, |             spinning: false, | ||||||
|             inbounds: [], |             inbounds: [], | ||||||
|             dbInbounds: [], |             dbInbounds: [], | ||||||
|  | @ -644,7 +646,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', |                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', |                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => { |                     onOk: () => { | ||||||
|  | @ -659,7 +661,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.deleteInbound"}}', |                     title: '{{ i18n "pages.inbounds.deleteInbound"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.deleteInboundContent"}}', |                     content: '{{ i18n "pages.inbounds.deleteInboundContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "delete"}}', |                     okText: '{{ i18n "delete"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit('/xui/inbound/del/' + dbInboundId), |                     onOk: () => this.submit('/xui/inbound/del/' + dbInboundId), | ||||||
|  | @ -671,7 +673,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.deleteInbound"}}', |                     title: '{{ i18n "pages.inbounds.deleteInbound"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.deleteInboundContent"}}', |                     content: '{{ i18n "pages.inbounds.deleteInboundContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "delete"}}', |                     okText: '{{ i18n "delete"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit(`/xui/inbound/${dbInboundId}/delClient/${clientId}`), |                     onOk: () => this.submit(`/xui/inbound/${dbInboundId}/delClient/${clientId}`), | ||||||
|  | @ -736,7 +738,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', |                     title: '{{ i18n "pages.inbounds.resetTraffic"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', |                     content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit('/xui/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email), |                     onOk: () => this.submit('/xui/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email), | ||||||
|  | @ -746,7 +748,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.resetAllTrafficTitle"}}', |                     title: '{{ i18n "pages.inbounds.resetAllTrafficTitle"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.resetAllTrafficContent"}}', |                     content: '{{ i18n "pages.inbounds.resetAllTrafficContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit('/xui/inbound/resetAllTraffics'), |                     onOk: () => this.submit('/xui/inbound/resetAllTraffics'), | ||||||
|  | @ -756,7 +758,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: dbInboundId > 0 ? '{{ i18n "pages.inbounds.resetInboundClientTrafficTitle"}}' : '{{ i18n "pages.inbounds.resetAllClientTrafficTitle"}}', |                     title: dbInboundId > 0 ? '{{ i18n "pages.inbounds.resetInboundClientTrafficTitle"}}' : '{{ i18n "pages.inbounds.resetAllClientTrafficTitle"}}', | ||||||
|                     content: dbInboundId > 0 ? '{{ i18n "pages.inbounds.resetInboundClientTrafficContent"}}' : '{{ i18n "pages.inbounds.resetAllClientTrafficContent"}}', |                     content: dbInboundId > 0 ? '{{ i18n "pages.inbounds.resetInboundClientTrafficContent"}}' : '{{ i18n "pages.inbounds.resetAllClientTrafficContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId), |                     onOk: () => this.submit('/xui/inbound/resetAllClientTraffics/' + dbInboundId), | ||||||
|  | @ -766,7 +768,7 @@ | ||||||
|                 this.$confirm({ |                 this.$confirm({ | ||||||
|                     title: '{{ i18n "pages.inbounds.delDepletedClientsTitle"}}', |                     title: '{{ i18n "pages.inbounds.delDepletedClientsTitle"}}', | ||||||
|                     content: '{{ i18n "pages.inbounds.delDepletedClientsContent"}}', |                     content: '{{ i18n "pages.inbounds.delDepletedClientsContent"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     okText: '{{ i18n "reset"}}', |                     okText: '{{ i18n "reset"}}', | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: () => this.submit('/xui/inbound/delDepletedClients/' + dbInboundId), |                     onOk: () => this.submit('/xui/inbound/delDepletedClients/' + dbInboundId), | ||||||
|  | @ -876,6 +878,7 @@ | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| {{template "inboundModal"}} | {{template "inboundModal"}} | ||||||
|  | @ -885,5 +888,6 @@ | ||||||
| {{template "inboundInfoModal"}} | {{template "inboundInfoModal"}} | ||||||
| {{template "clientsModal"}} | {{template "clientsModal"}} | ||||||
| {{template "clientsBulkModal"}} | {{template "clientsBulkModal"}} | ||||||
|  | 
 | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
|  | @ -16,29 +16,30 @@ | ||||||
|         color: hsla(0, 0%, 100%, .65); |         color: hsla(0, 0%, 100%, .65); | ||||||
|     } |     } | ||||||
| </style> | </style> | ||||||
|  | 
 | ||||||
| <body> | <body> | ||||||
| <a-layout id="app" v-cloak> | <a-layout id="app" v-cloak> | ||||||
|     {{ template "commonSider" . }} |     {{ template "commonSider" . }} | ||||||
|     <a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''"> |     <a-layout id="content-layout" :style="themeSwitcher.bgStyle"> | ||||||
|         <a-layout-content> |         <a-layout-content> | ||||||
|             <a-spin :spinning="spinning" :delay="200" :tip="loadingTip"/> |             <a-spin :spinning="spinning" :delay="200" :tip="loadingTip"/> | ||||||
|             <transition name="list" appear> |             <transition name="list" appear> | ||||||
|                 <a-row> |                 <a-row> | ||||||
|                     <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                     <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                         <a-row> |                         <a-row> | ||||||
|                             <a-col :sm="24" :md="12"> |                             <a-col :sm="24" :md="12"> | ||||||
|                                 <a-row> |                                 <a-row> | ||||||
|                                     <a-col :span="12" style="text-align: center"> |                                     <a-col :span="12" style="text-align: center"> | ||||||
|                                         <a-progress type="dashboard" status="normal" |                                         <a-progress type="dashboard" status="normal" | ||||||
|                                                     :stroke-color="status.cpu.color" |                                                     :stroke-color="status.cpu.color" | ||||||
|                                                     :class="siderDrawer.isDarkTheme ? darkClass : ''" |                                                     :class="themeSwitcher.darkCardClass" | ||||||
|                                                     :percent="status.cpu.percent"></a-progress> |                                                     :percent="status.cpu.percent"></a-progress> | ||||||
|                                         <div>CPU</div> |                                         <div>CPU</div> | ||||||
|                                     </a-col> |                                     </a-col> | ||||||
|                                     <a-col :span="12" style="text-align: center"> |                                     <a-col :span="12" style="text-align: center"> | ||||||
|                                         <a-progress type="dashboard" status="normal" |                                         <a-progress type="dashboard" status="normal" | ||||||
|                                                     :stroke-color="status.mem.color" |                                                     :stroke-color="status.mem.color" | ||||||
|                                                     :class="siderDrawer.isDarkTheme ? darkClass : ''" |                                                     :class="themeSwitcher.darkCardClass" | ||||||
|                                                     :percent="status.mem.percent"></a-progress> |                                                     :percent="status.mem.percent"></a-progress> | ||||||
|                                         <div> |                                         <div> | ||||||
|                                             {{ i18n "pages.index.memory"}}: [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]] |                                             {{ i18n "pages.index.memory"}}: [[ sizeFormat(status.mem.current) ]] / [[ sizeFormat(status.mem.total) ]] | ||||||
|  | @ -51,7 +52,7 @@ | ||||||
|                                     <a-col :span="12" style="text-align: center"> |                                     <a-col :span="12" style="text-align: center"> | ||||||
|                                         <a-progress type="dashboard" status="normal" |                                         <a-progress type="dashboard" status="normal" | ||||||
|                                                     :stroke-color="status.swap.color" |                                                     :stroke-color="status.swap.color" | ||||||
|                                                     :class="siderDrawer.isDarkTheme ? darkClass : ''" |                                                     :class="themeSwitcher.darkCardClass" | ||||||
|                                                     :percent="status.swap.percent"></a-progress> |                                                     :percent="status.swap.percent"></a-progress> | ||||||
|                                         <div> |                                         <div> | ||||||
|                                             Swap: [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]] |                                             Swap: [[ sizeFormat(status.swap.current) ]] / [[ sizeFormat(status.swap.total) ]] | ||||||
|  | @ -60,7 +61,7 @@ | ||||||
|                                     <a-col :span="12" style="text-align: center"> |                                     <a-col :span="12" style="text-align: center"> | ||||||
|                                         <a-progress type="dashboard" status="normal" |                                         <a-progress type="dashboard" status="normal" | ||||||
|                                                     :stroke-color="status.disk.color" |                                                     :stroke-color="status.disk.color" | ||||||
|                                                     :class="siderDrawer.isDarkTheme ? darkClass : ''" |                                                     :class="themeSwitcher.darkCardClass" | ||||||
|                                                     :percent="status.disk.percent"></a-progress> |                                                     :percent="status.disk.percent"></a-progress> | ||||||
|                                         <div> |                                         <div> | ||||||
|                                             {{ i18n "pages.index.hard"}}: [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]] |                                             {{ i18n "pages.index.hard"}}: [[ sizeFormat(status.disk.current) ]] / [[ sizeFormat(status.disk.total) ]] | ||||||
|  | @ -75,14 +76,14 @@ | ||||||
|             <transition name="list" appear> |             <transition name="list" appear> | ||||||
|                 <a-row> |                 <a-row> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             3x-ui: <a href="https://github.com/MHSanaei/3x-ui/releases" target="_blank"><a-tag color="green">v{{ .cur_ver }}</a-tag></a> |                             3x-ui: <a href="https://github.com/MHSanaei/3x-ui/releases" target="_blank"><a-tag color="green">v{{ .cur_ver }}</a-tag></a> | ||||||
|                             Xray: <a-tag color="green" style="cursor: pointer;" @click="openSelectV2rayVersion">v[[ status.xray.version ]]</a-tag> |                             Xray: <a-tag color="green" style="cursor: pointer;" @click="openSelectV2rayVersion">v[[ status.xray.version ]]</a-tag> | ||||||
|                             Telegram: <a href="https://t.me/panel3xui" target="_blank"><a-tag color="green">@panel3xui</a-tag></a> |                             Telegram: <a href="https://t.me/panel3xui" target="_blank"><a-tag color="green">@panel3xui</a-tag></a> | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             {{ i18n "pages.index.operationHours" }}: |                             {{ i18n "pages.index.operationHours" }}: | ||||||
|                             <a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag> |                             <a-tag color="green">[[ formatSecond(status.uptime) ]]</a-tag> | ||||||
|                             <a-tooltip> |                             <a-tooltip> | ||||||
|  | @ -94,7 +95,7 @@ | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             {{ i18n "pages.index.xrayStatus" }}: |                             {{ i18n "pages.index.xrayStatus" }}: | ||||||
|                             <a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag> |                             <a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag> | ||||||
|                             <a-tooltip v-if="status.xray.state === State.Error"> |                             <a-tooltip v-if="status.xray.state === State.Error"> | ||||||
|  | @ -109,7 +110,7 @@ | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             {{ i18n "menu.link" }}: |                             {{ i18n "menu.link" }}: | ||||||
|                             <a-tag color="blue" style="cursor: pointer;" @click="openLogs(20)">{{ i18n "pages.index.logs" }}</a-tag> |                             <a-tag color="blue" style="cursor: pointer;" @click="openLogs(20)">{{ i18n "pages.index.logs" }}</a-tag> | ||||||
|                             <a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag> |                             <a-tag color="blue" style="cursor: pointer;" @click="openConfig">{{ i18n "pages.index.config" }}</a-tag> | ||||||
|  | @ -117,12 +118,12 @@ | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             {{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]] |                             {{ i18n "pages.index.systemLoad" }}: [[ status.loads[0] ]] | [[ status.loads[1] ]] | [[ status.loads[2] ]] | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             TCP / UDP {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]] |                             TCP / UDP {{ i18n "pages.index.connectionCount" }}: [[ status.tcpCount ]] / [[ status.udpCount ]] | ||||||
|                             <a-tooltip> |                             <a-tooltip> | ||||||
|                                 <template slot="title"> |                                 <template slot="title"> | ||||||
|  | @ -133,7 +134,7 @@ | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             <a-row> |                             <a-row> | ||||||
|                                 <a-col :span="12"> |                                 <a-col :span="12"> | ||||||
|                                     <a-icon type="arrow-up"></a-icon> |                                     <a-icon type="arrow-up"></a-icon> | ||||||
|  | @ -159,7 +160,7 @@ | ||||||
|                         </a-card> |                         </a-card> | ||||||
|                     </a-col> |                     </a-col> | ||||||
|                     <a-col :sm="24" :md="12"> |                     <a-col :sm="24" :md="12"> | ||||||
|                         <a-card hoverable :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                         <a-card hoverable :class="themeSwitcher.darkCardClass"> | ||||||
|                             <a-row> |                             <a-row> | ||||||
|                                 <a-col :span="12"> |                                 <a-col :span="12"> | ||||||
|                                     <a-icon type="cloud-upload"></a-icon> |                                     <a-icon type="cloud-upload"></a-icon> | ||||||
|  | @ -191,7 +192,7 @@ | ||||||
| 
 | 
 | ||||||
|     <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}' |     <a-modal id="version-modal" v-model="versionModal.visible" title='{{ i18n "pages.index.xraySwitch" }}' | ||||||
|              :closable="true" @ok="() => versionModal.visible = false" |              :closable="true" @ok="() => versionModal.visible = false" | ||||||
|              :class="siderDrawer.isDarkTheme ? darkClass : ''" |              :class="themeSwitcher.darkCardClass" | ||||||
|              footer=""> |              footer=""> | ||||||
|         <h2>{{ i18n "pages.index.xraySwitchClick"}}</h2> |         <h2>{{ i18n "pages.index.xraySwitchClick"}}</h2> | ||||||
|         <h2>{{ i18n "pages.index.xraySwitchClickDesk"}}</h2> |         <h2>{{ i18n "pages.index.xraySwitchClickDesk"}}</h2> | ||||||
|  | @ -205,7 +206,7 @@ | ||||||
| 
 | 
 | ||||||
|     <a-modal id="log-modal" v-model="logModal.visible" title="X-UI logs" |     <a-modal id="log-modal" v-model="logModal.visible" title="X-UI logs" | ||||||
|              :closable="true" @ok="() => logModal.visible = false" @cancel="() => logModal.visible = false" |              :closable="true" @ok="() => logModal.visible = false" @cancel="() => logModal.visible = false" | ||||||
|              :class="siderDrawer.isDarkTheme ? darkClass : ''" |              :class="themeSwitcher.darkCardClass" | ||||||
|              width="800px" |              width="800px" | ||||||
|              footer=""> |              footer=""> | ||||||
|         <a-form layout="inline"> |         <a-form layout="inline"> | ||||||
|  | @ -213,7 +214,7 @@ | ||||||
|                 <a-select v-model="logModal.rows" |                 <a-select v-model="logModal.rows" | ||||||
|                 style="width: 80px" |                 style="width: 80px" | ||||||
|                 @change="openLogs(logModal.rows)" |                 @change="openLogs(logModal.rows)" | ||||||
|                 :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''"> |                 :dropdown-class-name="themeSwitcher.darkCardClass"> | ||||||
|                     <a-select-option value="10">10</a-select-option> |                     <a-select-option value="10">10</a-select-option> | ||||||
|                     <a-select-option value="20">20</a-select-option> |                     <a-select-option value="20">20</a-select-option> | ||||||
|                     <a-select-option value="50">50</a-select-option> |                     <a-select-option value="50">50</a-select-option> | ||||||
|  | @ -235,7 +236,7 @@ | ||||||
|     </a-modal> |     </a-modal> | ||||||
| 
 | 
 | ||||||
|     <a-modal id="backup-modal" v-model="backupModal.visible" :title="backupModal.title" |     <a-modal id="backup-modal" v-model="backupModal.visible" :title="backupModal.title" | ||||||
|             :closable="true" :class="siderDrawer.isDarkTheme ? darkClass : ''" |             :closable="true" :class="themeSwitcher.darkCardClass" | ||||||
|             @ok="() => backupModal.hide()" @cancel="() => backupModal.hide()"> |             @ok="() => backupModal.hide()" @cancel="() => backupModal.hide()"> | ||||||
|         <p style="color: inherit; font-size: 16px; padding: 4px 2px;"> |         <p style="color: inherit; font-size: 16px; padding: 4px 2px;"> | ||||||
|             <a-icon type="warning" style="color: inherit; font-size: 20px;"></a-icon> |             <a-icon type="warning" style="color: inherit; font-size: 20px;"></a-icon> | ||||||
|  | @ -253,6 +254,7 @@ | ||||||
| 
 | 
 | ||||||
| </a-layout> | </a-layout> | ||||||
| {{template "js" .}} | {{template "js" .}} | ||||||
|  | {{template "component/themeSwitcher" .}} | ||||||
| {{template "textModal"}} | {{template "textModal"}} | ||||||
| <script> | <script> | ||||||
| 
 | 
 | ||||||
|  | @ -386,7 +388,7 @@ | ||||||
|         delimiters: ['[[', ']]'], |         delimiters: ['[[', ']]'], | ||||||
|         el: '#app', |         el: '#app', | ||||||
|         data: { |         data: { | ||||||
|             siderDrawer, |             themeSwitcher, | ||||||
|             status: new Status(), |             status: new Status(), | ||||||
|             versionModal, |             versionModal, | ||||||
|             logModal, |             logModal, | ||||||
|  | @ -422,7 +424,7 @@ | ||||||
|                     title: '{{ i18n "pages.index.xraySwitchVersionDialog"}}', |                     title: '{{ i18n "pages.index.xraySwitchVersionDialog"}}', | ||||||
|                     content: '{{ i18n "pages.index.xraySwitchVersionDialogDesc"}}' + ` ${version}?`, |                     content: '{{ i18n "pages.index.xraySwitchVersionDialogDesc"}}' + ` ${version}?`, | ||||||
|                     okText: '{{ i18n "confirm"}}', |                     okText: '{{ i18n "confirm"}}', | ||||||
|                     class: siderDrawer.isDarkTheme ? darkClass : '', |                     class: themeSwitcher.darkCardClass, | ||||||
|                     cancelText: '{{ i18n "cancel"}}', |                     cancelText: '{{ i18n "cancel"}}', | ||||||
|                     onOk: async () => { |                     onOk: async () => { | ||||||
|                         versionModal.hide(); |                         versionModal.hide(); | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ | ||||||
| <body> | <body> | ||||||
| <a-layout id="app" v-cloak> | <a-layout id="app" v-cloak> | ||||||
|     {{ template "commonSider" . }} |     {{ template "commonSider" . }} | ||||||
|         <a-layout id="content-layout" :style="siderDrawer.isDarkTheme ? bgDarkStyle : ''"> |     <a-layout id="content-layout" :style="themeSwitcher.bgStyle"> | ||||||
|         <a-layout-content> |         <a-layout-content> | ||||||
|             <a-spin :spinning="spinning" :delay="500" tip="loading"> |             <a-spin :spinning="spinning" :delay="500" tip="loading"> | ||||||
|                 <a-space direction="vertical"> |                 <a-space direction="vertical"> | ||||||
|  | @ -36,9 +36,9 @@ | ||||||
|                         <a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.settings.save" }}</a-button> |                         <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> |                         <a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button> | ||||||
|                     </a-space> |                     </a-space> | ||||||
|                         <a-tabs default-active-key="1" :class="siderDrawer.isDarkTheme ? darkClass : ''" > |                     <a-tabs default-active-key="1" :class="themeSwitcher.darkCardClass" > | ||||||
|                         <a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings"}}'> |                         <a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings"}}'> | ||||||
|                                 <a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'"> |                             <a-list item-layout="horizontal" :style="themeSwitcher.textStyle"> | ||||||
|                                 <setting-list-item type="text" title='{{ i18n "pages.settings.panelListeningIP"}}' desc='{{ i18n "pages.settings.panelListeningIPDesc"}}' v-model="allSetting.webListen"></setting-list-item> |                                 <setting-list-item type="text" title='{{ i18n "pages.settings.panelListeningIP"}}' desc='{{ i18n "pages.settings.panelListeningIPDesc"}}' v-model="allSetting.webListen"></setting-list-item> | ||||||
|                                 <setting-list-item type="number" title='{{ i18n "pages.settings.panelPort"}}' desc='{{ i18n "pages.settings.panelPortDesc"}}' v-model="allSetting.webPort" :min="0"></setting-list-item> |                                 <setting-list-item type="number" title='{{ i18n "pages.settings.panelPort"}}' desc='{{ i18n "pages.settings.panelPortDesc"}}' v-model="allSetting.webPort" :min="0"></setting-list-item> | ||||||
|                                 <setting-list-item type="text" title='{{ i18n "pages.settings.publicKeyPath"}}' desc='{{ i18n "pages.settings.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item> |                                 <setting-list-item type="text" title='{{ i18n "pages.settings.publicKeyPath"}}' desc='{{ i18n "pages.settings.publicKeyPathDesc"}}' v-model="allSetting.webCertFile"></setting-list-item> | ||||||
|  | @ -60,7 +60,7 @@ | ||||||
|                                                     ref="selectLang" |                                                     ref="selectLang" | ||||||
|                                                     v-model="lang" |                                                     v-model="lang" | ||||||
|                                                     @change="setLang(lang)" |                                                     @change="setLang(lang)" | ||||||
|                                                         :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''" |                                                     :dropdown-class-name="themeSwitcher.darkCardClass" | ||||||
|                                                     style="width: 100%" |                                                     style="width: 100%" | ||||||
|                                                 > |                                                 > | ||||||
|                                                     <a-select-option :value="l.value" :label="l.value" v-for="l in supportLangs"> |                                                     <a-select-option :value="l.value" :label="l.value" v-for="l in supportLangs"> | ||||||
|  | @ -75,20 +75,20 @@ | ||||||
|                         </a-tab-pane> |                         </a-tab-pane> | ||||||
| 
 | 
 | ||||||
|                         <a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings"}}' style="padding: 20px;"> |                         <a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings"}}' style="padding: 20px;"> | ||||||
|                                 <a-tabs default-active-key="sec-1" :class="siderDrawer.isDarkTheme ? darkClass : ''"> |                             <a-tabs default-active-key="sec-1" :class="themeSwitcher.darkCardClass"> | ||||||
|                                 <a-tab-pane key="sec-1" tab='{{ i18n "pages.settings.security.admin"}}'> |                                 <a-tab-pane key="sec-1" tab='{{ i18n "pages.settings.security.admin"}}'> | ||||||
|                                         <a-form :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65); padding: 20px;': 'background: white; padding: 20px;'"> |                                     <a-form :style="'padding: 20px;' + themeSwitcher.textStyle"> | ||||||
|                                         <a-form-item label='{{ i18n "pages.settings.oldUsername"}}'> |                                         <a-form-item label='{{ i18n "pages.settings.oldUsername"}}'> | ||||||
|                                             <a-input v-model="user.oldUsername" style="max-width: 300px"></a-input> |                                             <a-input v-model="user.oldUsername" style="max-width: 300px"></a-input> | ||||||
|                                         </a-form-item> |                                         </a-form-item> | ||||||
|                                         <a-form-item label='{{ i18n "pages.settings.currentPassword"}}'> |                                         <a-form-item label='{{ i18n "pages.settings.currentPassword"}}'> | ||||||
|                                                 <a-input type="password" v-model="user.oldPassword" style="max-width: 300px"></a-input> |                                             <password-input v-model="user.oldPassword" style="max-width: 300px"></password-input> | ||||||
|                                         </a-form-item> |                                         </a-form-item> | ||||||
|                                         <a-form-item label='{{ i18n "pages.settings.newUsername"}}'> |                                         <a-form-item label='{{ i18n "pages.settings.newUsername"}}'> | ||||||
|                                             <a-input v-model="user.newUsername" style="max-width: 300px"></a-input> |                                             <a-input v-model="user.newUsername" style="max-width: 300px"></a-input> | ||||||
|                                         </a-form-item> |                                         </a-form-item> | ||||||
|                                         <a-form-item label='{{ i18n "pages.settings.newPassword"}}'> |                                         <a-form-item label='{{ i18n "pages.settings.newPassword"}}'> | ||||||
|                                                 <a-input type="password" v-model="user.newPassword" style="max-width: 300px"></a-input> |                                             <password-input v-model="user.newPassword" style="max-width: 300px"></password-input> | ||||||
|                                         </a-form-item> |                                         </a-form-item> | ||||||
|                                         <a-form-item> |                                         <a-form-item> | ||||||
|                                             <a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button> |                                             <a-button type="primary" @click="updateUser">{{ i18n "confirm" }}</a-button> | ||||||
|  | @ -96,7 +96,7 @@ | ||||||
|                                     </a-form> |                                     </a-form> | ||||||
|                                 </a-tab-pane> |                                 </a-tab-pane> | ||||||
|                                 <a-tab-pane key="sec-2" tab='{{ i18n "pages.settings.security.secret"}}'> |                                 <a-tab-pane key="sec-2" tab='{{ i18n "pages.settings.security.secret"}}'> | ||||||
|                                         <a-form :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65); padding: 20px;': 'background: white; padding: 20px;'"> |                                     <a-form :style="'padding: 20px;' + themeSwitcher.textStyle"> | ||||||
|                                         <a-list-item style="padding: 20px"> |                                         <a-list-item style="padding: 20px"> | ||||||
|                                             <a-row> |                                             <a-row> | ||||||
|                                                 <a-col :lg="24" :xl="12"> |                                                 <a-col :lg="24" :xl="12"> | ||||||
|  | @ -132,14 +132,14 @@ | ||||||
|                         </a-tab-pane> |                         </a-tab-pane> | ||||||
| 
 | 
 | ||||||
|                         <a-tab-pane key="3" tab='{{ i18n "pages.settings.xrayConfiguration"}}'> |                         <a-tab-pane key="3" tab='{{ i18n "pages.settings.xrayConfiguration"}}'> | ||||||
|                                 <a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'"> |                             <a-list item-layout="horizontal" :style="themeSwitcher.textStyle"> | ||||||
|                                 <a-divider style="padding: 20px;">{{ i18n "pages.settings.actions"}}</a-divider> |                                 <a-divider style="padding: 20px;">{{ i18n "pages.settings.actions"}}</a-divider> | ||||||
|                                 <a-space direction="horizontal" style="padding: 0px 20px"> |                                 <a-space direction="horizontal" style="padding: 0px 20px"> | ||||||
|                                     <a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button> |                                     <a-button type="primary" @click="resetXrayConfigToDefault">{{ i18n "pages.settings.resetDefaultConfig" }}</a-button> | ||||||
|                                 </a-space> |                                 </a-space> | ||||||
|                                 <a-divider style="padding: 20px;">{{ i18n "pages.settings.templates.title"}} </a-divider> |                                 <a-divider style="padding: 20px;">{{ i18n "pages.settings.templates.title"}} </a-divider> | ||||||
|                                  |                                  | ||||||
|                                     <a-tabs default-active-key="tpl-1" :class="siderDrawer.isDarkTheme ? darkClass : ''" style="padding: 20px 20px;"> |                                 <a-tabs default-active-key="tpl-1" :class="themeSwitcher.darkCardClass" style="padding: 20px 20px;"> | ||||||
|                                     <a-tab-pane key="tpl-1" tab='{{ i18n "pages.settings.templates.basicTemplate"}}' style="padding-top: 20px;"> |                                     <a-tab-pane key="tpl-1" tab='{{ i18n "pages.settings.templates.basicTemplate"}}' style="padding-top: 20px;"> | ||||||
|                                         <a-collapse> |                                         <a-collapse> | ||||||
|                                             <a-collapse-panel header='{{ i18n "pages.settings.templates.generalConfigs"}}'> |                                             <a-collapse-panel header='{{ i18n "pages.settings.templates.generalConfigs"}}'> | ||||||
|  | @ -213,7 +213,7 @@ | ||||||
|                         </a-tab-pane> |                         </a-tab-pane> | ||||||
| 
 | 
 | ||||||
|                         <a-tab-pane key="4" tab='{{ i18n "pages.settings.TGBotSettings"}}'> |                         <a-tab-pane key="4" tab='{{ i18n "pages.settings.TGBotSettings"}}'> | ||||||
|                                 <a-list item-layout="horizontal" :style="siderDrawer.isDarkTheme ? 'color: hsla(0,0%,100%,.65);': 'background: white;'"> |                             <a-list item-layout="horizontal" :style="themeSwitcher.textStyle"> | ||||||
|                                 <setting-list-item type="switch" title='{{ i18n "pages.settings.telegramBotEnable" }}' desc='{{ i18n "pages.settings.telegramBotEnableDesc" }}' v-model="allSetting.tgBotEnable"></setting-list-item> |                                 <setting-list-item type="switch" title='{{ i18n "pages.settings.telegramBotEnable" }}' desc='{{ i18n "pages.settings.telegramBotEnableDesc" }}' v-model="allSetting.tgBotEnable"></setting-list-item> | ||||||
|                                 <setting-list-item type="text" title='{{ i18n "pages.settings.telegramToken"}}' desc='{{ i18n "pages.settings.telegramTokenDesc"}}' v-model="allSetting.tgBotToken"></setting-list-item> |                                 <setting-list-item type="text" title='{{ i18n "pages.settings.telegramToken"}}' desc='{{ i18n "pages.settings.telegramTokenDesc"}}' v-model="allSetting.tgBotToken"></setting-list-item> | ||||||
|                                 <setting-list-item type="text" title='{{ i18n "pages.settings.telegramChatId"}}' desc='{{ i18n "pages.settings.telegramChatIdDesc"}}' v-model="allSetting.tgBotChatId"></setting-list-item> |                                 <setting-list-item type="text" title='{{ i18n "pages.settings.telegramChatId"}}' desc='{{ i18n "pages.settings.telegramChatIdDesc"}}' v-model="allSetting.tgBotChatId"></setting-list-item> | ||||||
|  | @ -228,15 +228,19 @@ | ||||||
|         </a-layout-content> |         </a-layout-content> | ||||||
|     </a-layout> |     </a-layout> | ||||||
| </a-layout> | </a-layout> | ||||||
|  | 
 | ||||||
| {{template "js" .}} | {{template "js" .}} | ||||||
|  | {{template "component/themeSwitcher" .}} | ||||||
|  | {{template "component/password" .}} | ||||||
| {{template "component/setting"}} | {{template "component/setting"}} | ||||||
|  | 
 | ||||||
| <script> | <script> | ||||||
| 
 | 
 | ||||||
|     const app = new Vue({ |     const app = new Vue({ | ||||||
|         delimiters: ['[[', ']]'], |         delimiters: ['[[', ']]'], | ||||||
|         el: '#app', |         el: '#app', | ||||||
|         data: { |         data: { | ||||||
|                 siderDrawer, |             themeSwitcher, | ||||||
|             spinning: false, |             spinning: false, | ||||||
|             oldAllSetting: new AllSetting(), |             oldAllSetting: new AllSetting(), | ||||||
|             allSetting: new AllSetting(), |             allSetting: new AllSetting(), | ||||||
|  | @ -332,7 +336,7 @@ | ||||||
|                 this.loading(false); |                 this.loading(false); | ||||||
|                 if (msg.success) { |                 if (msg.success) { | ||||||
|                     this.user = {}; |                     this.user = {}; | ||||||
|                         window.location.replace("/logout") |                     window.location.replace(basePath + "logout") | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             async restartPanel() { |             async restartPanel() { | ||||||
|  | @ -366,7 +370,7 @@ | ||||||
|                 const msg = await HttpUtil.post("/xui/setting/updateUserSecret", this.user); |                 const msg = await HttpUtil.post("/xui/setting/updateUserSecret", this.user); | ||||||
|                 if (msg.success) { |                 if (msg.success) { | ||||||
|                     this.user = msg.obj; |                     this.user = msg.obj; | ||||||
|                         window.location.replace("/logout") |                     window.location.replace(basePath + "logout") | ||||||
|                 } |                 } | ||||||
|                 this.loading(false); |                 this.loading(false); | ||||||
|                 await this.updateAllSetting(); |                 await this.updateAllSetting(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Ho3ein
						Ho3ein