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/modals | |
| 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/modals')
| -rw-r--r-- | web/html/modals/client_bulk_modal.html | 250 | ||||
| -rw-r--r-- | web/html/modals/client_modal.html | 172 | ||||
| -rw-r--r-- | web/html/modals/dns_modal.html | 114 | ||||
| -rw-r--r-- | web/html/modals/fakedns_modal.html | 57 | ||||
| -rw-r--r-- | web/html/modals/inbound_info_modal.html | 572 | ||||
| -rw-r--r-- | web/html/modals/inbound_modal.html | 144 | ||||
| -rw-r--r-- | web/html/modals/prompt_modal.html | 71 | ||||
| -rw-r--r-- | web/html/modals/qrcode_modal.html | 162 | ||||
| -rw-r--r-- | web/html/modals/text_modal.html | 62 | ||||
| -rw-r--r-- | web/html/modals/warp_modal.html | 246 | ||||
| -rw-r--r-- | web/html/modals/xray_balancer_modal.html | 123 | ||||
| -rw-r--r-- | web/html/modals/xray_outbound_modal.html | 127 | ||||
| -rw-r--r-- | web/html/modals/xray_reverse_modal.html | 138 | ||||
| -rw-r--r-- | web/html/modals/xray_rule_modal.html | 246 |
14 files changed, 2484 insertions, 0 deletions
diff --git a/web/html/modals/client_bulk_modal.html b/web/html/modals/client_bulk_modal.html new file mode 100644 index 00000000..d6bcfcd6 --- /dev/null +++ b/web/html/modals/client_bulk_modal.html @@ -0,0 +1,250 @@ +{{define "modals/clientsBulkModal"}} +<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" + :ok-text="clientsBulkModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> + <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> + <a-form-item label='{{ i18n "pages.client.method" }}'> + <a-select v-model="clientsBulkModal.emailMethod" buttonStyle="solid" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="0">Random</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="3">Random+Prefix+Num+Postfix</a-select-option> + <a-select-option :value="4">Prefix+Num+Postfix</a-select-option> + </a-select> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.first" }}' v-if="clientsBulkModal.emailMethod>1"> + <a-input-number v-model.number="clientsBulkModal.firstNum" :min="1"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.last" }}' v-if="clientsBulkModal.emailMethod>1"> + <a-input-number v-model.number="clientsBulkModal.lastNum" :min="clientsBulkModal.firstNum"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.prefix" }}' v-if="clientsBulkModal.emailMethod>0"> + <a-input v-model.trim="clientsBulkModal.emailPrefix"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.postfix" }}' v-if="clientsBulkModal.emailMethod>2"> + <a-input v-model.trim="clientsBulkModal.emailPostfix"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.clientCount" }}' v-if="clientsBulkModal.emailMethod < 2"> + <a-input-number v-model.number="clientsBulkModal.quantity" :min="1" :max="100"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "security" }}' v-if="inbound.protocol === Protocols.VMESS"> + <a-select v-model="clientsBulkModal.security" :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option v-for="key in USERS_SECURITY" :value="key">[[ key ]]</a-select-option> + </a-select> + </a-form-item> + <a-form-item label='Flow' v-if="clientsBulkModal.inbound.canEnableTlsFlow()"> + <a-select v-model="clientsBulkModal.flow" :dropdown-class-name="themeSwitcher.currentTheme"> + <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> + </a-form-item> + <a-form-item v-if="app.subSettings.enable"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.subscriptionDesc" }}</span> + </template> + Subscription + <a-icon @click="clientsBulkModal.subId = RandomUtil.randomLowerAndNum(16)" type="sync"></a-icon> + </a-tooltip> + </template> + <a-input v-model.trim="clientsBulkModal.subId"></a-input> + </a-form-item> + <a-form-item v-if="app.tgBotEnable"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.telegramDesc" }}</span> + </template> + Telegram ChatID + <a-icon type="question-circle"></a-icon> + </a-tooltip> + </template> + <a-input-number :style="{ width: '50%' }" v-model.number="clientsBulkModal.tgId" min="0"></a-input-number> + </a-form-item> + <a-form-item v-if="app.ipLimitEnable"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.IPLimitDesc" }}</span> + </template> + <span>{{ i18n "pages.inbounds.IPLimit" }} </span> + <a-icon type="question-circle"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model.number="clientsBulkModal.limitIp" min="0"></a-input-number> + </a-form-item> + <a-form-item> + <template slot="label"> + <a-tooltip> + <template slot="title"> + 0 <span>{{ i18n "pages.inbounds.meansNoLimit" }}</span> + </template> + {{ i18n "pages.inbounds.totalFlow" }} + <a-icon type="question-circle"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model.number="clientsBulkModal.totalGB" :min="0"></a-input-number> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.delayedStart" }}'> + <a-switch v-model="clientsBulkModal.delayedStart" @click="clientsBulkModal.expiryTime=0"></a-switch> + </a-form-item> + <a-form-item label='{{ i18n "pages.client.expireDays" }}' v-if="clientsBulkModal.delayedStart"> + <a-input-number v-model.number="delayedExpireDays" :min="0"></a-input-number> + </a-form-item> + <a-form-item v-else> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.inbounds.leaveBlankToNeverExpire" }}</span> + </template> + {{ i18n "pages.inbounds.expireDate" }} + <a-icon type="question-circle"></a-icon> + </a-tooltip> + </template> + <a-date-picker v-if="datepicker == 'gregorian'" :show-time="{ format: 'HH:mm:ss' }" + format="YYYY-MM-DD HH:mm:ss" :dropdown-class-name="themeSwitcher.currentTheme" + v-model="clientsBulkModal.expiryTime"></a-date-picker> + <a-persian-datepicker v-else placeholder='{{ i18n "pages.settings.datepickerPlaceholder" }}' + value="clientsBulkModal.expiryTime" v-model="clientsBulkModal.expiryTime"> + </a-persian-datepicker> + </a-form-item> + <a-form-item v-if="clientsBulkModal.expiryTime != 0"> + <template slot="label"> + <a-tooltip> + <template slot="title"> + <span>{{ i18n "pages.client.renewDesc" }}</span> + </template> + {{ i18n "pages.client.renew" }} + <a-icon type="question-circle"></a-icon> + </a-tooltip> + </template> + <a-input-number v-model.number="clientsBulkModal.reset" :min="0"></a-input-number> + </a-form-item> + </a-form> +</a-modal> +<script> + + const clientsBulkModal = { + visible: false, + confirmLoading: false, + title: '', + okText: '', + confirm: null, + dbInbound: new DBInbound(), + inbound: new Inbound(), + quantity: 1, + totalGB: 0, + limitIp: 0, + expiryTime: '', + emailMethod: 0, + firstNum: 1, + lastNum: 1, + emailPrefix: "", + emailPostfix: "", + subId: "", + tgId: '', + security: "auto", + flow: "", + delayedStart: false, + reset: 0, + ok() { + clients = []; + method = clientsBulkModal.emailMethod; + if (method > 1) { + start = clientsBulkModal.firstNum; + end = clientsBulkModal.lastNum + 1; + } else { + start = 0; + end = clientsBulkModal.quantity; + } + prefix = (method > 0 && clientsBulkModal.emailPrefix.length > 0) ? clientsBulkModal.emailPrefix : ""; + useNum = (method > 1); + postfix = (method > 2 && clientsBulkModal.emailPostfix.length > 0) ? clientsBulkModal.emailPostfix : ""; + for (let i = start; i < end; i++) { + newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol); + if (method == 4) newClient.email = ""; + newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix; + if (clientsBulkModal.subId.length > 0) newClient.subId = clientsBulkModal.subId; + newClient.tgId = clientsBulkModal.tgId; + newClient.security = clientsBulkModal.security; + newClient.limitIp = clientsBulkModal.limitIp; + newClient._totalGB = clientsBulkModal.totalGB; + newClient._expiryTime = clientsBulkModal.expiryTime; + if (clientsBulkModal.inbound.canEnableTlsFlow()) { + newClient.flow = clientsBulkModal.flow; + } + newClient.reset = clientsBulkModal.reset; + clients.push(newClient); + } + ObjectUtil.execute(clientsBulkModal.confirm, clients, clientsBulkModal.dbInbound.id); + }, + show({ + title = '', + okText = '{{ i18n "sure" }}', + dbInbound = null, + confirm = (inbound, dbInbound) => { } + }) { + this.visible = true; + this.title = title; + this.okText = okText; + this.confirm = confirm; + this.quantity = 1; + this.totalGB = 0; + this.expiryTime = 0; + this.emailMethod = 0; + this.limitIp = 0; + this.firstNum = 1; + this.lastNum = 1; + this.emailPrefix = ""; + this.emailPostfix = ""; + this.subId = ""; + this.tgId = ''; + this.security = "auto"; + this.flow = ""; + this.dbInbound = new DBInbound(dbInbound); + this.inbound = dbInbound.toInbound(); + this.delayedStart = false; + this.reset = 0; + }, + newClient(protocol) { + switch (protocol) { + case Protocols.VMESS: return new Inbound.VmessSettings.VMESS(); + case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS(); + case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan(); + case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings.Shadowsocks(clientsBulkModal.inbound.settings.shadowsockses[0].method); + default: return null; + } + }, + close() { + clientsBulkModal.visible = false; + clientsBulkModal.loading(false); + }, + loading(loading = true) { + clientsBulkModal.confirmLoading = loading; + }, + }; + + const clientsBulkModalApp = new Vue({ + delimiters: ['[[', ']]'], + el: '#client-bulk-modal', + data: { + clientsBulkModal, + get inbound() { + return this.clientsBulkModal.inbound; + }, + get delayedExpireDays() { + return this.clientsBulkModal.expiryTime < 0 ? this.clientsBulkModal.expiryTime / -86400000 : 0; + }, + get datepicker() { + return app.datepicker; + }, + set delayedExpireDays(days) { + this.clientsBulkModal.expiryTime = -86400000 * days; + }, + }, + }); + +</script> +{{end}}
\ No newline at end of file diff --git a/web/html/modals/client_modal.html b/web/html/modals/client_modal.html new file mode 100644 index 00000000..eba3c2c1 --- /dev/null +++ b/web/html/modals/client_modal.html @@ -0,0 +1,172 @@ +{{define "modals/clientsModal"}} +<a-modal id="client-modal" v-model="clientModal.visible" :title="clientModal.title" @ok="clientModal.ok" + :confirm-loading="clientModal.confirmLoading" :closable="true" :mask-closable="false" + :class="themeSwitcher.currentTheme" + :ok-text="clientModal.okText" cancel-text='{{ i18n "close" }}'> + <template v-if="isEdit"> + <a-tag v-if="isExpiry || isTrafficExhausted" color="red" :style="{ marginBottom: '10px', display: 'block', textAlign: 'center' }">Account is (Expired|Traffic Ended) And Disabled</a-tag> + </template> + {{template "form/client"}} +</a-modal> +<script> + + const clientModal = { + visible: false, + confirmLoading: false, + title: '', + okText: '', + isEdit: false, + dbInbound: new DBInbound(), + inbound: new Inbound(), + clients: [], + clientStats: [], + oldClientId: "", + index: null, + clientIps: null, + delayedStart: false, + ok() { + if (clientModal.isEdit) { + ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id, clientModal.oldClientId); + } else { + ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id); + } + }, + show({ title = '', okText = '{{ i18n "sure" }}', index = null, dbInbound = null, confirm = () => { }, isEdit = false }) { + this.visible = true; + this.title = title; + this.okText = okText; + this.isEdit = isEdit; + this.dbInbound = new DBInbound(dbInbound); + this.inbound = dbInbound.toInbound(); + this.clients = this.inbound.clients; + this.index = index === null ? this.clients.length : index; + this.delayedStart = false; + if (isEdit) { + if (this.clients[index].expiryTime < 0) { + this.delayedStart = true; + } + this.oldClientId = this.getClientId(dbInbound.protocol, clients[index]); + } else { + this.addClient(this.inbound.protocol, this.clients); + } + this.clientStats = this.dbInbound.clientStats.find(row => row.email === this.clients[this.index].email); + this.confirm = confirm; + }, + getClientId(protocol, client) { + switch (protocol) { + case Protocols.TROJAN: return client.password; + case Protocols.SHADOWSOCKS: return client.email; + default: return client.id; + } + }, + addClient(protocol, clients) { + switch (protocol) { + case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.VMESS()); + case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS()); + case Protocols.TROJAN: return clients.push(new Inbound.TrojanSettings.Trojan()); + case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks(clients[0].method)); + default: return null; + } + }, + close() { + clientModal.visible = false; + clientModal.loading(false); + }, + loading(loading=true) { + clientModal.confirmLoading = loading; + }, + }; + + const clientModalApp = new Vue({ + delimiters: ['[[', ']]'], + el: '#client-modal', + data: { + clientModal, + get inbound() { + return this.clientModal.inbound; + }, + get client() { + return this.clientModal.clients[this.clientModal.index]; + }, + get clientStats() { + return this.clientModal.clientStats; + }, + get isEdit() { + return this.clientModal.isEdit; + }, + get datepicker() { + return app.datepicker; + }, + get isTrafficExhausted() { + if (!clientStats) return false + if (clientStats.total <= 0) return false + if (clientStats.up + clientStats.down < clientStats.total) return false + return true + }, + get isExpiry() { + return this.clientModal.isEdit && this.client.expiryTime >0 ? (this.client.expiryTime < new Date().getTime()) : false; + }, + get delayedStart() { + return this.clientModal.delayedStart; + }, + set delayedStart(value) { + this.clientModal.delayedStart = value; + }, + get delayedExpireDays() { + return this.client && this.client.expiryTime < 0 ? this.client.expiryTime / -86400000 : 0; + }, + set delayedExpireDays(days) { + this.client.expiryTime = -86400000 * days; + }, + }, + methods: { + async getDBClientIps(email) { + const msg = await HttpUtil.post(`/panel/inbound/clientIps/${email}`); + if (!msg.success) { + document.getElementById("clientIPs").value = msg.obj; + return; + } + let ips = msg.obj; + if (typeof ips === 'string' && ips.startsWith('[') && ips.endsWith(']')) { + try { + ips = JSON.parse(ips); + ips = Array.isArray(ips) ? ips.join("\n") : ips; + } catch (e) { + console.error('Error parsing JSON:', e); + } + } + document.getElementById("clientIPs").value = ips; + }, + async clearDBClientIps(email) { + try { + const msg = await HttpUtil.post(`/panel/inbound/clearClientIps/${email}`); + if (!msg.success) { + return; + } + document.getElementById("clientIPs").value = ""; + } catch (error) { + } + }, + resetClientTraffic(email, dbInboundId, iconElement) { + this.$confirm({ + title: '{{ i18n "pages.inbounds.resetTraffic"}}', + content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', + class: themeSwitcher.currentTheme, + okText: '{{ i18n "reset"}}', + cancelText: '{{ i18n "cancel"}}', + onOk: async () => { + iconElement.disabled = true; + const msg = await HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + email); + if (msg.success) { + this.clientModal.clientStats.up = 0; + this.clientModal.clientStats.down = 0; + } + iconElement.disabled = false; + }, + }) + }, + }, + }); + +</script> +{{end}} diff --git a/web/html/modals/dns_modal.html b/web/html/modals/dns_modal.html new file mode 100644 index 00000000..e6266c06 --- /dev/null +++ b/web/html/modals/dns_modal.html @@ -0,0 +1,114 @@ +{{define "modals/dnsModal"}} +<a-modal id="dns-modal" v-model="dnsModal.visible" :title="dnsModal.title" @ok="dnsModal.ok" :closable="true" + :mask-closable="false" :ok-text="dnsModal.okText" cancel-text='{{ i18n "close" }}' + :class="themeSwitcher.currentTheme"> + <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> + <a-form-item label='{{ i18n "pages.xray.outbound.address" }}'> + <a-input v-model.trim="dnsModal.dnsServer.address"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.xray.dns.domains" }}'> + <a-button icon="plus" size="small" type="primary" @click="dnsModal.dnsServer.domains.push('')"></a-button> + <template v-for="(domain, index) in dnsModal.dnsServer.domains"> + <a-input v-model.trim="dnsModal.dnsServer.domains[index]"> + <a-button icon="minus" size="small" slot="addonAfter" + @click="dnsModal.dnsServer.domains.splice(index,1)"></a-button> + </a-input> + </template> + </a-form-item> + <a-form-item label='{{ i18n "pages.xray.dns.strategy" }}' v-if="isAdvanced"> + <a-select v-model="dnsModal.dnsServer.queryStrategy" :style="{ width: '100%' }" + :dropdown-class-name="themeSwitcher.currentTheme"> + <a-select-option :value="l" :label="l" v-for="l in ['UseIP', 'UseIPv4', 'UseIPv6']"> [[ l ]] </a-select-option> + </a-select> + </a-form-item> + <a-form-item label='Skip Fallback' v-if="isAdvanced"> + <a-switch v-model="dnsModal.dnsServer.skipFallback"></a-switch> + </a-form-item> + <a-form-item label='{{ i18n "pages.xray.dns.expectIPs"}}'> + <a-button icon="plus" size="small" type="primary" @click="dnsModal.dnsServer.expectIPs.push('')"></a-button> + <template v-for="(domain, index) in dnsModal.dnsServer.expectIPs"> + <a-input v-model.trim="dnsModal.dnsServer.expectIPs[index]"> + <a-button icon="minus" size="small" slot="addonAfter" + @click="dnsModal.dnsServer.expectIPs.splice(index,1)"></a-button> + </a-input> + </template> + </a-form-item> + </a-form> +</a-modal> +<script> + const dnsModal = { + title: '', + visible: false, + okText: '{{ i18n "confirm" }}', + isEdit: false, + confirm: null, + dnsServer: { + address: "localhost", + domains: [], + expectIPs: [], + queryStrategy: 'UseIP', + skipFallback: true, + }, + ok() { + domains = dnsModal.dnsServer.domains.filter(d => d.length > 0); + expectIPs = dnsModal.dnsServer.expectIPs.filter(ip => ip.length > 0); + dnsModal.dnsServer.domains = domains; + dnsModal.dnsServer.expectIPs = expectIPs; + newDnsServer = (domains.length > 0 || expectIPs.length > 0) ? dnsModal.dnsServer : dnsModal.dnsServer.address; + ObjectUtil.execute(dnsModal.confirm, newDnsServer); + }, + + show({ + title = '', + okText = '{{ i18n "confirm" }}', + dnsServer, + confirm = (dnsServer) => { }, + isEdit = false + }) { + this.title = title; + this.okText = okText; + this.confirm = confirm; + this.visible = true; + if (isEdit) { + if (typeof dnsServer == 'object') { + this.dnsServer = dnsServer; + } else { + this.dnsServer = { + address: dnsServer ?? "", + domains: [], + expectIPs: [], + queryStrategy: 'UseIP', + skipFallback: true, + } + } + } else { + this.dnsServer = { + address: "localhost", + domains: [], + expectIPs: [], + queryStrategy: 'UseIP', + skipFallback: true, + } + } + this.isEdit = isEdit; + }, + close() { + dnsModal.visible = false; + }, + }; + new Vue({ + delimiters: ['[[', ']]'], + el: '#dns-modal', + data: { + dnsModal: dnsModal, + }, + computed: { + isAdvanced: { + get: function () { + return dnsModal.dnsServer.domains.length > 0; + } + } + } + }); +</script> +{{end}}
\ No newline at end of file diff --git a/web/html/modals/fakedns_modal.html b/web/html/modals/fakedns_modal.html new file mode 100644 index 00000000..8e554ac0 --- /dev/null +++ b/web/html/modals/fakedns_modal.html @@ -0,0 +1,57 @@ +{{define "modals/fakednsModal"}} +<a-modal id="fakedns-modal" v-model="fakednsModal.visible" :title="fakednsModal.title" @ok="fakednsModal.ok" + :closable="true" :mask-closable="false" + :ok-text="fakednsModal.okText" cancel-text='{{ i18n "close" }}' :class="themeSwitcher.currentTheme"> + <a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }"> + <a-form-item label='{{ i18n "pages.xray.fakedns.ipPool" }}'> + <a-input v-model.trim="fakednsModal.fakeDns.ipPool"></a-input> + </a-form-item> + <a-form-item label='{{ i18n "pages.xray.fakedns.poolSize" }}'> + <a-input-number v-model.number="fakednsModal.fakeDns.poolSize" :min="1"></a-input-number> + </a-form-item> + </a-form> +</a-modal> +<script> + const fakednsModal = { + title: '', + visible: false, + okText: '{{ i18n "confirm" }}', + isEdit: false, + confirm: null, + fakeDns: { + ipPool: "198.18.0.0/16", + poolSize: 65535, + }, + ok() { + ObjectUtil.execute(fakednsModal.confirm, fakednsModal.fakeDns); + }, + show({ title='', okText='{{ i18n "confirm" }}', fakeDns, confirm=(fakeDns)=>{}, isEdit=false }) { + this.title = title; + this.okText = okText; + this.confirm = confirm; + this.visible = true; + if(isEdit) { + this.fakeDns = fakeDns; + } else { + this.fakeDns = { + ipPool: "198.18.0.0/16", + poolSize: 65535, + } + } + this.isEdit = isEdit; + }, + close() { + fakednsModal.visible = false; + }, + }; + + new Vue({ + delimiters: ['[[', ']]'], + el: '#fakedns-modal', + data: { + fakednsModal: fakednsModal, + } + }); + +</script> +{{end}} diff --git a/web/html/modals/inbound_info_modal.html b/web/html/modals/inbound_info_modal.html new file mode 100644 index 00000000..0ccaeff0 --- /dev/null +++ b/web/html/modals/inbound_info_modal.html @@ -0,0 +1,572 @@ +{{define "modals/inboundInfoModal"}} +<a-modal id="inbound-info-modal" v-model="infoModal.visible" title='{{ i18n "pages.inbounds.details"}}' :closable="true" :mask-closable="true" :footer="null" width="600px" :class="themeSwitcher.currentTheme"> + <a-row> + <a-col :xs="24" :md="12"> + <table> + <tr> + <td>{{ i18n "protocol" }}</td> + <td> + <a-tag color="purple">[[ dbInbound.protocol ]]</a-tag> + </td> + </tr> + <tr> + <td>{{ i18n "pages.inbounds.address" }}</td> + <td> + <a-tooltip :title="[[ dbInbound.address ]]"> + <a-tag class="info-large-tag">[[ dbInbound.address ]]</a-tag> + </a-tooltip> + </td> + </tr> + <tr> + <td>{{ i18n "pages.inbounds.port" }}</td> + <td> + <a-tag>[[ dbInbound.port ]]</a-tag> + </td> + </tr> + </table> + </a-col> + <a-col :xs="24" :md="12"> + <template v-if="dbInbound.isVMess || dbInbound.isVLess || dbInbound.isTrojan || dbInbound.isSS"> + <table> + <tr> + <td>{{ i18n "transmission" }}</td> + <td> + <a-tag color="green">[[ inbound.network ]]</a-tag> + </td> + </tr> + <template v-if="inbound.isTcp || inbound.isWs || inbound.isHttpupgrade || inbound.isXHTTP"> + <tr> + <td>{{ i18n "host" }}</td> + <td v-if="inbound.host"> + <a-tooltip :title="[[ inbound.host ]]"> + <a-tag class="info-large-tag">[[ inbound.host ]]</a-tag> + </a-tooltip> + </td> + <td v-else> + <a-tag color="orange">{{ i18n "none" }}</a-tag> + </td> + </tr> + </tr> + <tr> + <td>{{ i18n "path" }}</td> + <td v-if="inbound.path"> + <a-tooltip :title="[[ inbound.path ]]"> + <a-tag class="info-large-tag">[[ inbound.path ]]</a-tag> + </a-tooltip> + <td v-else> + <a-tag color="orange">{{ i18n "none" }}</a-tag> + </td> + </tr> + </template> + <template v-if="inbound.isXHTTP"> + <tr> + <td>Mode</td> + <td> + <a-tag>[[ inbound.stream.xhttp.mode ]]</a-tag> + </td> + </tr> + </template> + <template v-if="inbound.isKcp"> + <tr> + <td>kcp {{ i18n "encryption" }}</td> + <td> + <a-tag>[[ inbound.kcpType ]]</a-tag> + </td> + </tr> + <tr> + <td>kcp {{ i18n "password" }}</td> + <td> + <a-tag>[[ inbound.kcpSeed ]]</a-tag> + </td> + </tr> + </template> + <template v-if="inbound.isGrpc"> + <tr> + <td>grpc serviceName</td> + <td> + <a-tooltip :title="[[ inbound.serviceName ]]"> + <a-tag class="info-large-tag">[[ inbound.serviceName ]]</a-tag> + </a-tooltip> + <tr> + <td>grpc multiMode</td> + <td> + <a-tag>[[ inbound.stream.grpc.multiMode ]]</a-tag> + </td> + </tr> + </template> + </table> + </template> + </a-col> + <template v-if="dbInbound.hasLink()"> + {{ i18n "security" }} + <a-tag :color="inbound.stream.security == 'none' ? 'red' : 'green'">[[ inbound.stream.security ]]</a-tag> + <br /> + <template v-if="inbound.stream.security != 'none'"> + {{ i18n "domainName" }} + <a-tag v-if="inbound.serverName" :color="inbound.serverName ? 'green' : 'orange'">[[ inbound.serverName ? inbound.serverName : '' ]]</a-tag> + <a-tag v-else color="orange">{{ i18n "none" }}</a-tag> + </template> + </template> + <table v-if="dbInbound.isSS" :style="{ marginBottom: '10px', width: '100%' }"> + <tr> + <td>{{ i18n "encryption" }}</td> + <td> + <a-tag color="green">[[ inbound.settings.method ]]</a-tag> + </td> + </tr> + <tr v-if="inbound.isSS2022"> + <td>{{ i18n "password" }}</td> + <td> + <a-tooltip :title="[[ inbound.settings.password ]]"> + <a-tag class="info-large-tag">[[ inbound.settings.password ]]</a-tag> + </a-tooltip> + </td> + </tr> + <tr> + <td>{{ i18n "pages.inbounds.network" }}</td> + <td> + <a-tag color="green">[[ inbound.settings.network ]]</a-tag> + </td> + </tr> + </table> + <template v-if="infoModal.clientSettings"> + <a-divider>{{ i18n "pages.inbounds.client" }}</a-divider> + <table :style="{ marginBottom: '10px' }"> + <tr> + <td>{{ i18n "pages.inbounds.email" }}</td> + <td v-if="infoModal.clientSettings.email"> + <a-tag color="green">[[ infoModal.clientSettings.email ]]</a-tag> + </td> + <td v-else> + <a-tag color="red">{{ i18n "none" }}</a-tag> + </td> + </tr> + <tr v-if="infoModal.clientSettings.id"> + <td>ID</td> + <td> + <a-tag>[[ infoModal.clientSettings.id ]]</a-tag> + </td> + </tr> + <tr v-if="dbInbound.isVMess"> + <td>{{ i18n "security" }}</td> + <td> + <a-tag>[[ infoModal.clientSettings
|
