Satur@it-depot.ru 2025-03-05 15:42:59 +03:00
parent 1e1250e55d
commit 039bb6f2d3
1 changed files with 42 additions and 34 deletions

View File

@ -17,7 +17,7 @@
.jstree-node { position: relative; } .jstree-node { position: relative; }
.folder-actions { display: none; position: absolute; right: 5px; top: 50%; transform: translateY(-50%); margin-left: 0; } /* Сдвигаем кнопки вправо и центрируем по вертикали */ .folder-actions { display: none; position: absolute; right: 5px; top: 50%; transform: translateY(-50%); margin-left: 0; } /* Сдвигаем кнопки вправо и центрируем по вертикали */
#search-container { position: absolute; top: 10px; right: 10px; text-align: right; } #search-container { position: absolute; top: 10px; right: 10px; text-align: right; }
#search-input { width: 200px; } #search-input { width: 200px; margin-bottom: 5px; }
#installs-list { margin-top: 20px; } #installs-list { margin-top: 20px; }
.header { display: flex; justify-content: space-between; font-weight: bold; padding: 5px; background: #f0f0f0; cursor: pointer; } .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 { flex: 1; text-align: center; }
@ -30,13 +30,13 @@
.install-item:hover .edit-button { display: inline-block; } .install-item:hover .edit-button { display: inline-block; }
.action-buttons { display: none; } .action-buttons { display: none; }
.install-item:hover .action-buttons { display: inline; } .install-item:hover .action-buttons { display: inline; }
#import-form { margin-top: 10px; } #import-form { margin-top: 5px; }
#import-file { display: none; } #import-file { display: none; }
#import-label { cursor: pointer; background: #007bff; color: white; padding: 5px 10px; border-radius: 5px; } #import-label { cursor: pointer; background: #007bff; color: white; padding: 5px 10px; border-radius: 3px; margin-left: 5px; }
#import-label:hover { background: #0056b3; } #import-label:hover { background: #0056b3; }
.folder-select { margin: 5px 0; } .folder-select { margin-bottom: 5px; width: 150px; }
.time-hint { font-size: 12px; color: #666; margin-top: 5px; } .time-hint { font-size: 12px; color: #666; margin-top: 5px; }
#notes-panel { width: 30%; padding: 10px; border-left: 1px solid #ccc; background: #f9f9f9; min-height: 200px; margin-top: 70px; } /* Смещаем ниже и начинаем с уровня заголовка */ #notes-panel { width: 30%; padding: 10px; border-left: 1px solid #ccc; background: #f9f9f9; min-height: 200px; margin-top: 40px; } /* Смещаем ниже, чтобы начиналось на уровне заголовка таблицы */
#notes-content { margin-top: 10px; } #notes-content { margin-top: 10px; }
#note-modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border: 1px solid #ccc; box-shadow: 0 0 10px rgba(0,0,0,0.3); z-index: 1000; width: 500px; } #note-modal { display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 20px; border: 1px solid #ccc; box-shadow: 0 0 10px rgba(0,0,0,0.3); z-index: 1000; width: 500px; }
#note-modal .markdown-buttons { margin-bottom: 10px; } #note-modal .markdown-buttons { margin-bottom: 10px; }
@ -60,14 +60,7 @@
Органайзер АйТи-Депо Органайзер АйТи-Депо
</h1> </h1>
<div id="search-container"> <div id="search-container">
<input type="text" id="search-input" placeholder="Поиск по ID или имени" onkeyup="filterInstalls()"> <input type="text" id="search-input" placeholder="Поиск по ID или имени">
<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 style="margin-top: 10px;">
<select id="folder-select" class="folder-select"> <select id="folder-select" class="folder-select">
<option value="">Все папки</option> <option value="">Все папки</option>
</select> </select>
@ -77,7 +70,6 @@
<label for="import-file" id="import-label">Импорт CSV</label> <label for="import-file" id="import-label">Импорт CSV</label>
</form> </form>
</div> </div>
</div>
<div class="form-container"> <div class="form-container">
<h2>Добавить запись</h2> <h2>Добавить запись</h2>
<input type="text" id="rustId" placeholder="ID подключения" required> <input type="text" id="rustId" placeholder="ID подключения" required>
@ -96,8 +88,8 @@
<div class="time-hint">Пример: 2025-03-05 14:30:00</div> <div class="time-hint">Пример: 2025-03-05 14:30:00</div>
</div> </div>
<div class="header"> <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('computer_name')">Имя компьютера<span class="sort-arrow"></span></div>
<div onclick="sortInstalls('rust_id')">ID подключения<span class="sort-arrow"></span></div>
<div onclick="sortInstalls('install_time')">Время установки<span class="sort-arrow"></span></div> <div onclick="sortInstalls('install_time')">Время установки<span class="sort-arrow"></span></div>
<div>Действия</div> <div>Действия</div>
</div> </div>
@ -232,15 +224,15 @@
function displayInstalls(installs) { function displayInstalls(installs) {
$('#installs-list').html(installs.map(item => ` $('#installs-list').html(installs.map(item => `
<div class="install-item" data-id="${item.id}" draggable="true" style="display: flex; justify-content: space-between; position: relative;"> <div class="install-item" data-id="${item.id}" draggable="true" style="display: flex; justify-content: space-between; position: relative;">
<div style="flex: 1; text-align: center; position: relative;">
${item.computer_name}
<button class="edit-button" onclick="editField(${item.id}, 'computer_name', '${item.computer_name}')">✏️</button>
</div>
<div style="flex: 1; text-align: center; position: relative;"> <div style="flex: 1; text-align: center; position: relative;">
<span class="protocol-icon">${protocolIcons[item.protocol]}</span> <span class="protocol-icon">${protocolIcons[item.protocol]}</span>
<a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link" onclick="selectInstall(${item.id}, '${item.rust_id}', '${item.protocol}'); return false;">${item.rust_id}</a> <a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link" onclick="selectInstall(${item.id}, '${item.rust_id}', '${item.protocol}'); return false;">${item.rust_id}</a>
<button class="edit-button" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')">✏️</button> <button class="edit-button" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')">✏️</button>
</div> </div>
<div style="flex: 1; text-align: center; position: relative;">
${item.computer_name}
<button class="edit-button" onclick="editField(${item.id}, 'computer_name', '${item.computer_name}')">✏️</button>
</div>
<div style="flex: 1; text-align: center; position: relative;"> <div style="flex: 1; text-align: center; position: relative;">
${item.install_time} ${item.install_time}
<button class="edit-button" onclick="editField(${item.id}, 'install_time', '${item.install_time}')">✏️</button> <button class="edit-button" onclick="editField(${item.id}, 'install_time', '${item.install_time}')">✏️</button>
@ -269,10 +261,8 @@
function filterInstalls() { function filterInstalls() {
const query = $('#search-input').val().toLowerCase(); const query = $('#search-input').val().toLowerCase();
const scope = $('input[name="search-scope"]:checked').val(); const scope = $('#folder-select').val() || ''; // Используем значение из выпадающего списка
let filtered = scope === 'current' let filtered = scope ? allInstalls.filter(i => i.folder_id == scope) : allInstalls;
? (selectedFolderId ? allInstalls.filter(i => i.folder_id == selectedFolderId) : allInstalls.filter(i => i.folder_id === null))
: allInstalls;
filtered = filtered.filter(i => filtered = filtered.filter(i =>
i.rust_id.toLowerCase().includes(query) || i.rust_id.toLowerCase().includes(query) ||
i.computer_name.toLowerCase().includes(query) i.computer_name.toLowerCase().includes(query)
@ -307,7 +297,7 @@
function updateSortArrows() { function updateSortArrows() {
$('.sort-arrow').text(''); $('.sort-arrow').text('');
if (sortField) { if (sortField) {
$(`.header div:contains("${sortField === 'rust_id' ? 'ID подключения' : sortField === 'computer_name' ? 'Имя компьютера' : 'Время установки'}") .sort-arrow`) $(`.header div:contains("${sortField === 'computer_name' ? 'Имя компьютера' : sortField === 'rust_id' ? 'ID подключения' : 'Время установки'}") .sort-arrow`)
.text(sortDirection === 'asc' ? '↑' : '↓'); .text(sortDirection === 'asc' ? '↑' : '↓');
} }
} }
@ -322,6 +312,7 @@
data: JSON.stringify({ name, parent_id: selectedFolderId }), data: JSON.stringify({ name, parent_id: selectedFolderId }),
success: function () { success: function () {
$('#folder-tree').jstree(true).refresh(); $('#folder-tree').jstree(true).refresh();
updateFolderSelect(); // Обновляем выпадающий список папок
} }
}); });
} }
@ -337,6 +328,7 @@
data: JSON.stringify({ name: newName }), data: JSON.stringify({ name: newName }),
success: function () { success: function () {
$('#folder-tree').jstree(true).refresh(); $('#folder-tree').jstree(true).refresh();
updateFolderSelect(); // Обновляем выпадающий список папок
} }
}); });
} }
@ -356,6 +348,7 @@
}); });
$('#folder-tree').jstree(true).refresh(); $('#folder-tree').jstree(true).refresh();
loadInstalls(selectedFolderId); loadInstalls(selectedFolderId);
updateFolderSelect(); // Обновляем выпадающий список папок
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {
if (xhr.status === 403) { if (xhr.status === 403) {
@ -401,13 +394,13 @@
function editField(installId, field, currentValue) { function editField(installId, field, currentValue) {
let newValue; let newValue;
if (field === 'install_time') { if (field === 'install_time') {
newValue = prompt(`Новое ${field === 'rust_id' ? 'ID подключения' : field === 'computer_name' ? 'Имя компьютера' : 'Время установки'} (опционально, формат для времени: ГГГГ-ММ-ДД ЧЧ:ММ:СС):`, currentValue || ''); newValue = prompt(`Новое ${field === 'computer_name' ? 'Имя компьютера' : field === 'rust_id' ? 'ID подключения' : 'Время установки'} (опционально, формат для времени: ГГГГ-ММ-ДД ЧЧ:ММ:СС):`, currentValue || '');
if (newValue && field === 'install_time' && !/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/.test(newValue)) { if (newValue && field === 'install_time' && !/^\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/.test(newValue)) {
alert("Неверный формат времени. Используйте ГГГГ-ММ-ДД ЧЧ:ММ:СС (например, 2025-03-05 14:30:00)"); alert("Неверный формат времени. Используйте ГГГГ-ММ-ДД ЧЧ:ММ:СС (например, 2025-03-05 14:30:00)");
return; return;
} }
} else { } else {
newValue = prompt(`Новое ${field === 'rust_id' ? 'ID подключения' : field === 'computer_name' ? 'Имя компьютера' : 'Время установки'}:`, currentValue || ''); newValue = prompt(`Новое ${field === 'computer_name' ? 'Имя компьютера' : field === 'rust_id' ? 'ID подключения' : 'Время установки'}:`, currentValue || '');
} }
if (newValue !== null && newValue !== currentValue) { // Проверяем, что значение изменилось if (newValue !== null && newValue !== currentValue) { // Проверяем, что значение изменилось
@ -555,6 +548,16 @@
} }
} }
function updateFolderSelect() {
$.getJSON(`${API_URL}/folders`, function (folders) {
const $folderSelect = $('#folder-select');
$folderSelect.empty().append('<option value="">Все папки</option>');
folders.forEach(folder => {
$folderSelect.append(`<option value="${folder.id}">${folder.name}</option>`);
});
});
}
// Обновляем заметки при клике на подключение // Обновляем заметки при клике на подключение
$('#installs-list').on('click', '.install-item', function () { $('#installs-list').on('click', '.install-item', function () {
selectedInstallId = $(this).data('id'); selectedInstallId = $(this).data('id');
@ -602,6 +605,11 @@
textarea[0].selectionEnd = start + newText.length - (selected ? 0 : '[текст]'.length); // Учитываем длину [текст](URL) textarea[0].selectionEnd = start + newText.length - (selected ? 0 : '[текст]'.length); // Учитываем длину [текст](URL)
} }
} }
// Обновляем фильтр при изменении выбора папки
$('#folder-select').on('change', function () {
filterInstalls();
});
</script> </script>
</body> </body>
</html> </html>