diff options
| author | Shishkevich D. <135337715+shishkevichd@users.noreply.github.com> | 2025-04-06 12:40:33 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-06 12:40:33 +0300 |
| commit | bea19a263db88fef44b4356082b199fbfcc39a25 (patch) | |
| tree | a111e9328c6273ad9721118238c40cf3004f72a9 /web/html/xui/settings.html | |
| parent | 878e0d02cd01a045f4f32464124c59e24f98aedd (diff) | |
Code refactoring (#2865)
* refactor: use vue inline styles in entire application
* refactor: setting row in dashboard page
* refactor: use blob for download file in text modal
* refactor: move all html templates in `web/html` folder
* refactor: `DeviceUtils` -> `MediaQueryMixin`
The transition to mixins has been made, as they can update themselves.
* chore: pretty right buttons in `outbounds` tab in xray settings
* refactor: add translations for system status
* refactor: adjust gutter spacing in setting list item
* refactor: use native `a-input-password` for password field
* chore: return old system status
with new translations
* chore: add missing translation
Diffstat (limited to 'web/html/xui/settings.html')
| -rw-r--r-- | web/html/xui/settings.html | 540 |
1 files changed, 0 insertions, 540 deletions
diff --git a/web/html/xui/settings.html b/web/html/xui/settings.html deleted file mode 100644 index cab41e5a..00000000 --- a/web/html/xui/settings.html +++ /dev/null @@ -1,540 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -{{template "head" .}} -<style> - @media (min-width: 769px) { - .ant-layout-content { - margin: 24px 16px; - } - } - @media (max-width: 768px) { - .ant-tabs-nav .ant-tabs-tab { - margin: 0; - padding: 12px .5rem; - } - } - .ant-tabs-bar { - margin: 0; - } - .ant-list-item { - display: block; - } - .alert-msg { - color: rgb(194, 117, 18); - font-weight: normal; - font-size: 16px; - padding: .5rem 1rem; - text-align: center; - background: rgb(255 145 0 / 15%); - margin: 1.5rem 2.5rem 0rem; - border-radius: .5rem; - transition: all 0.5s; - animation: signal 3s cubic-bezier(0.18, 0.89, 0.32, 1.28) infinite; - } - .alert-msg:hover { - cursor: default; - transition-duration: .3s; - animation: signal 0.9s ease infinite; - } - @keyframes signal { - 0% { - box-shadow: 0 0 0 0 rgba(194, 118, 18, 0.5); - } - - 50% { - box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); - } - - 100% { - box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); - } - } - .alert-msg>i { - color: inherit; - font-size: 24px; - } -</style> -<body> - <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> - <a-sidebar></a-sidebar> - <a-layout id="content-layout"> - <a-layout-content> - <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'> - <transition name="list" appear> - <a-alert type="error" v-if="confAlerts.length>0" style="margin-bottom: 10px;" - message='{{ i18n "secAlertTitle" }}' - color="red" - show-icon closable> - <template slot="description"> - <b>{{ i18n "secAlertConf" }}</b> - <ul><li v-for="a in confAlerts">[[ a ]]</li></ul> - </template> - </a-alert> - </transition> - <a-space direction="vertical"> - <a-card hoverable style="margin-bottom: .5rem; overflow-x: hidden;"> - <a-row style="display: flex; flex-wrap: wrap; align-items: center;"> - <a-col :xs="24" :sm="10" style="padding: 4px;"> - <a-space direction="horizontal"> - <a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.settings.save" }}</a-button> - <a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button> - </a-space> - </a-col> - <a-col :xs="24" :sm="14"> - <template> - <div> - <a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200"></a-back-top> - <a-alert type="warning" style="float: right; width: fit-content" - message='{{ i18n "pages.settings.infoDesc" }}' - show-icon> - </a-alert> - </div> - </template> - </a-col> - </a-row> - </a-card> - <a-tabs default-active-key="1"> - <a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings" }}' style="padding-top: 20px;"> - {{ template "settings/panel/general" . }} - </a-tab-pane> - <a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings" }}' style="padding-top: 20px;"> - {{ template "settings/panel/security" . }} - </a-tab-pane> - <a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings" }}' style="padding-top: 20px;"> - {{ template "settings/panel/telegram" . }} - </a-tab-pane> - <a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}' style="padding-top: 20px;"> - {{ template "settings/panel/subscription/general" . }} - </a-tab-pane> - <a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable" style="padding-top: 20px;"> - {{ template "settings/panel/subscription/json" . }} - </a-tab-pane> - </a-tabs> - </a-space> - </a-spin> - </a-layout-content> - </a-layout> - </a-layout> -{{template "js" .}} -<script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script> -{{template "component/aSidebar" .}} -{{template "component/aThemeSwitch" .}} -{{template "component/aPasswordInput" .}} -{{template "component/aSettingListItem" .}} -<script> - const app = new Vue({ - delimiters: ['[[', ']]'], - el: '#app', - data: { - themeSwitcher, - spinning: false, - changeSecret: false, - oldAllSetting: new AllSetting(), - allSetting: new AllSetting(), - saveBtnDisable: true, - user: {}, - lang: LanguageManager.getLanguage(), - remarkModels: { i: 'Inbound', e: 'Email', o: 'Other' }, - remarkSeparators: [' ', '-', '_', '@', ':', '~', '|', ',', '.', '/'], - datepickerList: [{ name: 'Gregorian (Standard)', value: 'gregorian' }, { name: 'Jalalian (شمسی)', value: 'jalalian' }], - remarkSample: '', - defaultFragment: { - tag: "fragment", - protocol: "freedom", - settings: { - domainStrategy: "AsIs", - fragment: { - packets: "tlshello", - length: "100-200", - interval: "10-20" - } - }, - streamSettings: { - sockopt: { - tcpKeepAliveIdle: 100, - tcpMptcp: true, - penetrate: true - } - } - }, - defaultNoises: { - tag: "noises", - protocol: "freedom", - settings: { - domainStrategy: "AsIs", - noises: [ - { type: "rand", packet: "10-20", delay: "10-16" }, - ], - }, - }, - defaultMux: { - enabled: true, - concurrency: 8, - xudpConcurrency: 16, - xudpProxyUDP443: "reject" - }, - defaultRules: [ - { - type: "field", - outboundTag: "direct", - domain: [ - "geosite:category-ir" - ] - }, - { - type: "field", - outboundTag: "direct", - ip: [ - "geoip:private", - "geoip:ir" - ] - }, - ], - directIPsOptions: [ - { label: 'Private IP', value: 'geoip:private' }, - { label: '🇮🇷 Iran', value: 'geoip:ir' }, - { label: '🇨🇳 China', value: 'geoip:cn' }, - { label: '🇷🇺 Russia', value: 'geoip:ru' }, - { label: '🇻🇳 Vietnam', value: 'geoip:vn' }, - { label: '🇪🇸 Spain', value: 'geoip:es' }, - { label: '🇮🇩 Indonesia', value: 'geoip:id' }, - { label: '🇺🇦 Ukraine', value: 'geoip:ua' }, - { label: '🇹🇷 Türkiye', value: 'geoip:tr' }, - { label: '🇧🇷 Brazil', value: 'geoip:br' }, - ], - diretDomainsOptions: [ - { label: 'Private DNS', value: 'geosite:private' }, - { label: '🇮🇷 Iran', value: 'geosite:category-ir' }, - { label: '🇨🇳 China', value: 'geosite:cn' }, - { label: '🇷🇺 Russia', value: 'geosite:category-ru' }, - { label: 'Apple', value: 'geosite:apple' }, - { label: 'Meta', value: 'geosite:meta' }, - { label: 'Google', value: 'geosite:google' }, - ], - get remarkModel() { - rm = this.allSetting.remarkModel; - return rm.length > 1 ? rm.substring(1).split('') : []; - }, - set remarkModel(value) { - rs = this.allSetting.remarkModel[0]; - this.allSetting.remarkModel = rs + value.join(''); - this.changeRemarkSample(); - }, - get remarkSeparator() { - return this.allSetting.remarkModel.length > 1 ? this.allSetting.remarkModel.charAt(0) : '-'; - }, - set remarkSeparator(value) { - this.allSetting.remarkModel = value + this.allSetting.remarkModel.substring(1); - this.changeRemarkSample(); - }, - get datepicker() { - return this.allSetting.datepicker ? this.allSetting.datepicker : 'gregorian'; - }, - set datepicker(value) { - this.allSetting.datepicker = value; - }, - changeRemarkSample() { - sample = [] - this.remarkModel.forEach(r => sample.push(this.remarkModels[r])); - this.remarkSample = sample.length == 0 ? '' : sample.join(this.remarkSeparator); - } - }, - methods: { - loading(spinning = true) { - this.spinning = spinning; - }, - async getAllSetting() { - this.loading(true); - const msg = await HttpUtil.post("/panel/setting/all"); - this.loading(false); - if (msg.success) { - this.oldAllSetting = new AllSetting(msg.obj); - this.allSetting = new AllSetting(msg.obj); - app.changeRemarkSample(); - this.saveBtnDisable = true; - } - await this.fetchUserSecret(); - }, - async updateAllSetting() { - this.loading(true); - const msg = await HttpUtil.post("/panel/setting/update", this.allSetting); - this.loading(false); - if (msg.success) { - await this.getAllSetting(); - } - }, - async updateUser() { - this.loading(true); - const msg = await HttpUtil.post("/panel/setting/updateUser", this.user); - this.loading(false); - if (msg.success) { - this.user = {}; - window.location.replace(basePath + "logout"); - } - }, - async restartPanel() { - await new Promise(resolve => { - this.$confirm({ - title: '{{ i18n "pages.settings.restartPanel" }}', - content: '{{ i18n "pages.settings.restartPanelDesc" }}', - class: themeSwitcher.currentTheme, - okText: '{{ i18n "sure" }}', - cancelText: '{{ i18n "cancel" }}', - onOk: () => resolve(), - }); - }); - this.loading(true); - const msg = await HttpUtil.post("/panel/setting/restartPanel"); - this.loading(false); - if (msg.success) { - this.loading(true); - await PromiseUtil.sleep(5000); - var { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting; - if (host == this.oldAllSetting.webDomain) host = null; - if (port == this.oldAllSetting.webPort) port = null; - const isTLS = webCertFile !== "" || webKeyFile !== ""; - const url = URLBuilder.buildURL({ host, port, isTLS, base, path: "panel/settings" }); - window.location.replace(url); - } - }, - async fetchUserSecret() { - this.loading(true); - const userMessage = await HttpUtil.post("/panel/setting/getUserSecret", this.user); - if (userMessage.success) { - this.user = userMessage.obj; - } - this.loading(false); - }, - async updateSecret() { - this.loading(true); - const msg = await HttpUtil.post("/panel/setting/updateUserSecret", this.user); - if (msg && msg.obj) { - this.user = msg.obj; - } - this.loading(false); - await this.updateAllSetting(); - }, - generateRandomString(length) { - var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - let randomString = ""; - for (let i = 0; i < length; i++) { - randomString += chars[Math.floor(Math.random() * chars.length)]; - } - return randomString; - }, - async getNewSecret() { - if (!this.changeSecret) { - this.changeSecret = true; - this.user.loginSecret = ''; - const newSecret = this.generateRandomString(64); - await PromiseUtil.sleep(1000); - this.user.loginSecret = newSecret; - this.changeSecret = false; - } - }, - async toggleToken(value) { - if (value) { - await this.getNewSecret(); - } else { - this.user.loginSecret = ""; - } - }, - addNoise() { - const newNoise = { type: "rand", packet: "10-20", delay: "10-16" }; - this.noisesArray = [...this.noisesArray, newNoise]; - }, - removeNoise(index) { - const newNoises = [...this.noisesArray]; - newNoises.splice(index, 1); - this.noisesArray = newNoises; - }, - updateNoiseType(index, value) { - const updatedNoises = [...this.noisesArray]; - updatedNoises[index] = { ...updatedNoises[index], type: value }; - this.noisesArray = updatedNoises; - }, - updateNoisePacket(index, value) { - const updatedNoises = [...this.noisesArray]; - updatedNoises[index] = { ...updatedNoises[index], packet: value }; - this.noisesArray = updatedNoises; - }, - updateNoiseDelay(index, value) { - const updatedNoises = [...this.noisesArray]; - updatedNoises[index] = { ...updatedNoises[index], delay: value }; - this.noisesArray = updatedNoises; - }, - }, - computed: { - fragment: { - get: function () { return this.allSetting?.subJsonFragment != ""; }, - set: function (v) { - this.allSetting.subJsonFragment = v ? JSON.stringify(this.defaultFragment) : ""; - } - }, - fragmentPackets: { - get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.packets : ""; }, - set: function (v) { - if (v != "") { - newFragment = JSON.parse(this.allSetting.subJsonFragment); - newFragment.settings.fragment.packets = v; - this.allSetting.subJsonFragment = JSON.stringify(newFragment); - } - } - }, - fragmentLength: { - get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.length : ""; }, - set: function (v) { - if (v != "") { - newFragment = JSON.parse(this.allSetting.subJsonFragment); - newFragment.settings.fragment.length = v; - this.allSetting.subJsonFragment = JSON.stringify(newFragment); - } - } - }, - fragmentInterval: { - get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.interval : ""; }, - set: function (v) { - if (v != "") { - newFragment = JSON.parse(this.allSetting.subJsonFragment); - newFragment.settings.fragment.interval = v; - this.allSetting.subJsonFragment = JSON.stringify(newFragment); - } - } - }, - noises: { - get() { - return this.allSetting?.subJsonNoises != ""; - }, - set(v) { - if (v) { - this.allSetting.subJsonNoises = JSON.stringify(this.defaultNoises); - } else { - this.allSetting.subJsonNoises = ""; - } - } - }, - noisesArray: { - get() { - return this.noises ? JSON.parse(this.allSetting.subJsonNoises).settings.noises : []; - }, - set(value) { - if (this.noises) { - const newNoises = JSON.parse(this.allSetting.subJsonNoises); - newNoises.settings.noises = value; - this.allSetting.subJsonNoises = JSON.stringify(newNoises); - } - } - }, - enableMux: { - get: function () { return this.allSetting?.subJsonMux != ""; }, - set: function (v) { - this.allSetting.subJsonMux = v ? JSON.stringify(this.defaultMux) : ""; - } - }, - muxConcurrency: { - get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).concurrency : -1; }, - set: function (v) { - newMux = JSON.parse(this.allSetting.subJsonMux); - newMux.concurrency = v; - this.allSetting.subJsonMux = JSON.stringify(newMux); - } - }, - muxXudpConcurrency: { - get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpConcurrency : -1; }, - set: function (v) { - newMux = JSON.parse(this.allSetting.subJsonMux); - newMux.xudpConcurrency = v; - this.allSetting.subJsonMux = JSON.stringify(newMux); - } - }, - muxXudpProxyUDP443: { - get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpProxyUDP443 : "reject"; }, - set: function (v) { - newMux = JSON.parse(this.allSetting.subJsonMux); - newMux.xudpProxyUDP443 = v; - this.allSetting.subJsonMux = JSON.stringify(newMux); - } - }, - enableDirect: { - get: function () { return this.allSetting?.subJsonRules != ""; }, - set: function (v) { - this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : ""; - } - }, - directIPs: { - get: function () { - if (!this.enableDirect) return []; - const rules = JSON.parse(this.allSetting.subJsonRules); - if (!Array.isArray(rules)) return []; - const ipRule = rules.find(r => r.ip); - return ipRule?.ip ?? []; - }, - set: function (v) { - let rules = JSON.parse(this.allSetting.subJsonRules); - if (!Array.isArray(rules)) return; - - if (v.length == 0) { - rules = rules.filter(r => !r.ip); - } else { - let ruleIndex = rules.findIndex(r => r.ip); - if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[1]) - 1; - - rules[ruleIndex].ip = []; - v.forEach(d => { - rules[ruleIndex].ip.push(d); - }); - } - this.allSetting.subJsonRules = JSON.stringify(rules); - } - }, - directDomains: { - get: function () { - if (!this.enableDirect) return []; - const rules = JSON.parse(this.allSetting.subJsonRules); - if (!Array.isArray(rules)) return []; - const domainRule = rules.find(r => r.domain); - return domainRule?.domain ?? []; - }, - set: function (v) { - let rules = JSON.parse(this.allSetting.subJsonRules); - if (!Array.isArray(rules)) return; - if (v.length == 0) { - rules = rules.filter(r => !r.domain); - } else { - let ruleIndex = rules.findIndex(r => r.domain); - if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[0]) - 1; - - rules[ruleIndex].domain = v; - } - this.allSetting.subJsonRules = JSON.stringify(rules); - } - }, - confAlerts: { - get: function () { - if (!this.allSetting) return []; - var alerts = [] - if (window.location.protocol !== "https:") alerts.push('{{ i18n "secAlertSSL" }}'); - if (this.allSetting.webPort == 54321) alerts.push('{{ i18n "secAlertPanelPort" }}'); - panelPath = window.location.pathname.split('/').length < 4 - if (panelPath && this.allSetting.webBasePath == '/') alerts.push('{{ i18n "secAlertPanelURI" }}'); - if (this.allSetting.subEnable) { - subPath = this.allSetting.subURI.length > 0 ? new URL(this.allSetting.subURI).pathname : this.allSetting.subPath; - if (subPath == '/sub/') alerts.push('{{ i18n "secAlertSubURI" }}'); - subJsonPath = this.allSetting.subJsonURI.length > 0 ? new URL(this.allSetting.subJsonURI).pathname : this.allSetting.subJsonPath; - if (subJsonPath == '/json/') alerts.push('{{ i18n "secAlertSubJsonURI" }}'); - } - return alerts - } - } - }, - async mounted() { - await this.getAllSetting(); - while (true) { - await PromiseUtil.sleep(1000); - this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting); - } - } - }); -</script> -</body> -</html>
\ No newline at end of file |
