Files
mario_scraper/static/js/main.js
2025-04-18 10:41:32 +03:00

530 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = `
<p>
Парсинг запущено для категорії: ${data.current_category}<br>
`;
if (data.total_products > 0) {
statusHtml += `
<strong>Товар ${data.current_product} із ${data.total_products}</strong><br>
Прогрес: ${data.progress}%
`;
} else {
statusHtml += `Отримання інформації про кількість товарів...`;
}
statusHtml += `</p>`;
status.innerHTML = statusHtml;
setTimeout(checkStatus, 500);
} else {
if (data.error) {
status.innerHTML = `<p class="error">Помилка: ${data.error}</p>`;
} else if (data.total_products > 0) {
status.innerHTML = `
<p>
Парсинг завершено<br>
<strong>Всього оброблено товарів: ${data.total_products}</strong>
</p>
`;
updateFilesList('parsed', 'parser', 'file-select');
}
button.disabled = false;
}
})
.catch(error => {
console.error('Status check error:', error);
status.innerHTML = `<p class="error">Помилка: ${error.message}</p>`;
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 = '<p class="error">Будь ласка, виберіть файл для обробки</p>';
return;
}
button.disabled = true;
status.innerHTML = '<p>Починаємо переклад...</p>';
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 = `<p class="error">${data.error}</p>`;
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 = `
<p>
Переклад в процесі...<br>
Оброблено: ${data.processed_items} з ${data.total_items}<br>
Прогрес: ${percent}%
</p>
`;
} else {
status.innerHTML = '<p>Підготовка до перекладу...</p>';
}
setTimeout(checkTranslationStatus, 1000);
} else {
if (data.error) {
status.innerHTML = `<p class="error">Помилка: ${data.error}</p>`;
} else if (data.total_items > 0) {
status.innerHTML = `
<p>
Переклад завершено<br>
Всього оброблено товарів: ${data.total_items}
</p>
`;
updateFilesList('translated', 'processor', 'yml-file-select');
}
button.disabled = false;
}
})
.catch(error => {
console.error('Translation status check error:', error);
status.innerHTML = `<p class="error">Помилка: ${error.message}</p>`;
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 = `
<span>${newId} - ${categoryName} ${portalId ? `(portal_id: ${portalId})` : ''}</span>
<button class="delete-btn" onclick="deleteCategory('${newId}')" title="Видалити категорію">🗑️</button>
`;
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 = '<p class="error">Будь ласка, виберіть категорію та файл</p>';
return;
}
button.disabled = true;
status.innerHTML = '<p>Генерація YML...</p>';
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 = `<p class="error">${data.error}</p>`;
} else {
status.innerHTML = '<p>YML файл успішно згенеровано</p>';
updateFilesList('yml', 'generator', null);
}
button.disabled = false;
})
.catch(error => {
status.innerHTML = `<p class="error">Помилка: ${error.message}</p>`;
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 => `
<li>
<div class="file-info">
<a href="/download/${file.name}" class="download-link" download>
${file.name}
</a>
<span class="file-date">${file.modified}</span>
<span class="file-size">${file.size}</span>
</div>
<button class="delete-btn" onclick="deleteFile('${file.name}', '${fileType}')" title="Видалити файл">
🗑️
</button>
</li>
`).join('');
// Обновляем select, если указан
if (selectId) {
const select = document.getElementById(selectId);
select.innerHTML = '<option value="">Виберіть файл...</option>' +
files.map(file => `
<option value="${file.name}">${file.name}</option>
`).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 = '<p class="error">Будь ласка, введіть URL</p>';
return;
}
button.disabled = true;
status.innerHTML = '<p>Починаємо парсинг...</p>';
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 = `<p class="error">${data.error}</p>`;
button.disabled = false;
} else {
checkParsingStatus();
}
})
.catch(error => {
status.innerHTML = `<p class="error">Помилка: ${error.message}</p>`;
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 = `
<p>
Парсинг в процесі...<br>
Оброблено: ${data.processed_items} з ${data.total_items}<br>
Прогрес: ${percent}%
</p>
`;
} else {
status.innerHTML = '<p>Отримання інформації про товари...</p>';
}
setTimeout(checkParsingStatus, 1000);
} else {
if (data.error) {
status.innerHTML = `<p class="error">Помилка: ${data.error}</p>`;
} else {
status.innerHTML = `
<p>
Парсинг завершено<br>
Всього оброблено товарів: ${data.total_items}
</p>
`;
updateFilesList('parsed', 'parser', 'file-select');
}
button.disabled = false;
}
})
.catch(error => {
console.error('Status check error:', error);
status.innerHTML = `<p class="error">Помилка: ${error.message}</p>`;
document.getElementById('parseButton').disabled = false;
});
}
function refreshOldestCategory() {
fetch('/manual-refresh-all', {
method: 'POST'
})
}