From 698a99afc5973682cbda6d0145cffdda9ff91315 Mon Sep 17 00:00:00 2001 From: Mikhail Chusavitin Date: Wed, 21 Jan 2026 19:05:10 +0300 Subject: [PATCH] Pretier rows --- public/app.js | 191 +++++++++++++++++++++++++++++++++++++++++++++- public/index.html | 95 ++++++++++++++++++++--- 2 files changed, 275 insertions(+), 11 deletions(-) diff --git a/public/app.js b/public/app.js index 3564a85..b1ea692 100644 --- a/public/app.js +++ b/public/app.js @@ -185,6 +185,169 @@ async function loadTree() { treeEl.style.color = 'red'; } } + +// ✅ Получаем ключ для localStorage (уникальный для каждой таблицы) +function getColumnVisibilityKey() { + if (!currentSchema || !currentTable) return null; + return `columnVisibility_${currentSchema}_${currentTable}`; +} + +// ✅ Сохраняем видимость столбцов +function saveColumnVisibility(visibilityMap) { + const key = getColumnVisibilityKey(); + if (!key) return; + + sessionStorage.setItem(key, JSON.stringify(visibilityMap)); + console.log('💾 Видимость столбцов сохранена:', visibilityMap); +} + +// ✅ Загружаем видимость столбцов +function loadColumnVisibility() { + const key = getColumnVisibilityKey(); + if (!key) return null; + + const saved = sessionStorage.getItem(key); + if (saved) { + try { + return JSON.parse(saved); + } catch (e) { + console.error('Ошибка загрузки видимости столбцов:', e); + return null; + } + } + return null; +} + +// ✅ Показываем меню выбора столбцов +function showColumnManager() { + if (!table || !currentMeta) { + alert('Сначала выберите таблицу'); + return; + } + + // Создаём overlay + const overlay = document.createElement('div'); + overlay.className = 'columns-menu-overlay'; + + // Создаём меню + const menu = document.createElement('div'); + menu.className = 'columns-menu'; + + let html = '

Выбор столбцов

