New
parent
607af48ad2
commit
01b1515172
|
|
@ -0,0 +1,8 @@
|
|||
FROM python:3.11-slim
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY app.py .
|
||||
COPY templates/ ./templates/
|
||||
EXPOSE 8001
|
||||
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8001"]
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
import sqlite3
|
||||
import datetime
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Соединение с базой данных
|
||||
conn = sqlite3.connect("/db/rustdesk.db", check_same_thread=False)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Создаем таблицы
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS folders (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
parent_id INTEGER,
|
||||
FOREIGN KEY (parent_id) REFERENCES folders(id)
|
||||
)
|
||||
""")
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS installs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
rust_id TEXT,
|
||||
computer_name TEXT,
|
||||
install_time TEXT,
|
||||
folder_id INTEGER,
|
||||
FOREIGN KEY (folder_id) REFERENCES folders(id)
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
|
||||
# Модели данных
|
||||
class Folder(BaseModel):
|
||||
name: str
|
||||
parent_id: int | None = None
|
||||
|
||||
class FolderUpdate(BaseModel):
|
||||
name: str
|
||||
|
||||
class InstallData(BaseModel):
|
||||
rust_id: str
|
||||
computer_name: str
|
||||
install_time: str | None = None
|
||||
folder_id: int | None = None
|
||||
|
||||
# Монтируем папку templates как статические файлы
|
||||
app.mount("/templates", StaticFiles(directory="templates"), name="templates")
|
||||
|
||||
# Главная страница
|
||||
@app.get("/")
|
||||
async def root():
|
||||
return FileResponse("templates/index.html")
|
||||
|
||||
# --- Folders API ---
|
||||
@app.get("/api/folders")
|
||||
def get_folders():
|
||||
cursor.execute("SELECT * FROM folders")
|
||||
rows = cursor.fetchall()
|
||||
return [{"id": row[0], "name": row[1], "parent_id": row[2]} for row in rows]
|
||||
|
||||
@app.post("/api/folders")
|
||||
def add_folder(folder: Folder):
|
||||
cursor.execute("INSERT INTO folders (name, parent_id) VALUES (?, ?)",
|
||||
(folder.name, folder.parent_id))
|
||||
conn.commit()
|
||||
return {"status": "success", "id": cursor.lastrowid}
|
||||
|
||||
@app.put("/api/folders/{folder_id}")
|
||||
def update_folder(folder_id: int, folder: FolderUpdate):
|
||||
cursor.execute("UPDATE folders SET name = ? WHERE id = ?", (folder.name, folder_id))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=404, detail="Папка не найдена")
|
||||
return {"status": "success"}
|
||||
|
||||
@app.delete("/api/folders/{folder_id}")
|
||||
def delete_folder(folder_id: int):
|
||||
cursor.execute("DELETE FROM folders WHERE id = ?", (folder_id,))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=404, detail="Папка не найдена")
|
||||
return {"status": "success"}
|
||||
|
||||
# --- Installs API ---
|
||||
@app.get("/api/installs")
|
||||
def get_installs():
|
||||
cursor.execute("""
|
||||
SELECT i.id, i.rust_id, i.computer_name, i.install_time, i.folder_id, f.name as folder_name
|
||||
FROM installs i
|
||||
LEFT JOIN folders f ON i.folder_id = f.id
|
||||
""")
|
||||
rows = cursor.fetchall()
|
||||
return [{"id": row[0], "rust_id": row[1], "computer_name": row[2],
|
||||
"install_time": row[3], "folder_id": row[4], "folder_name": row[5]}
|
||||
for row in rows]
|
||||
|
||||
@app.post("/api/install")
|
||||
def add_install(data: InstallData):
|
||||
install_time = data.install_time or datetime.datetime.now().isoformat()
|
||||
cursor.execute("INSERT INTO installs (rust_id, computer_name, install_time, folder_id) VALUES (?, ?, ?, ?)",
|
||||
(data.rust_id, data.computer_name, install_time, data.folder_id))
|
||||
conn.commit()
|
||||
return {"status": "success"}
|
||||
|
||||
@app.put("/api/install/{install_id}")
|
||||
def update_install(install_id: int, data: InstallData):
|
||||
cursor.execute("""
|
||||
UPDATE installs
|
||||
SET rust_id = ?, computer_name = ?, install_time = ?, folder_id = ?
|
||||
WHERE id = ?
|
||||
""", (data.rust_id, data.computer_name, data.install_time or datetime.datetime.now().isoformat(),
|
||||
data.folder_id, install_id))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=404, detail="Запись не найдена")
|
||||
return {"status": "success"}
|
||||
|
||||
@app.delete("/api/install/{install_id}")
|
||||
def delete_install(install_id: int):
|
||||
cursor.execute("DELETE FROM installs WHERE id = ?", (install_id,))
|
||||
conn.commit()
|
||||
if cursor.rowcount == 0:
|
||||
raise HTTPException(status_code=404, detail="Запись не найдена")
|
||||
return {"status": "success"}
|
||||
|
||||
# CORS
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
|
@ -1,23 +1,9 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
rustdesk-organizer:
|
||||
build: .
|
||||
ports:
|
||||
- "8001:8001" # Порт для FastAPI
|
||||
- "8001:8001"
|
||||
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
|
||||
- ./db:/db
|
||||
restart: unless-stopped
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
<!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>
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
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}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fastapi
|
||||
uvicorn
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Органайзер RustDesk</title>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/jstree.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/themes/default/style.min.css">
|
||||
<style>
|
||||
body { display: flex; font-family: Arial, sans-serif; }
|
||||
#tree-container { width: 30%; padding: 10px; border-right: 1px solid #ccc; }
|
||||
#installs-container { width: 70%; padding: 10px; }
|
||||
.install-item { padding: 5px; margin: 2px; border: 1px solid #ddd; cursor: move; }
|
||||
.form-container { margin-bottom: 20px; }
|
||||
.jstree-node { position: relative; }
|
||||
.folder-actions { display: inline; margin-left: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="tree-container">
|
||||
<h2>Папки</h2>
|
||||
<div id="folder-tree"></div>
|
||||
<button onclick="addFolder()">Добавить папку</button>
|
||||
</div>
|
||||
<div id="installs-container">
|
||||
<h1>Органайзер RustDesk</h1>
|
||||
<div class="form-container">
|
||||
<h2>Добавить запись</h2>
|
||||
<input type="text" id="rustId" placeholder="Rust ID" required>
|
||||
<input type="text" id="computerName" placeholder="Имя компьютера" required>
|
||||
<input type="text" id="installTime" placeholder="Время (опционально)">
|
||||
<button onclick="addInstall()">Добавить</button>
|
||||
</div>
|
||||
<div id="installs-list"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_URL = "/api";
|
||||
let selectedFolderId = null;
|
||||
|
||||
$(document).ready(function () {
|
||||
// Инициализация дерева папок
|
||||
$('#folder-tree').jstree({
|
||||
'core': {
|
||||
'data': function (node, cb) {
|
||||
$.getJSON(`${API_URL}/folders`, function (data) {
|
||||
const treeData = data.map(folder => ({
|
||||
id: folder.id,
|
||||
text: `${folder.name} <span class="folder-actions">` +
|
||||
`<button onclick="editFolder(${folder.id}, '${folder.name}')">✏️</button>` +
|
||||
`<button onclick="deleteFolder(${folder.id})">🗑️</button></span>`,
|
||||
parent: folder.parent_id ? folder.parent_id : '#'
|
||||
}));
|
||||
cb(treeData);
|
||||
});
|
||||
},
|
||||
'check_callback': true
|
||||
},
|
||||
'plugins': ['dnd', 'html_data']
|
||||
}).on('select_node.jstree', function (e, data) {
|
||||
selectedFolderId = data.node.id;
|
||||
loadInstalls(selectedFolderId);
|
||||
});
|
||||
|
||||
// Drag-and-drop для записей
|
||||
$('#installs-list').on('dragstart', '.install-item', function (e) {
|
||||
e.originalEvent.dataTransfer.setData('text/plain', $(this).data('id'));
|
||||
});
|
||||
|
||||
$('#folder-tree').on('dragover', function (e) {
|
||||
e.preventDefault(); // Разрешаем drop
|
||||
}).on('drop', function (e) {
|
||||
e.preventDefault();
|
||||
const installId = e.originalEvent.dataTransfer.getData('text');
|
||||
const folderId = $(e.target).closest('.jstree-node').attr('id');
|
||||
if (installId && folderId) {
|
||||
updateInstallFolder(installId, folderId);
|
||||
}
|
||||
});
|
||||
|
||||
// Загрузка записей без выбранной папки
|
||||
loadInstalls(null);
|
||||
});
|
||||
|
||||
function loadInstalls(folderId) {
|
||||
$.getJSON(`${API_URL}/installs`, function (data) {
|
||||
const filtered = folderId ? data.filter(i => i.folder_id == folderId) : data;
|
||||
$('#installs-list').html(filtered.map(item => `
|
||||
<div class="install-item" data-id="${item.id}" draggable="true">
|
||||
<a href="rustdesk://${item.rust_id}" onclick="openRustDesk('${item.rust_id}'); return false;">${item.rust_id}</a>
|
||||
- ${item.computer_name} (${item.install_time})
|
||||
<button onclick="editInstall(${item.id}, '${item.rust_id}', '${item.computer_name}', '${item.install_time}')">Редактировать</button>
|
||||
<button onclick="deleteInstall(${item.id})">Удалить</button>
|
||||
</div>
|
||||
`).join(''));
|
||||
});
|
||||
}
|
||||
|
||||
function addFolder() {
|
||||
const name = prompt("Введите имя папки:");
|
||||
if (name) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/folders`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ name, parent_id: selectedFolderId }),
|
||||
success: function () {
|
||||
$('#folder-tree').jstree(true).refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function editFolder(folderId, currentName) {
|
||||
const newName = prompt("Введите новое имя папки:", currentName);
|
||||
if (newName) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/folders/${folderId}`,
|
||||
type: 'PUT',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ name: newName }),
|
||||
success: function () {
|
||||
$('#folder-tree').jstree(true).refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteFolder(folderId) {
|
||||
if (confirm("Удалить папку? Все записи будут перемещены в корень.")) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/folders/${folderId}`,
|
||||
type: 'DELETE',
|
||||
success: function () {
|
||||
// Перемещаем записи в корень (folder_id = null)
|
||||
$.getJSON(`${API_URL}/installs`, function (data) {
|
||||
const folderInstalls = data.filter(i => i.folder_id == folderId);
|
||||
folderInstalls.forEach(item => {
|
||||
updateInstallFolder(item.id, null);
|
||||
});
|
||||
});
|
||||
$('#folder-tree').jstree(true).refresh();
|
||||
loadInstalls(selectedFolderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addInstall() {
|
||||
const rustId = $('#rustId').val();
|
||||
const computerName = $('#computerName').val();
|
||||
const installTime = $('#installTime').val() || new Date().toISOString();
|
||||
$.ajax({
|
||||
url: `${API_URL}/install`,
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ rust_id: rustId, computer_name: computerName, install_time: installTime, folder_id: selectedFolderId }),
|
||||
success: function () {
|
||||
loadInstalls(selectedFolderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function editInstall(id, rustId, computerName, installTime) {
|
||||
const newRustId = prompt("Rust ID:", rustId);
|
||||
const newComputerName = prompt("Имя компьютера:", computerName);
|
||||
const newInstallTime = prompt("Время установки:", installTime);
|
||||
if (newRustId && newComputerName) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/install/${id}`,
|
||||
type: 'PUT',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ rust_id: newRustId, computer_name: newComputerName, install_time: newInstallTime, folder_id: selectedFolderId }),
|
||||
success: function () {
|
||||
loadInstalls(selectedFolderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteInstall(id) {
|
||||
if (confirm("Удалить запись?")) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/install/${id}`,
|
||||
type: 'DELETE',
|
||||
success: function () {
|
||||
loadInstalls(selectedFolderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateInstallFolder(installId, folderId) {
|
||||
$.ajax({
|
||||
url: `${API_URL}/install/${installId}`,
|
||||
type: 'PUT',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ folder_id: folderId === 'undefined' ? null : folderId }),
|
||||
success: function () {
|
||||
loadInstalls(selectedFolderId); // Обновляем список после переноса
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("Ошибка переноса:", status, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openRustDesk(rustId) {
|
||||
if (confirm("Подключиться к " + rustId + "?")) {
|
||||
window.location.href = `rustdesk://${rustId}`;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue