add table edit feature with auto saving on focus loose
This commit is contained in:
106
public/app.js
106
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('Сначала выберите таблицу');
|
||||
|
||||
Reference in New Issue
Block a user