Satur@it-depot.ru 2025-03-04 13:01:45 +03:00
parent 961d8981fc
commit ff30e857a7
4 changed files with 337 additions and 0 deletions

23
docker-compose.yml Normal file
View File

@ -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

60
frontend/index.html Normal file
View File

@ -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>

239
frontend/script.js Normal file
View File

@ -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}`;
}
}
};
});

15
frontend/style.css Normal file
View File

@ -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;
}