From 92a5c0040c7f35f1106a830e3598433eb9e3523f Mon Sep 17 00:00:00 2001 From: Michael Chus Date: Wed, 21 Jan 2026 04:20:53 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20"createProgressModal=20is=20not=20defined"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Добавлена функция createProgressModal в правильное место в app.js - Упрощен код удаления до одного варианта (без излишней сложности) - Функция определена до использования - Проверена работоспособность batch delete --- public/app.js | 200 +++++++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 101 deletions(-) diff --git a/public/app.js b/public/app.js index 6e53baf..f129963 100644 --- a/public/app.js +++ b/public/app.js @@ -31,6 +31,73 @@ function updateSelectionCounter() { } } +// Функция создания модального окна с прогресс-баром +function createProgressModal(message) { + const modal = document.createElement('div'); + modal.style.cssText = ` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0,0,0,0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + `; + + const dialog = document.createElement('div'); + dialog.style.cssText = ` + background: white; + padding: 30px; + border-radius: 8px; + min-width: 300px; + text-align: center; + `; + + dialog.innerHTML = ` +
${message}
+
+
+
+
+ + Пожалуйста, подождите... +
+ + `; + + modal.appendChild(dialog); + + // Анимация прогресс-бара (имитация) + const progressBar = dialog.querySelector('.progress-bar'); + let progress = 0; + const interval = setInterval(() => { + progress += Math.random() * 15; + if (progress > 90) progress = 90; // Останавливаемся на 90% + progressBar.style.width = progress + '%'; + }, 200); + + modal.stopProgress = () => { + clearInterval(interval); + progressBar.style.width = '100%'; + }; + + return modal; +} + +function escapeHtml(text) { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; +} + // Логин document.getElementById('loginBtn').addEventListener('click', async () => { const user = document.getElementById('loginUser').value.trim(); @@ -563,13 +630,7 @@ async function promptForForeignKeys(fkFields) { }); } -function escapeHtml(text) { - const div = document.createElement('div'); - div.textContent = text; - return div.innerHTML; -} - -// ✅ УДАЛИТЬ (с реальным прогрессом для больших объемов) +// ✅ УДАЛИТЬ (оптимизированное с batch delete) document.getElementById('btnDelete').addEventListener('click', async () => { if (!table || !currentSchema || !currentTable) return; @@ -586,106 +647,43 @@ document.getElementById('btnDelete').addEventListener('click', async () => { if (!confirm(confirmMsg)) return; - const rowsArray = Array.from(selectedRowsData.values()); - - // Для очень больших удалений - показываем прогресс - const BATCH_SIZE = 1000; // Удаляем по 1000 строк за раз - const batches = []; - for (let i = 0; i < rowsArray.length; i += BATCH_SIZE) { - batches.push(rowsArray.slice(i, i + BATCH_SIZE)); - } + // Создаем модальное окно с прогресс-баром + const modal = createProgressModal('Удаление записей...'); + document.body.appendChild(modal); - if (batches.length > 1) { - // Множество батчей - показываем реальный прогресс - const modal = createProgressModal(`Удаление ${count} записей...`); - document.body.appendChild(modal); + try { + // Преобразуем Map в массив + const rowsArray = Array.from(selectedRowsData.values()); - const progressBar = modal.querySelector('.progress-bar'); - const progressText = modal.querySelector('.spinner').parentElement; + // Используем batch delete для оптимизации + const result = await api('/api/table/delete-batch', 'POST', { + schema: currentSchema, + table: currentTable, + rows: rowsArray + }); - let totalDeleted = 0; - let totalErrors = 0; - let allErrorMessages = []; - - try { - for (let i = 0; i < batches.length; i++) { - const batch = batches[i]; - - progressText.innerHTML = ` Обработка ${i + 1} из ${batches.length} батчей...`; - - const result = await api('/api/table/delete-batch', 'POST', { - schema: currentSchema, - table: currentTable, - rows: batch - }); - - totalDeleted += result.deleted; - totalErrors += result.errors; - if (result.errorMessages) { - allErrorMessages.push(...result.errorMessages); - } - - // Обновляем прогресс - const progress = ((i + 1) / batches.length) * 100; - progressBar.style.width = progress + '%'; - } - - document.body.removeChild(modal); - - selectedRowsData.clear(); - updateSelectionCounter(); - await table.replaceData(); - - if (totalErrors > 0) { - const errorsToShow = allErrorMessages.slice(0, 10); - const moreErrors = allErrorMessages.length > 10 - ? `\n... и еще ${allErrorMessages.length - 10} ошибок` - : ''; - alert(`Удалено строк: ${totalDeleted}\nОшибок: ${totalErrors}\n\nПервые ошибки:\n${errorsToShow.join('\n')}${moreErrors}`); - } else { - alert(`✓ Успешно удалено строк: ${totalDeleted}`); - } - } catch (e) { - document.body.removeChild(modal); - console.error(e); - alert('Ошибка удаления: ' + e.message); - } - } else { - // Один батч - используем простое модальное окно - const modal = createProgressModal('Удаление записей...'); - document.body.appendChild(modal); - - try { - const result = await api('/api/table/delete-batch', 'POST', { - schema: currentSchema, - table: currentTable, - rows: rowsArray - }); - - document.body.removeChild(modal); - - selectedRowsData.clear(); - updateSelectionCounter(); - await table.replaceData(); - - if (result.errors > 0) { - const errorsToShow = result.errorMessages.slice(0, 10); - const moreErrors = result.errorMessages.length > 10 - ? `\n... и еще ${result.errorMessages.length - 10} ошибок` - : ''; - alert(`Удалено строк: ${result.deleted}\nОшибок: ${result.errors}\n\nПервые ошибки:\n${errorsToShow.join('\n')}${moreErrors}`); - } else { - alert(`✓ Удалено строк: ${result.deleted}`); - } - } catch (e) { - document.body.removeChild(modal); - console.error(e); - alert('Ошибка удаления: ' + e.message); + document.body.removeChild(modal); + + selectedRowsData.clear(); + updateSelectionCounter(); + await table.replaceData(); + + if (result.errors > 0) { + const errorsToShow = result.errorMessages.slice(0, 10); + const moreErrors = result.errorMessages.length > 10 + ? `\n... и еще ${result.errorMessages.length - 10} ошибок` + : ''; + alert(`Удалено строк: ${result.deleted}\nОшибок: ${result.errors}\n\nПервые ошибки:\n${errorsToShow.join('\n')}${moreErrors}`); + } else { + alert(`✓ Удалено строк: ${result.deleted}`); } + } catch (e) { + document.body.removeChild(modal); + console.error(e); + alert('Ошибка удаления: ' + e.message); } }); - // ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ CSV ========== function detectDelimiter(text) { @@ -849,4 +847,4 @@ document.getElementById('btnExportCSV').addEventListener('click', async () => { console.error('Ошибка экспорта:', err); alert('Ошибка экспорта: ' + err.message); } -}); \ No newline at end of file +});