diff --git a/public/app.js b/public/app.js index 0b007b6..ef5a198 100644 --- a/public/app.js +++ b/public/app.js @@ -185,7 +185,7 @@ async function selectTable(schema, tableName) { currentSchema = schema; currentTable = tableName; lastEditedRow = null; - selectedRowsDataGlobal.clear(); // Очищаем при смене таблицы + selectedRowsDataGlobal.clear(); updateSelectionCounter(); if (enterHandler) { @@ -221,6 +221,10 @@ async function selectTable(schema, tableName) { table = null; } + // ✅ Переменная для отслеживания несохраненных изменений + let pendingSave = null; + let saveTimeout = null; + table = new Tabulator("#table", { selectableRows: true, columns: columns, @@ -270,12 +274,10 @@ async function selectTable(schema, tableName) { }; }, - // Обновляем счетчик при изменении выделения rowSelectionChanged: function(data, rows) { updateSelectionCounter(); }, - // Восстанавливаем выделение для глобально выделенных строк dataLoaded: function(data) { if (selectedRowsDataGlobal.size > 0) { const rows = this.getRows(); @@ -291,36 +293,95 @@ async function selectTable(schema, tableName) { } }, + // ✅ При начале редактирования + cellEditing: function(cell) { + const row = cell.getRow(); + row.getElement().style.backgroundColor = '#fff9e6'; + }, + + // ✅ При изменении ячейки cellEdited: function(cell) { const row = cell.getRow(); - lastEditedRow = row.getData(); + const rowData = row.getData(); + + // Подсвечиваем измененную строку row.getElement().style.backgroundColor = '#fffae6'; + + // Сохраняем данные для отложенного сохранения + pendingSave = { + cell: cell, + row: rowData, + rowElement: row + }; + + // ✅ Автосохранение через 1.5 секунды после последнего изменения + clearTimeout(saveTimeout); + saveTimeout = setTimeout(async () => { + if (pendingSave) { + await saveRowData(pendingSave.row, pendingSave.rowElement); + pendingSave = null; + } + }, 1500); + }, + + // ✅ При отмене редактирования (потеря фокуса, Esc) + cellEditCancelled: function(cell) { + // Если были несохраненные изменения - сохраняем их + if (pendingSave && pendingSave.cell === cell) { + clearTimeout(saveTimeout); + saveRowData(pendingSave.row, pendingSave.rowElement).then(() => { + pendingSave = null; + }); + } }, headerFilterLiveFilterDelay: 800 }); + // ✅ Функция сохранения строки + async function saveRowData(rowData, rowElement) { + if (!currentSchema || !currentTable) return; + + try { + await api('/api/table/update', 'POST', { + schema: currentSchema, + table: currentTable, + row: rowData + }); + + // Убираем подсветку после успешного сохранения + if (rowElement && rowElement.getElement) { + rowElement.getElement().style.backgroundColor = '#e8f5e9'; // Зеленоватый фон + setTimeout(() => { + rowElement.getElement().style.backgroundColor = ''; + }, 1000); + } + + console.log('✓ Изменения сохранены:', rowData); + } catch (err) { + console.error('Ошибка сохранения:', err); + + // Красная подсветка при ошибке + if (rowElement && rowElement.getElement) { + rowElement.getElement().style.backgroundColor = '#ffebee'; + } + + alert('Ошибка сохранения: ' + err.message); + } + } + + // ✅ Обработчик Enter - сохраняет немедленно enterHandler = async function(e) { - if (e.key === 'Enter' && lastEditedRow && currentSchema && currentTable) { + if (e.key === 'Enter' && pendingSave && currentSchema && currentTable) { e.preventDefault(); - try { - const res = await api('/api/table/update', 'POST', { - schema: currentSchema, - table: currentTable, - row: lastEditedRow - }); - - lastEditedRow = null; - - table.getRows().forEach(r => { - r.getElement().style.backgroundColor = ''; - }); - - await table.replaceData(); - } catch (err) { - console.error('Ошибка сохранения:', err); - alert('Ошибка: ' + err.message); + clearTimeout(saveTimeout); + await saveRowData(pendingSave.row, pendingSave.rowElement); + pendingSave = null; + + // Снимаем фокус с ячейки + if (document.activeElement) { + document.activeElement.blur(); } } }; @@ -328,6 +389,7 @@ async function selectTable(schema, tableName) { document.addEventListener('keydown', enterHandler); } + document.getElementById('btnSelectAll').addEventListener('click', async () => { if (!currentSchema || !currentTable || !table) { alert('Сначала выберите таблицу');