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 @@
+
Выбрано: 0