new save system

This commit is contained in:
Mikhail Chusavitin
2026-01-21 17:47:18 +03:00
parent 227d2c3442
commit 5b205742dc

View File

@@ -221,9 +221,8 @@ async function selectTable(schema, tableName) {
table = null;
}
// ✅ Переменная для отслеживания несохраненных изменений
let pendingSave = null;
let saveTimeout = null;
// ✅ Map для отслеживания несохраненных строк (доступен глобально)
const dirtyRows = new Map(); // key = row position, value = {data, element, timeout}
table = new Tabulator("#table", {
selectableRows: true,
@@ -293,73 +292,67 @@ async function selectTable(schema, tableName) {
}
},
// ✅ При начале редактирования
cellEditing: function(cell) {
const row = cell.getRow();
row.getElement().style.backgroundColor = '#fff9e6';
},
// ✅ При изменении ячейки
cellEdited: function(cell) {
const row = cell.getRow();
const rowData = row.getData();
const rowPos = row.getPosition();
// Подсвечиваем измененную строку
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;
});
// Отменяем предыдущий таймер для этой строки
if (dirtyRows.has(rowPos)) {
clearTimeout(dirtyRows.get(rowPos).timeout);
}
// ✅ Устанавливаем новый таймер на автосохранение (1 сек)
const timeout = setTimeout(async () => {
await saveRow(rowPos, rowData, row);
}, 1000);
// Сохраняем информацию о грязной строке
dirtyRows.set(rowPos, {
data: rowData,
element: row,
timeout: timeout
});
console.log('📝 Изменено:', cell.getField(), '→', cell.getValue());
},
headerFilterLiveFilterDelay: 800
});
// ✅ Функция сохранения строки
async function saveRowData(rowData, rowElement) {
async function saveRow(rowPos, rowData, rowElement) {
if (!currentSchema || !currentTable) return;
// Удаляем из списка несохраненных
dirtyRows.delete(rowPos);
try {
console.log('💾 Сохранение строки...', rowData);
await api('/api/table/update', 'POST', {
schema: currentSchema,
table: currentTable,
row: rowData
});
// Убираем подсветку после успешного сохранения
// ✅ Зеленый фон = успешное сохранение
if (rowElement && rowElement.getElement) {
rowElement.getElement().style.backgroundColor = '#e8f5e9'; // Зеленоватый фон
rowElement.getElement().style.backgroundColor = '#e8f5e9';
setTimeout(() => {
rowElement.getElement().style.backgroundColor = '';
}, 1000);
if (rowElement.getElement) {
rowElement.getElement().style.backgroundColor = '';
}
}, 1500);
}
console.log(' Изменения сохранены:', rowData);
console.log(' Изменения сохранены');
} catch (err) {
console.error('Ошибка сохранения:', err);
console.error('Ошибка сохранения:', err);
// Красная подсветка при ошибке
if (rowElement && rowElement.getElement) {
@@ -370,14 +363,22 @@ async function selectTable(schema, tableName) {
}
}
// ✅ Обработчик Enter - сохраняет немедленно
// ✅ Обработчик Enter - сохраняет ВСЕ несохраненные строки немедленно
enterHandler = async function(e) {
if (e.key === 'Enter' && pendingSave && currentSchema && currentTable) {
if (e.key === 'Enter' && dirtyRows.size > 0) {
e.preventDefault();
clearTimeout(saveTimeout);
await saveRowData(pendingSave.row, pendingSave.rowElement);
pendingSave = null;
console.log(`⏎ Enter: сохранение ${dirtyRows.size} измененных строк...`);
// Сохраняем все грязные строки
const savePromises = [];
dirtyRows.forEach((info, rowPos) => {
clearTimeout(info.timeout);
savePromises.push(saveRow(rowPos, info.data, info.element));
});
await Promise.all(savePromises);
// Снимаем фокус с ячейки
if (document.activeElement) {
@@ -387,9 +388,25 @@ async function selectTable(schema, tableName) {
};
document.addEventListener('keydown', enterHandler);
// ✅ Сохраняем несохраненные изменения при смене страницы/фильтрации
table.on("pageLoaded", async function() {
if (dirtyRows.size > 0) {
console.log('📄 Смена страницы: сохранение несохраненных изменений...');
const savePromises = [];
dirtyRows.forEach((info, rowPos) => {
clearTimeout(info.timeout);
savePromises.push(saveRow(rowPos, info.data, info.element));
});
await Promise.all(savePromises);
}
});
}
document.getElementById('btnSelectAll').addEventListener('click', async () => {
if (!currentSchema || !currentTable || !table) {
alert('Сначала выберите таблицу');