addressbook_web/templates/index.html

316 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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; position: relative; }
.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; }
#search-container { position: absolute; top: 10px; right: 10px; text-align: right; }
#search-input { width: 200px; }
#installs-list { margin-top: 20px; }
.header { display: flex; justify-content: space-between; font-weight: bold; padding: 5px; background: #f0f0f0; cursor: pointer; }
.header div { flex: 1; text-align: center; }
.header div:hover { background: #e0e0e0; }
.sort-arrow { font-size: 12px; margin-left: 5px; }
.protocol-icon { margin-right: 5px; }
</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 id="search-container">
<input type="text" id="search-input" placeholder="Поиск по ID или имени" onkeyup="filterInstalls()">
<div>
<input type="radio" id="search-current" name="search-scope" value="current" checked>
<label for="search-current">Текущая папка</label>
<input type="radio" id="search-all" name="search-scope" value="all">
<label for="search-all">Все папки</label>
</div>
</div>
<div class="form-container">
<h2>Добавить запись</h2>
<input type="text" id="rustId" placeholder="ID подключения" required>
<input type="text" id="computerName" placeholder="Имя компьютера" required>
<input type="text" id="installTime" placeholder="Время (опционально)">
<select id="protocol">
<option value="rustdesk" selected>RustDesk</option>
<option value="anydesk">AnyDesk</option>
<option value="ammyy">Ammyy Admin</option>
<option value="teamviewer">TeamViewer</option>
<option value="vnc">VNC</option>
<option value="rdp">RDP</option>
</select>
<button onclick="addInstall()">Добавить</button>
</div>
<div class="header">
<div onclick="sortInstalls('rust_id')">ID подключения<span class="sort-arrow"></span></div>
<div onclick="sortInstalls('computer_name')">Имя компьютера<span class="sort-arrow"></span></div>
<div onclick="sortInstalls('install_time')">Время установки<span class="sort-arrow"></span></div>
<div>Действия</div>
</div>
<div id="installs-list"></div>
</div>
<script>
const API_URL = "/api";
let selectedFolderId = null;
let allInstalls = [];
let sortField = null;
let sortDirection = 'asc';
const protocolIcons = {
'rustdesk': '🖥️', // Эмодзи для RustDesk
'anydesk': '🔴', // Эмодзи для AnyDesk
'ammyy': '🟢', // Эмодзи для Ammyy Admin
'teamviewer': '🔵', // Эмодзи для TeamViewer
'vnc': '🟡', // Эмодзи для VNC
'rdp': '🟣' // Эмодзи для RDP
};
$(document).ready(function () {
$('#folder-tree').jstree({
'core': {
'data': function (node, cb) {
$.getJSON(`${API_URL}/folders`, function (data) {
const treeData = [
{ id: "root", text: "Корень", parent: "#" }
].concat(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 : "root"
})));
cb(treeData);
});
},
'check_callback': true
},
'plugins': ['dnd', 'html_data']
}).on('select_node.jstree', function (e, data) {
selectedFolderId = data.node.id === "root" ? null : data.node.id;
loadInstalls(selectedFolderId);
});
$('#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();
}).on('drop', function (e) {
e.preventDefault();
const installId = e.originalEvent.dataTransfer.getData('text');
let targetFolderId = $(e.target).closest('.jstree-node').attr('id');
if (installId && targetFolderId) {
targetFolderId = targetFolderId === "root" ? null : targetFolderId;
moveInstallToFolder(installId, targetFolderId);
}
});
loadInstalls(null);
$('#folder-tree').jstree('select_node', 'root');
});
function loadInstalls(folderId) {
$.getJSON(`${API_URL}/installs`, function (data) {
allInstalls = data;
let filtered = folderId ? data.filter(i => i.folder_id == folderId) : data.filter(i => i.folder_id === null);
displayInstalls(filtered);
});
selectedFolderId = folderId;
}
function displayInstalls(installs) {
$('#installs-list').html(installs.map(item => `
<div class="install-item" data-id="${item.id}" draggable="true" style="display: flex; justify-content: space-between;">
<div style="flex: 1; text-align: center;"><span class="protocol-icon">${protocolIcons[item.protocol]}</span>${item.rust_id}</div>
<div style="flex: 1; text-align: center;">${item.computer_name}</div>
<div style="flex: 1; text-align: center;">${item.install_time}</div>
<div style="flex: 1; text-align: center;">
<a href="${item.protocol}://${item.rust_id}" onclick="openRemote('${item.rust_id}', '${item.protocol}'); return false;">Подключиться</a>
<button onclick="editInstall(${item.id}, '${item.rust_id}', '${item.computer_name}', '${item.install_time}', '${item.protocol}')">Редактировать</button>
<button onclick="deleteInstall(${item.id})">Удалить</button>
</div>
</div>
`).join(''));
updateSortArrows();
}
function filterInstalls() {
const query = $('#search-input').val().toLowerCase();
const scope = $('input[name="search-scope"]:checked').val();
let filtered = scope === 'current'
? (selectedFolderId ? allInstalls.filter(i => i.folder_id == selectedFolderId) : allInstalls.filter(i => i.folder_id === null))
: allInstalls;
filtered = filtered.filter(i =>
i.rust_id.toLowerCase().includes(query) ||
i.computer_name.toLowerCase().includes(query)
);
sortInstalls(null, filtered);
}
function sortInstalls(field, filteredInstalls = null) {
let installs = filteredInstalls || (selectedFolderId
? allInstalls.filter(i => i.folder_id == selectedFolderId)
: allInstalls.filter(i => i.folder_id === null));
if (field) {
if (sortField === field) {
sortDirection = sortDirection === 'asc' ? 'desc' : 'asc';
} else {
sortField = field;
sortDirection = 'asc';
}
installs.sort((a, b) => {
let valA = a[field], valB = b[field];
if (field === 'install_time') {
valA = new Date(valA);
valB = new Date(valB);
}
return sortDirection === 'asc' ? (valA > valB ? 1 : -1) : (valA < valB ? 1 : -1);
});
}
displayInstalls(installs);
}
function updateSortArrows() {
$('.sort-arrow').text('');
if (sortField) {
$(`.header div:contains("${sortField === 'rust_id' ? 'ID подключения' : sortField === 'computer_name' ? 'Имя компьютера' : 'Время установки'}") .sort-arrow`)
.text(sortDirection === 'asc' ? '↑' : '↓');
}
}
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 () {
$.getJSON(`${API_URL}/installs`, function (data) {
const folderInstalls = data.filter(i => i.folder_id == folderId);
folderInstalls.forEach(item => {
moveInstallToFolder(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();
const protocol = $('#protocol').val();
$.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, protocol: protocol }),
success: function () {
loadInstalls(selectedFolderId);
}
});
}
function editInstall(id, rustId, computerName, installTime, protocol) {
const newRustId = prompt("ID подключения:", rustId);
const newComputerName = prompt("Имя компьютера:", computerName);
const newInstallTime = prompt("Время установки:", installTime);
const newProtocol = prompt("Протокол (rustdesk, anydesk, ammyy, teamviewer, vnc, rdp):", protocol);
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, protocol: newProtocol }),
success: function () {
loadInstalls(selectedFolderId);
}
});
}
}
function deleteInstall(id) {
if (confirm("Удалить запись?")) {
$.ajax({
url: `${API_URL}/install/${id}`,
type: 'DELETE',
success: function () {
loadInstalls(selectedFolderId);
}
});
}
}
function moveInstallToFolder(installId, folderId) {
$.ajax({
url: `${API_URL}/install/${installId}`,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify({ folder_id: folderId }),
success: function () {
loadInstalls(selectedFolderId);
},
error: function (xhr, status, error) {
console.error("Ошибка переноса:", status, error);
}
});
}
function openRemote(id, protocol) {
if (confirm(`Подключиться к ${id} через ${protocol}?`)) {
window.location.href = `${protocol}://${id}`;
}
}
</script>
</body>
</html>