new save system
This commit is contained in:
109
public/app.js
109
public/app.js
@@ -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('Сначала выберите таблицу');
|
||||
|
||||
Reference in New Issue
Block a user