|
@@ -167,7 +167,10 @@
|
|
<span>{{ i18n "pages.index.xrayErrorPopoverTitle" }}</span>
|
|
<span>{{ i18n "pages.index.xrayErrorPopoverTitle" }}</span>
|
|
</a-col>
|
|
</a-col>
|
|
<a-col>
|
|
<a-col>
|
|
- <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openLogs()"></a-tag>
|
|
|
|
|
|
+ <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openLogs()"></a-icon>
|
|
|
|
+ </a-col>
|
|
|
|
+ <a-col>
|
|
|
|
+ <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openXrayLogs()"></a-icon>
|
|
</a-col>
|
|
</a-col>
|
|
</a-row>
|
|
</a-row>
|
|
</span>
|
|
</span>
|
|
@@ -179,6 +182,10 @@
|
|
</template>
|
|
</template>
|
|
</template>
|
|
</template>
|
|
<template #actions>
|
|
<template #actions>
|
|
|
|
+ <a-space v-if="app.ipLimitEnable" direction="horizontal" @click="openXrayLogs()" :style="{ justifyContent: 'center' }">
|
|
|
|
+ <a-icon type="bars"></a-icon>
|
|
|
|
+ <span v-if="!isMobile">{{ i18n "pages.index.logs" }}</span>
|
|
|
|
+ </a-space>
|
|
<a-space direction="horizontal" @click="stopXrayService" :style="{ justifyContent: 'center' }">
|
|
<a-space direction="horizontal" @click="stopXrayService" :style="{ justifyContent: 'center' }">
|
|
<a-icon type="poweroff"></a-icon>
|
|
<a-icon type="poweroff"></a-icon>
|
|
<span v-if="!isMobile">{{ i18n "pages.index.stopXray" }}</span>
|
|
<span v-if="!isMobile">{{ i18n "pages.index.stopXray" }}</span>
|
|
@@ -422,6 +429,40 @@
|
|
</a-form>
|
|
</a-form>
|
|
<div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="logModal.formattedLogs"></div>
|
|
<div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="logModal.formattedLogs"></div>
|
|
</a-modal>
|
|
</a-modal>
|
|
|
|
+ <a-modal id="xraylog-modal"
|
|
|
|
+ v-model="xraylogModal.visible"
|
|
|
|
+ :closable="true" @cancel="() => xraylogModal.visible = false"
|
|
|
|
+ :class="themeSwitcher.currentTheme"
|
|
|
|
+ width="80vw"
|
|
|
|
+ footer="">
|
|
|
|
+ <template slot="title">
|
|
|
|
+ {{ i18n "pages.index.logs" }}
|
|
|
|
+ <a-icon :spin="xraylogModal.loading"
|
|
|
|
+ type="sync"
|
|
|
|
+ :style="{ verticalAlign: 'middle', marginLeft: '10px' }"
|
|
|
|
+ :disabled="xraylogModal.loading"
|
|
|
|
+ @click="openXrayLogs()">
|
|
|
|
+ </a-icon>
|
|
|
|
+ </template>
|
|
|
|
+ <a-form layout="inline">
|
|
|
|
+ <a-form-item :style="{ marginRight: '0.5rem' }">
|
|
|
|
+ <a-input-group compact>
|
|
|
|
+ <a-select size="small" v-model="xraylogModal.rows" :style="{ width: '70px' }"
|
|
|
|
+ @change="openXrayLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
|
|
|
|
+ <a-select-option value="10">10</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="100">100</a-select-option>
|
|
|
|
+ <a-select-option value="500">500</a-select-option>
|
|
|
|
+ </a-select>
|
|
|
|
+ </a-input-group>
|
|
|
|
+ </a-form-item>
|
|
|
|
+ <a-form-item :style="{ float: 'right' }">
|
|
|
|
+ <a-button type="primary" icon="download" @click="FileManager.downloadTextFile(xraylogModal.logs?.join('\n'), 'x-ui.log')"></a-button>
|
|
|
|
+ </a-form-item>
|
|
|
|
+ </a-form>
|
|
|
|
+ <div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="xraylogModal.formattedLogs"></div>
|
|
|
|
+ </a-modal>
|
|
<a-modal id="backup-modal"
|
|
<a-modal id="backup-modal"
|
|
v-model="backupModal.visible"
|
|
v-model="backupModal.visible"
|
|
title='{{ i18n "pages.index.backupTitle" }}'
|
|
title='{{ i18n "pages.index.backupTitle" }}'
|
|
@@ -606,6 +647,57 @@
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ const xraylogModal = {
|
|
|
|
+ visible: false,
|
|
|
|
+ logs: [],
|
|
|
|
+ rows: 20,
|
|
|
|
+ loading: false,
|
|
|
|
+ show(logs) {
|
|
|
|
+ this.visible = true;
|
|
|
|
+ this.logs = logs;
|
|
|
|
+ this.formattedLogs = this.logs?.length > 0 ? this.formatLogs(this.logs) : "No Record...";
|
|
|
|
+ },
|
|
|
|
+ formatLogs(logs) {
|
|
|
|
+ let formattedLogs = '';
|
|
|
|
+
|
|
|
|
+ logs.forEach((log, index) => {
|
|
|
|
+ if(index > 0) formattedLogs += '<br>';
|
|
|
|
+
|
|
|
|
+ const parts = log.split(' ');
|
|
|
|
+
|
|
|
|
+ if(parts.length === 9) {
|
|
|
|
+ const dateTime = `<b>${parts[0]} ${parts[1]}</b>`;
|
|
|
|
+ const from = `<b>${parts[3]}</b>`;
|
|
|
|
+ const to = `<b>${parts[5].replace(/^\/+/, "")}</b>`;
|
|
|
|
+
|
|
|
|
+ let outboundColor = '';
|
|
|
|
+ if (parts[8].startsWith('blocked')) {
|
|
|
|
+ outboundColor = ' style="color: #e04141;"';
|
|
|
|
+ }
|
|
|
|
+ else if (!parts[8].startsWith('direct')) {
|
|
|
|
+ outboundColor = ' style="color: #3c89e8;"';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ formattedLogs += `<span${outboundColor}>
|
|
|
|
+${dateTime}
|
|
|
|
+ ${parts[2]}
|
|
|
|
+ ${from}
|
|
|
|
+ ${parts[4]}
|
|
|
|
+ ${to}
|
|
|
|
+ ${parts.slice(6).join(' ')}
|
|
|
|
+</span>`;
|
|
|
|
+ } else {
|
|
|
|
+ formattedLogs += `<span>${parts.join(' ')}</span>`;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ return formattedLogs;
|
|
|
|
+ },
|
|
|
|
+ hide() {
|
|
|
|
+ this.visible = false;
|
|
|
|
+ },
|
|
|
|
+ };
|
|
|
|
+
|
|
const backupModal = {
|
|
const backupModal = {
|
|
visible: false,
|
|
visible: false,
|
|
show() {
|
|
show() {
|
|
@@ -629,10 +721,12 @@
|
|
status: new Status(),
|
|
status: new Status(),
|
|
versionModal,
|
|
versionModal,
|
|
logModal,
|
|
logModal,
|
|
|
|
+ xraylogModal,
|
|
backupModal,
|
|
backupModal,
|
|
loadingTip: '{{ i18n "loading"}}',
|
|
loadingTip: '{{ i18n "loading"}}',
|
|
showAlert: false,
|
|
showAlert: false,
|
|
- showIp: false
|
|
|
|
|
|
+ showIp: false,
|
|
|
|
+ ipLimitEnable: false,
|
|
},
|
|
},
|
|
methods: {
|
|
methods: {
|
|
loading(spinning, tip = '{{ i18n "loading"}}') {
|
|
loading(spinning, tip = '{{ i18n "loading"}}') {
|
|
@@ -721,6 +815,16 @@
|
|
await PromiseUtil.sleep(500);
|
|
await PromiseUtil.sleep(500);
|
|
logModal.loading = false;
|
|
logModal.loading = false;
|
|
},
|
|
},
|
|
|
|
+ async openXrayLogs(){
|
|
|
|
+ xraylogModal.loading = true;
|
|
|
|
+ const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows);
|
|
|
|
+ if (!msg.success) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ xraylogModal.show(msg.obj);
|
|
|
|
+ await PromiseUtil.sleep(500);
|
|
|
|
+ xraylogModal.loading = false;
|
|
|
|
+ },
|
|
async openConfig() {
|
|
async openConfig() {
|
|
this.loading(true);
|
|
this.loading(true);
|
|
const msg = await HttpUtil.post('server/getConfigJson');
|
|
const msg = await HttpUtil.post('server/getConfigJson');
|
|
@@ -773,6 +877,12 @@
|
|
if (window.location.protocol !== "https:") {
|
|
if (window.location.protocol !== "https:") {
|
|
this.showAlert = true;
|
|
this.showAlert = true;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ const msg = await HttpUtil.post('/panel/setting/defaultSettings');
|
|
|
|
+ if (msg.success) {
|
|
|
|
+ this.ipLimitEnable = msg.obj.ipLimitEnable;
|
|
|
|
+ }
|
|
|
|
+
|
|
while (true) {
|
|
while (true) {
|
|
try {
|
|
try {
|
|
await this.getStatus();
|
|
await this.getStatus();
|