let statusCheckInterval; function startStatusCheck() { // Очищаем предыдущий интервал, если он существует if (statusCheckInterval) { clearInterval(statusCheckInterval); } // Проверяем статус каждые 500мс statusCheckInterval = setInterval(checkStatus, 500); // Сразу делаем первую проверку checkStatus(); } function checkStatus() { fetch('/status') .then(response => response.json()) .then(data => { const status = document.getElementById('status'); const button = document.getElementById('parseButton'); if (data.is_running) { let statusHtml = `

Парсинг запущено для категорії: ${data.current_category}
`; if (data.total_products > 0) { statusHtml += ` Товар ${data.current_product} із ${data.total_products}
Прогрес: ${data.progress}% `; } else { statusHtml += `Отримання інформації про кількість товарів...`; } statusHtml += `

`; status.innerHTML = statusHtml; setTimeout(checkStatus, 500); } else { if (data.error) { status.innerHTML = `

Помилка: ${data.error}

`; } else if (data.total_products > 0) { status.innerHTML = `

Парсинг завершено
Всього оброблено товарів: ${data.total_products}

`; updateFilesList('parsed', 'parser', 'file-select'); } button.disabled = false; } }) .catch(error => { console.error('Status check error:', error); status.innerHTML = `

Помилка: ${error.message}

`; button.disabled = false; }); } function stopStatusCheck() { if (statusCheckInterval) { clearInterval(statusCheckInterval); statusCheckInterval = null; } } function deleteFile(filename, type) { if (confirm('Ви впевнені, що хочете видалити цей файл?')) { fetch(`/delete/${filename}`, { method: 'POST' }) .then(response => response.json()) .then(data => { if (data.error) { alert(data.error); } else { // Удаляем файл из списка const fileItem = document.querySelector(`a[href*="${filename}"]`).closest('li'); fileItem.remove(); // Обновляем соответствующий select в зависимости от типа файла if (type === 'parsed') { const fileSelect = document.getElementById('file-select'); const optionToRemove = Array.from(fileSelect.options).find(opt => opt.value === filename); if (optionToRemove) { optionToRemove.remove(); } } else if (type === 'translated') { const ymlFileSelect = document.getElementById('yml-file-select'); const optionToRemove = Array.from(ymlFileSelect.options).find(opt => opt.value === filename); if (optionToRemove) { optionToRemove.remove(); } } } }) .catch(error => { console.error('Error:', error); alert('Помилка при видаленні файлу'); }); } } function openTab(tabName) { // Приховуємо всі вкладки const tabContents = document.getElementsByClassName('tab-content'); for (let content of tabContents) { content.classList.remove('active'); } // Деактивуємо всі кнопки const tabButtons = document.getElementsByClassName('tab-button'); for (let button of tabButtons) { button.classList.remove('active'); } // Показуємо вибрану вкладку document.getElementById(tabName).classList.add('active'); // Активуємо потрібну кнопку event.currentTarget.classList.add('active'); } function startTranslation() { const fileSelect = document.getElementById('file-select'); const button = document.getElementById('translateButton'); const status = document.getElementById('translation-status'); if (!fileSelect.value) { status.innerHTML = '

Будь ласка, виберіть файл для обробки

'; return; } button.disabled = true; status.innerHTML = '

Починаємо переклад...

'; fetch('/translate', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `filename=${encodeURIComponent(fileSelect.value)}` }) .then(response => response.json()) .then(data => { if (data.error) { status.innerHTML = `

${data.error}

`; button.disabled = false; } else { checkTranslationStatus(); } }); } function checkTranslationStatus() { fetch('/translation-status') .then(response => response.json()) .then(data => { const status = document.getElementById('translation-status'); const button = document.getElementById('translateButton'); if (data.is_running) { if (data.total_items > 0) { const percent = Math.round((data.processed_items / data.total_items) * 100); status.innerHTML = `

Переклад в процесі...
Оброблено: ${data.processed_items} з ${data.total_items}
Прогрес: ${percent}%

`; } else { status.innerHTML = '

Підготовка до перекладу...

'; } setTimeout(checkTranslationStatus, 1000); } else { if (data.error) { status.innerHTML = `

Помилка: ${data.error}

`; } else if (data.total_items > 0) { status.innerHTML = `

Переклад завершено
Всього оброблено товарів: ${data.total_items}

`; updateFilesList('translated', 'processor', 'yml-file-select'); } button.disabled = false; } }) .catch(error => { console.error('Translation status check error:', error); status.innerHTML = `

Помилка: ${error.message}

`; document.getElementById('translateButton').disabled = false; }); } function generateFullYML() { if (!confirm("Згенерувати загальний YML-файл для всіх категорій?")) return; fetch('/generate-full-yml', { method: 'POST' }) .then(response => response.json()) .then(data => { if (data.success) { alert("Повний YML успішно згенеровано"); updateFilesList('yml', 'generator'); } else { alert("Помилка: " + (data.error || "Невідома помилка")); } }); } function updateItemsLimit(value) { fetch('/update-settings', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ items_limit: parseInt(value) }) }) .then(response => response.json()) .then(data => { if (data.error) { alert(data.error); } }); } function addCategory() { const categoryName = document.getElementById('category-name').value; const portalId = document.getElementById('portal-id').value; const categoryUrl = document.getElementById('category-url').value; if (!categoryName || !categoryUrl) { alert('Будь ласка, заповніть назву і URL категорії'); return; } fetch('/add-category', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: categoryName, portal_id: portalId, url: categoryUrl }) }) .then(response => response.json()) .then(data => { if (data.error) { alert(data.error); } else { const newId = data.id; document.getElementById('category-name').value = ''; document.getElementById('portal-id').value = ''; document.getElementById('category-url').value = ''; const categoriesList = document.getElementById('categories-list'); const li = document.createElement('li'); li.title = categoryUrl; li.innerHTML = ` ${newId} - ${categoryName} ${portalId ? `(portal_id: ${portalId})` : ''} `; categoriesList.appendChild(li); const ymlSelect = document.getElementById('yml-category-select'); const option = document.createElement('option'); option.value = newId; option.text = categoryName; ymlSelect.appendChild(option); } }); } function deleteCategory(categoryId) { if (confirm('Ви впевнені, що хочете видалити цю категорію?')) { fetch('/delete-category', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: categoryId }) }) .then(response => response.json()) .then(data => { if (data.error) { alert(data.error); } else { // Удаляем категорию из списка const categoryItems = document.querySelectorAll('#categories-list li'); categoryItems.forEach(item => { if (item.querySelector('span').textContent.startsWith(categoryId + ' -')) { item.remove(); } }); // Удаляем опцию из select в генераторе YML const ymlSelect = document.getElementById('yml-category-select'); const option = Array.from(ymlSelect.options).find(opt => opt.value === categoryId); if (option) option.remove(); } }); } } function generateYML() { console.log('generateYML called'); // Отладка const categoryId = document.getElementById('yml-category-select').value; const fileSelect = document.getElementById('yml-file-select'); console.log('Selected category:', categoryId); // Отладка console.log('Selected file:', fileSelect.value); // Отладка const button = document.getElementById('generateButton'); const status = document.getElementById('yml-status'); if (!categoryId || !fileSelect.value) { status.innerHTML = '

Будь ласка, виберіть категорію та файл

'; return; } button.disabled = true; status.innerHTML = '

Генерація YML...

'; fetch('/generate-yml', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ filename: fileSelect.value, category_id: categoryId }) }) .then(response => response.json()) .then(data => { if (data.error) { status.innerHTML = `

${data.error}

`; } else { status.innerHTML = '

YML файл успішно згенеровано

'; updateFilesList('yml', 'generator', null); } button.disabled = false; }) .catch(error => { status.innerHTML = `

Помилка: ${error.message}

`; button.disabled = false; }); } // Добавляем вспомогательную функцию для поиска по тексту jQuery.expr[':'].contains = function (a, i, m) { return jQuery(a).text().toUpperCase() .indexOf(m[3].toUpperCase()) >= 0; }; function updateFilesList(fileType, containerId, selectId = null) { fetch(`/get-files/${fileType}`) .then(response => response.json()) .then(files => { // Обновляем список файлов const filesList = document.querySelector(`#${containerId} .files ul`); filesList.innerHTML = files.map(file => `
  • ${file.name} ${file.modified} ${file.size}
  • `).join(''); // Обновляем select, если указан if (selectId) { const select = document.getElementById(selectId); select.innerHTML = '' + files.map(file => ` `).join(''); } }); } function showLoader(element) { element.classList.add('loading'); } function hideLoader(element) { element.classList.remove('loading'); } function showError(message) { const errorDiv = document.createElement('div'); errorDiv.className = 'error-message'; errorDiv.textContent = message; document.body.appendChild(errorDiv); setTimeout(() => errorDiv.remove(), 3000); } // Использование: async function someAction() { const element = document.getElementById('someElement'); showLoader(element); try { const response = await fetch('/some-endpoint'); const data = await response.json(); if (data.error) throw new Error(data.error); // обработка успешного ответа } catch (error) { showError(error.message); } finally { hideLoader(element); } } function translateAllCategories() { if (!confirm("Запустити переклад для всіх категорій?")) return; fetch('/manual-translate-all', { method: 'POST' }) .then(response => response.json()) .then(data => { if (data.message) { alert(data.message); } else { alert("Переклад запущено."); } }) .catch(error => { alert("Помилка при запуску перекладу: " + error.message); }); } function startParsing() { const url = document.getElementById('url').value; const button = document.getElementById('parseButton'); const status = document.getElementById('status'); if (!url) { status.innerHTML = '

    Будь ласка, введіть URL

    '; return; } button.disabled = true; status.innerHTML = '

    Починаємо парсинг...

    '; fetch('/parse', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `url=${encodeURIComponent(url)}` }) .then(response => response.json()) .then(data => { if (data.error) { status.innerHTML = `

    ${data.error}

    `; button.disabled = false; } else { checkParsingStatus(); } }) .catch(error => { status.innerHTML = `

    Помилка: ${error.message}

    `; button.disabled = false; }); } function checkParsingStatus() { fetch('/status') .then(response => response.json()) .then(data => { const status = document.getElementById('status'); const button = document.getElementById('parseButton'); if (data.is_running) { if (data.total_items > 0) { const percent = Math.round((data.processed_items / data.total_items) * 100); status.innerHTML = `

    Парсинг в процесі...
    Оброблено: ${data.processed_items} з ${data.total_items}
    Прогрес: ${percent}%

    `; } else { status.innerHTML = '

    Отримання інформації про товари...

    '; } setTimeout(checkParsingStatus, 1000); } else { if (data.error) { status.innerHTML = `

    Помилка: ${data.error}

    `; } else { status.innerHTML = `

    Парсинг завершено
    Всього оброблено товарів: ${data.total_items}

    `; updateFilesList('parsed', 'parser', 'file-select'); } button.disabled = false; } }) .catch(error => { console.error('Status check error:', error); status.innerHTML = `

    Помилка: ${error.message}

    `; document.getElementById('parseButton').disabled = false; }); } function refreshOldestCategory() { fetch('/manual-refresh-all', { method: 'POST' }) }