'; + html += '
'; + html += '💡 Выберите столбцы для отображения. Настройки сохраняются до конца сессии.'; + html += '
'; + + // Получаем все колонки + const columns = table.getColumns(); + + // Кнопки управления + html += '
'; + html += ''; + html += ''; + html += '
'; + + html += '
'; + + columns.forEach(col => { + const field = col.getField(); + + // Пропускаем колонку с чекбоксами + if (field === '__tabulator_row_selection') return; + + const definition = col.getDefinition(); + const visible = col.isVisible(); + const title = definition.title || field; + + // Ищем комментарий в мета-данных + const metaCol = currentMeta.columns.find(c => c.COLUMN_NAME === field); + const comment = metaCol?.COLUMN_COMMENT || ''; + + html += ` +
+ + +
+ `; + }); + + html += '
'; + + html += ` +
+ + +
+ `; + + menu.innerHTML = html; + + document.body.appendChild(overlay); + document.body.appendChild(menu); + + // Обработчики + document.getElementById('selectAllColumns').addEventListener('click', () => { + document.querySelectorAll('.column-checkbox input[type="checkbox"]').forEach(cb => { + cb.checked = true; + }); + }); + + document.getElementById('deselectAllColumns').addEventListener('click', () => { + document.querySelectorAll('.column-checkbox input[type="checkbox"]').forEach(cb => { + cb.checked = false; + }); + }); + + document.getElementById('columnMenuCancel').addEventListener('click', () => { + document.body.removeChild(overlay); + document.body.removeChild(menu); + }); + + document.getElementById('columnMenuApply').addEventListener('click', () => { + const visibilityMap = {}; + const checkboxes = document.querySelectorAll('.column-checkbox input[type="checkbox"]'); + + checkboxes.forEach(cb => { + const field = cb.dataset.field; + const visible = cb.checked; + visibilityMap[field] = visible; + + // Применяем видимость + const column = table.getColumn(field); + if (column) { + if (visible) { + column.show(); + } else { + column.hide(); + } + } + }); + + // Сохраняем настройки + saveColumnVisibility(visibilityMap); + + document.body.removeChild(overlay); + document.body.removeChild(menu); + + console.log('✅ Видимость столбцов обновлена'); + }); + + // Закрытие по клику на overlay + overlay.addEventListener('click', () => { + document.body.removeChild(overlay); + document.body.removeChild(menu); + }); +} + + + // selectTable async function selectTable(schema, tableName) { @@ -380,8 +543,11 @@ async function selectTable(schema, tableName) { selectableRowsCheck: function(row) { return true; }, columns: columns, - layout: "fitColumns", - resizableColumnFit: true, + layout: "fitData", // ✅ Изменено с fitColumns на fitData + resizableColumns: true, // ✅ Разрешаем изменять ширину столбцов + resizableColumnFit: false, // ✅ Выключаем авто-подгонку при ресайзе + + columnMinWidth: 100, // ✅ Минимальная ширина столбца pagination: true, paginationMode: "remote", @@ -431,6 +597,23 @@ async function selectTable(schema, tableName) { console.log('✅ Tabulator создан, подключаем события...'); + // ✅ Применяем сохранённую видимость столбцов + const savedVisibility = loadColumnVisibility(); + if (savedVisibility) { + console.log('📂 Применяем сохранённую видимость столбцов:', savedVisibility); + + Object.keys(savedVisibility).forEach(field => { + const column = table.getColumn(field); + if (column) { + if (savedVisibility[field]) { + column.show(); + } else { + column.hide(); + } + } + }); + } + // Функция сохранения async function saveRow(rowPos, rowData, rowElement) { console.log('💾 === СОХРАНЕНИЕ ==='); @@ -1303,3 +1486,7 @@ document.getElementById('btnExportCSV').addEventListener('click', async () => { alert('Ошибка экспорта: ' + err.message); } }); +// ✅ Управление столбцами +document.getElementById('btnManageColumns').addEventListener('click', () => { + showColumnManager(); +}); diff --git a/public/index.html b/public/index.html index a89eb32..8a3c4b1 100644 --- a/public/index.html +++ b/public/index.html @@ -24,13 +24,97 @@ overflow-y: auto; flex-shrink: 0; } - #main { + + #main { flex: 1; display: flex; flex-direction: column; min-width: 0; overflow: hidden; } + + #table { + flex: 1; + position: relative; + overflow: auto; /* ✅ Разрешаем прокрутку */ + min-height: 0; + } + + /* ✅ Горизонтальная прокрутка для Tabulator */ + .tabulator { + border: none; + background-color: white; + overflow: auto !important; /* Включаем прокрутку */ + } + + .tabulator .tabulator-header { + background-color: #f5f5f5; + border-bottom: 2px solid #ddd; + } + + .tabulator .tabulator-tableholder { + overflow: auto !important; /* ✅ Горизонтальная прокрутка */ + } + + .tabulator .tabulator-table { + width: auto !important; /* ✅ Позволяем таблице быть шире контейнера */ + } + + /* ✅ Стили для меню столбцов */ + .columns-menu { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + padding: 20px; + border-radius: 8px; + box-shadow: 0 4px 20px rgba(0,0,0,0.3); + z-index: 10000; + max-width: 500px; + max-height: 80vh; + overflow-y: auto; + } + + .columns-menu-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0,0,0,0.5); + z-index: 9999; + } + + .column-checkbox { + display: flex; + align-items: center; + padding: 8px; + margin: 4px 0; + border-radius: 4px; + cursor: pointer; + } + + .column-checkbox:hover { + background: #f5f5f5; + } + + .column-checkbox input[type="checkbox"] { + margin-right: 10px; + cursor: pointer; + } + + .column-checkbox label { + cursor: pointer; + flex: 1; + user-select: none; + } + + /* ✅ Минимальная ширина столбцов */ + .tabulator-col { + min-width: 100px !important; + } + #toolbar { padding: 8px; border-bottom: 1px solid #ccc; @@ -40,14 +124,6 @@ gap: 4px; flex-wrap: wrap; } - #table { - flex: 1; - position: relative; - overflow: auto; - min-height: 0; - } - .schema { font-weight: bold; margin-top: 8px; cursor: pointer; } - .table { margin-left: 12px; cursor: pointer; } #loginPanel { padding: 8px; border-bottom: 1px solid #ccc; @@ -206,6 +282,7 @@ +