fix
parent
961d8981fc
commit
ff30e857a7
|
|
@ -0,0 +1,23 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8001:8001" # Порт для FastAPI
|
||||||
|
volumes:
|
||||||
|
- ./db:/db # Монтирование базы данных
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: nginx:latest
|
||||||
|
ports:
|
||||||
|
- "8081:80" # Порт для фронтенда
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/usr/share/nginx/html # Монтирование фронтенда
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: sqlite3:latest # Или используй существующий volume с rustdesk.db
|
||||||
|
volumes:
|
||||||
|
- ./db:/db
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Адресная книга подключений</title>
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/jquery.dataTables.min.css">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Адресная книга подключений</h1>
|
||||||
|
|
||||||
|
<!-- Панель управления папками -->
|
||||||
|
<div class="folder-controls">
|
||||||
|
<h2>Управление папками</h2>
|
||||||
|
<input type="text" id="folderName" placeholder="Имя папки">
|
||||||
|
<select id="parentFolder">
|
||||||
|
<option value="">Корневая папка</option>
|
||||||
|
</select>
|
||||||
|
<button onclick="createFolder()">Создать папку</button>
|
||||||
|
<button onclick="editFolder()">Редактировать папку</button>
|
||||||
|
<button onclick="deleteFolder()">Удалить папку</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Форма для добавления подключения -->
|
||||||
|
<div class="connection-controls">
|
||||||
|
<h2>Добавить подключение</h2>
|
||||||
|
<form id="addConnectionForm">
|
||||||
|
<input type="text" id="connectionId" placeholder="ID подключения" required>
|
||||||
|
<input type="text" id="connectionName" placeholder="Имя подключения" required>
|
||||||
|
<select id="connectionType">
|
||||||
|
<option value="RustDesk">RustDesk</option>
|
||||||
|
<option value="SSH">SSH</option>
|
||||||
|
<option value="RDP">RDP</option>
|
||||||
|
</select>
|
||||||
|
<select id="connectionFolder">
|
||||||
|
<option value="">Без папки</option>
|
||||||
|
</select>
|
||||||
|
<button type="submit">Добавить</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Таблица подключений -->
|
||||||
|
<table id="connectionsTable" class="display">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Connection ID</th>
|
||||||
|
<th>Имя</th>
|
||||||
|
<th>Тип</th>
|
||||||
|
<th>Папка</th>
|
||||||
|
<th>Действие</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,239 @@
|
||||||
|
const API_URL = "http://localhost:8001/api";
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
loadFolders();
|
||||||
|
loadConnections();
|
||||||
|
|
||||||
|
// Загрузка папок
|
||||||
|
function loadFolders() {
|
||||||
|
$.getJSON(`${API_URL}/folders`, function (folders) {
|
||||||
|
$('#parentFolder, #connectionFolder').empty();
|
||||||
|
$('#parentFolder, #connectionFolder').append('<option value="">Корневая папка</option>');
|
||||||
|
folders.forEach(folder => {
|
||||||
|
$('#parentFolder, #connectionFolder').append(
|
||||||
|
`<option value="${folder.id}">${folder.name} (ID: ${folder.id})</option>`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Загрузка подключений в таблицу
|
||||||
|
function loadConnections() {
|
||||||
|
$.getJSON(`${API_URL}/connections`, function (data) {
|
||||||
|
let table = $('#connectionsTable').DataTable({
|
||||||
|
"destroy": true,
|
||||||
|
"data": data,
|
||||||
|
"columns": [
|
||||||
|
{ "data": "id" },
|
||||||
|
{
|
||||||
|
"data": "connection_id",
|
||||||
|
"render": function (data, type, row) {
|
||||||
|
if (row.type === "RustDesk") {
|
||||||
|
return `<a href="rustdesk://${data}" onclick="openRustDesk('${data}'); return false;">${data}</a>`;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "data": "name" },
|
||||||
|
{ "data": "type" },
|
||||||
|
{
|
||||||
|
"data": "folder_id",
|
||||||
|
"render": function (data, type, row) {
|
||||||
|
return data ? getFolderName(data) : "Без папки";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": "id",
|
||||||
|
"render": function (data) {
|
||||||
|
return `
|
||||||
|
<button onclick="editConnection(${data})">Редактировать</button>
|
||||||
|
<button onclick="deleteConnection(${data})">Удалить</button>
|
||||||
|
<button onclick="moveConnection(${data})">Переместить</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение имени папки по ID
|
||||||
|
function getFolderName(folderId) {
|
||||||
|
let folderName = "Без папки";
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/folders/${folderId}`,
|
||||||
|
async: false,
|
||||||
|
success: function (folder) {
|
||||||
|
folderName = folder.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return folderName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создание папки
|
||||||
|
window.createFolder = function () {
|
||||||
|
let name = $('#folderName').val();
|
||||||
|
let parentId = $('#parentFolder').val() || null;
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/folders`,
|
||||||
|
type: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify({ name, parent_id: parentId }),
|
||||||
|
success: function () {
|
||||||
|
alert("Папка создана!");
|
||||||
|
loadFolders();
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Редактирование папки (пример, нужно уточнить UI)
|
||||||
|
window.editFolder = function () {
|
||||||
|
let folderId = prompt("Введите ID папки для редактирования:");
|
||||||
|
if (folderId) {
|
||||||
|
let name = prompt("Новое имя папки:");
|
||||||
|
let parentId = prompt("ID родительской папки (оставьте пустым для корневой):") || null;
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/folders/${folderId}`,
|
||||||
|
type: 'PUT',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify({ name, parent_id: parentId }),
|
||||||
|
success: function () {
|
||||||
|
alert("Папка обновлена!");
|
||||||
|
loadFolders();
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Удаление папки
|
||||||
|
window.deleteFolder = function () {
|
||||||
|
let folderId = prompt("Введите ID папки для удаления:");
|
||||||
|
if (folderId && confirm("Вы уверены?")) {
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/folders/${folderId}`,
|
||||||
|
type: 'DELETE',
|
||||||
|
success: function () {
|
||||||
|
alert("Папка удалена!");
|
||||||
|
loadFolders();
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Добавление подключения
|
||||||
|
$('#addConnectionForm').submit(function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
let connectionId = $('#connectionId').val();
|
||||||
|
let name = $('#connectionName').val();
|
||||||
|
let type = $('#connectionType').val();
|
||||||
|
let folderId = $('#connectionFolder').val() || null;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/connections`,
|
||||||
|
type: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify({ connection_id: connectionId, name, type, folder_id: folderId }),
|
||||||
|
success: function () {
|
||||||
|
alert("Подключение добавлено!");
|
||||||
|
loadConnections();
|
||||||
|
$('#addConnectionForm')[0].reset();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Редактирование подключения
|
||||||
|
window.editConnection = function (id) {
|
||||||
|
let connection = promptConnectionDetails(id);
|
||||||
|
if (connection) {
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/connections/${id}`,
|
||||||
|
type: 'PUT',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(connection),
|
||||||
|
success: function () {
|
||||||
|
alert("Подключение обновлено!");
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Удаление подключения
|
||||||
|
window.deleteConnection = function (id) {
|
||||||
|
if (confirm("Вы уверены, что хотите удалить подключение?")) {
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/connections/${id}`,
|
||||||
|
type: 'DELETE',
|
||||||
|
success: function () {
|
||||||
|
alert("Подключение удалено!");
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Перемещение подключения
|
||||||
|
window.moveConnection = function (id) {
|
||||||
|
let folderId = prompt("Введите ID папки для перемещения (оставьте пустым для корневой):") || null;
|
||||||
|
$.ajax({
|
||||||
|
url: `${API_URL}/connections/${id}`,
|
||||||
|
type: 'PUT',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify({ folder_id: folderId }),
|
||||||
|
success: function () {
|
||||||
|
alert("Подключение перемещено!");
|
||||||
|
loadConnections();
|
||||||
|
},
|
||||||
|
error: function (xhr) {
|
||||||
|
alert("Ошибка: " + xhr.responseJSON.detail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для запроса деталей подключения через prompt (можно улучшить с модальным окном)
|
||||||
|
function promptConnectionDetails(id) {
|
||||||
|
let connectionId = prompt("Новый ID подключения:");
|
||||||
|
let name = prompt("Новое имя подключения:");
|
||||||
|
let type = prompt("Новый тип подключения (RustDesk, SSH, RDP):");
|
||||||
|
let folderId = prompt("ID папки (оставьте пустым для корневой):") || null;
|
||||||
|
if (connectionId && name && type) {
|
||||||
|
return { connection_id: connectionId, name, type, folder_id: folderId };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка клика по RustDesk ссылке
|
||||||
|
window.openRustDesk = function(rustId) {
|
||||||
|
if (confirm("Подключиться к устройству с ID " + rustId + "?")) {
|
||||||
|
if (typeof navigator.msLaunchUri !== 'undefined') {
|
||||||
|
navigator.msLaunchUri(`rustdesk://${rustId}`,
|
||||||
|
function() { console.log("Успешно запущен RustDesk"); },
|
||||||
|
function() { alert("Не удалось запустить RustDesk. Убедитесь, что RustDesk установлен и зарегистрирован для обработки rustdesk://."); }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
window.location.href = `rustdesk://${rustId}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.folder-controls, .connection-controls {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select, button {
|
||||||
|
margin: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue