3x-ui/web/html/servers.html
2025-10-21 09:05:17 +03:00

277 lines
No EOL
13 KiB
HTML

{{ template "page/head_start" .}}
<!-- <link rel="stylesheet" href="{{ .base_path }}assets/jquery/jquery.modal.min.css" /> -->
<link rel="stylesheet" href="{{ .base_path }}assets/bootstrap/bootstrap.min.css">
{{ template "page/head_end" .}} {{ template
"page/body_start" .}}
<a-layout id="app" v-cloak :class="themeSwitcher.currentTheme + ' settings-page'">
<a-sidebar></a-sidebar>
<a-layout id="content-layout">
<a-layout-content>
<a-spin :spinning="loadingStates.spinning" :delay="500" tip='{{ i18n "loading"}}'>
<transition name="list" appear>
<a-alert type="error" v-if="confAlerts.length>0 && loadingStates.fetched"
:style="{ marginBottom: '10px' }" message='{{ i18n "secAlertTitle" }}' color="red" show-icon
slot="description">
<b>{{ i18n "secAlertConf" }}</b>
<ul>
<li v-for="a in confAlerts">[[ a ]]</li>
</ul>
</template>
</a-alert>
</transition>
<transition name="list" appear>
<template>
<div class="row" v-cloak>
<div class="col-md-12">
<div class="card-header">
<h3 class="card-title">Server Management</h3>
<div class="card-tools">
<button class="btn btn-primary" @click="showAddModal">Add Server</button>
</div>
</div>
<div class="card-body">
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Address</th>
<th>Port</th>
<th>Enabled</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<template v-if="servers.length>0">
<tr v-for="(server, index) in servers">
<td>[[ index + 1 ]]</td>
<td>[[ server.name ]]</td>
<td>[[ server.address ]]</td>
<td>[[ server.port ]]</td>
<td><span v-if="server.enable"
class="badge bg-success">Yes</span><span v-else
class="badge bg-danger">No</span>
</td>
<td><button class="btn btn-info btn-sm"
@click="showEditModal(server)">Edit</button><button
class="btn btn-danger btn-sm"
@click="deleteServer(server.id)">Delete</button></td>
</tr>
</template>
<tr v-else>
<td colspan="6" class="text-center">No servers found</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template>
</transition>
<transition>
<template>
<!-- Add/Edit Modal -->
<div class="modal fade" data-backdrop="false" id="serverModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">[[ modal.title ]]</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label>Name</label>
<input type="text" class="form-control" v-model="modal.server.name" />
</div>
<div class="form-group">
<label>Address (IP or Domain)</label>
<input type="text" class="form-control"
v-model="modal.server.address" />
</div>
<div class="form-group">
<label>Port</label>
<input type="number" class="form-control"
v-model.number="modal.server.port" />
</div>
<div class="form-group">
<label>API Key</label>
<input type="text" class="form-control" v-model="modal.server.apiKey" />
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input"
v-model="modal.server.enable" />
<label class="form-check-label">Enabled</label>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
Close
</button>
<button type="button" class="btn btn-primary" @click="saveServer">
Save
</button>
</div>
</div>
</div>
</div>
</template>
</transition>
</a-spin>
</a-layout-content>
</a-layout>
</a-layout>
{{template "page/body_scripts" .}} {{template "component/aSidebar" .}}
{{template "component/aThemeSwitch" .}}
<!-- <script src="{{ .base_path }}assets/jquery/jquery.min.js"></script> -->
<!--<script src="{{ .base_path }}assets/jquery/jquery.modal.min.js"></script> -->
<script src="{{ .base_path }}assets/bootstrap/bootstrap.min.js"></script>
<script>
const app = new Vue({
delimiters: ["[[", "]]"],
mixins: [MediaQueryMixin],
el: "#app",
data: {
themeSwitcher,
loadingStates: {
fetched: false,
spinning: false,
},
servers: [],
modal: {
title: "",
server: {
name: "",
address: "",
port: 0,
apiKey: "",
enable: true,
},
},
},
methods: {
loadServers() {
axios.get('{{.base_path}}panel/api/servers/list')
.then(response => {
this.servers = response.data.obj;
if (this.servers.length == 0) {
}
})
.catch(error => {
alert(error);
});
},
showAddModal() {
this.modal.title = "Add Server";
this.modal.server = {
name: "",
address: "",
port: 0,
apiKey: "",
enable: true,
};
const modalEl = document.getElementById('serverModal');
const modal = new bootstrap.Modal(modalEl);
modal.show();
},
showEditModal(server) {
this.modal.title = "Edit Server";
this.modal.server = Object.assign({}, server);
const modalEl = document.getElementById('serverModal');
const modal = new bootstrap.Modal(modalEl);
modal.show();
},
saveServer() {
let url = "/panel/api/servers/add";
if (this.modal.server.id) {
url = `/panel/api/servers/update/${this.modal.server.id}`;
}
console.log(this.modal.server);
axios
.post(url, this.modal.server)
.then((response) => {
alert(response.data.msg);
const modalEl = document.getElementById('serverModal');
const modal = bootstrap.Modal.getInstance(modalEl);
modal.hide();
this.loadServers();
})
.catch((error) => {
alert(error.response.data.msg);
});
},
deleteServer(id) {
if (!confirm("Are you sure you want to delete this server?")) {
return;
}
axios
.post(`/panel/api/servers/del/${id}`)
.then((response) => {
alert(response.data.msg);
this.loadServers();
})
.catch((error) => {
alert(error.response.data.msg);
});
},
},
computed: {
confAlerts: {
get: function () {
if (!this.allSetting) return [];
var alerts = [];
if (window.location.protocol !== "https:")
alerts.push('{{ i18n "secAlertSSL" }}');
if (this.allSetting.webPort === 2053)
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" }}');
}
if (this.allSetting.subJsonEnable) {
subJsonPath =
this.allSetting.subJsonURI.length > 0
? new URL(this.allSetting.subJsonURI).pathname
: this.allSetting.subJsonPath;
if (subJsonPath == "/json/")
alerts.push('{{ i18n "secAlertSubJsonURI" }}');
}
return alerts;
},
},
},
mounted() {
this.loadServers();
},
});
</script>
{{ template "page/body_end" .}}