Hoghoghi / frontend /js /scraping-control.js
Really-amin's picture
Upload 143 files
c636ebf verified
raw
history blame
13.4 kB
/**
* Scraping Control Panel for Legal Dashboard
* Manages web scraping operations, real-time monitoring, and results display
*/
class ScrapingControlPanel {
constructor() {
this.baseEndpoint = '/api/scraping';
this.currentJob = null;
this.isRunning = false;
this.statusInterval = null;
this.logs = [];
this.initializeEventListeners();
this.loadScrapingStatus();
}
initializeEventListeners() {
// Start scraping button
const startBtn = document.getElementById('startScrapingBtn');
if (startBtn) {
startBtn.addEventListener('click', () => this.startScraping());
}
// Stop scraping button
const stopBtn = document.getElementById('stopScrapingBtn');
if (stopBtn) {
stopBtn.addEventListener('click', () => this.stopScraping());
}
// Refresh results button
const refreshBtn = document.getElementById('refreshResultsBtn');
if (refreshBtn) {
refreshBtn.addEventListener('click', () => this.loadScrapingResults());
}
// Clear logs button
const clearLogsBtn = document.getElementById('clearLogsBtn');
if (clearLogsBtn) {
clearLogsBtn.addEventListener('click', () => this.clearLogs());
}
}
async startScraping() {
if (this.isRunning) {
this.showToast('اسکرپینگ در حال انجام است', 'warning');
return;
}
const scrapingConfig = this.getScrapingConfig();
if (!scrapingConfig.url) {
this.showToast('لطفاً URL را وارد کنید', 'error');
return;
}
try {
this.isRunning = true;
this.updateStartButton(true);
this.addLog('شروع اسکرپینگ...', 'info');
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/start`, {
method: 'POST',
body: JSON.stringify(scrapingConfig)
});
this.currentJob = response.job_id;
this.showToast('اسکرپینگ شروع شد', 'success');
this.addLog(`شغل اسکرپینگ ایجاد شد: ${this.currentJob}`, 'success');
// Start monitoring
this.startStatusMonitoring();
} catch (error) {
this.showToast(`خطا در شروع اسکرپینگ: ${error.message}`, 'error');
this.addLog(`خطا در شروع اسکرپینگ: ${error.message}`, 'error');
this.isRunning = false;
this.updateStartButton(false);
}
}
async stopScraping() {
if (!this.isRunning) {
this.showToast('هیچ اسکرپینگی در حال انجام نیست', 'warning');
return;
}
try {
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/stop`, {
method: 'POST',
body: JSON.stringify({ job_id: this.currentJob })
});
this.showToast('اسکرپینگ متوقف شد', 'success');
this.addLog('اسکرپینگ متوقف شد', 'info');
this.isRunning = false;
this.currentJob = null;
this.updateStartButton(false);
this.stopStatusMonitoring();
} catch (error) {
this.showToast(`خطا در توقف اسکرپینگ: ${error.message}`, 'error');
this.addLog(`خطا در توقف اسکرپینگ: ${error.message}`, 'error');
}
}
async loadScrapingStatus() {
try {
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/status`);
this.updateStatusDisplay(response);
} catch (error) {
console.error('Failed to load scraping status:', error);
}
}
async loadScrapingResults() {
try {
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/results`);
this.renderResults(response);
} catch (error) {
console.error('Failed to load scraping results:', error);
this.showToast('خطا در بارگذاری نتایج', 'error');
}
}
async loadScrapingStatistics() {
try {
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/statistics`);
this.renderStatistics(response);
} catch (error) {
console.error('Failed to load scraping statistics:', error);
}
}
startStatusMonitoring() {
this.statusInterval = setInterval(async () => {
if (this.isRunning) {
await this.updateScrapingStatus();
}
}, 5000); // Update every 5 seconds
}
stopStatusMonitoring() {
if (this.statusInterval) {
clearInterval(this.statusInterval);
this.statusInterval = null;
}
}
async updateScrapingStatus() {
try {
const response = await fetchWithErrorHandling(`${this.baseEndpoint}/status`);
this.updateStatusDisplay(response);
// Check if scraping is complete
if (response.status === 'completed' || response.status === 'failed') {
this.isRunning = false;
this.currentJob = null;
this.updateStartButton(false);
this.stopStatusMonitoring();
if (response.status === 'completed') {
this.addLog('اسکرپینگ تکمیل شد', 'success');
this.loadScrapingResults();
} else {
this.addLog('اسکرپینگ با خطا مواجه شد', 'error');
}
}
} catch (error) {
console.error('Failed to update scraping status:', error);
}
}
updateStatusDisplay(status) {
const statusElement = document.getElementById('scrapingStatus');
const progressElement = document.getElementById('scrapingProgress');
const statsElement = document.getElementById('scrapingStats');
if (statusElement) {
statusElement.textContent = this.getStatusText(status.status);
statusElement.className = `status-indicator ${this.getStatusClass(status.status)}`;
}
if (progressElement && status.progress) {
progressElement.style.width = `${status.progress}%`;
progressElement.textContent = `${status.progress}%`;
}
if (statsElement) {
statsElement.innerHTML = `
<div class="stat-item">
<span class="stat-label">صفحات پردازش شده:</span>
<span class="stat-value">${status.pages_processed || 0}</span>
</div>
<div class="stat-item">
<span class="stat-label">نتایج یافت شده:</span>
<span class="stat-value">${status.items_found || 0}</span>
</div>
<div class="stat-item">
<span class="stat-label">زمان سپری شده:</span>
<span class="stat-value">${status.elapsed_time || '0s'}</span>
</div>
`;
}
}
renderResults(results) {
const container = document.getElementById('scrapingResults');
if (!container) return;
if (!results.items || results.items.length === 0) {
container.innerHTML = '<p class="no-results">هیچ نتیجه‌ای یافت نشد</p>';
return;
}
const resultsHTML = results.items.map(item => `
<div class="scraping-item">
<div class="item-header">
<h4 class="item-title">${item.title || 'بدون عنوان'}</h4>
<span class="item-rating">امتیاز: ${item.rating || 0}</span>
</div>
<div class="item-content">
<p class="item-url">
<a href="${item.url}" target="_blank">${item.url}</a>
</p>
<p class="item-description">${item.description || 'توضیحات موجود نیست'}</p>
<div class="item-meta">
<span class="item-date">${this.formatDate(item.date)}</span>
<span class="item-category">${item.category || 'نامشخص'}</span>
</div>
</div>
</div>
`).join('');
container.innerHTML = resultsHTML;
}
renderStatistics(stats) {
const container = document.getElementById('scrapingStatistics');
if (!container) return;
const statsHTML = `
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number">${stats.total_scraped || 0}</div>
<div class="stat-label">کل نتایج</div>
</div>
<div class="stat-card">
<div class="stat-number">${stats.success_rate || 0}%</div>
<div class="stat-label">نرخ موفقیت</div>
</div>
<div class="stat-card">
<div class="stat-number">${stats.average_speed || 0}</div>
<div class="stat-label">سرعت متوسط (صفحه/دقیقه)</div>
</div>
<div class="stat-card">
<div class="stat-number">${stats.average_rating || 0}</div>
<div class="stat-label">امتیاز متوسط</div>
</div>
</div>
`;
container.innerHTML = statsHTML;
}
getScrapingConfig() {
const urlInput = document.getElementById('scrapingUrl');
const depthInput = document.getElementById('scrapingDepth');
const maxPagesInput = document.getElementById('maxPages');
const filtersInput = document.getElementById('scrapingFilters');
return {
url: urlInput ? urlInput.value : '',
depth: depthInput ? parseInt(depthInput.value) : 1,
max_pages: maxPagesInput ? parseInt(maxPagesInput.value) : 100,
filters: filtersInput ? filtersInput.value : ''
};
}
updateStartButton(isRunning) {
const startBtn = document.getElementById('startScrapingBtn');
const stopBtn = document.getElementById('stopScrapingBtn');
if (startBtn) {
startBtn.disabled = isRunning;
startBtn.textContent = isRunning ? 'در حال اجرا...' : 'شروع اسکرپینگ';
}
if (stopBtn) {
stopBtn.disabled = !isRunning;
stopBtn.style.display = isRunning ? 'inline-block' : 'none';
}
}
addLog(message, type = 'info') {
const timestamp = new Date().toLocaleTimeString('fa-IR');
const logEntry = {
timestamp,
message,
type
};
this.logs.unshift(logEntry);
this.renderLogs();
// Keep only last 100 logs
if (this.logs.length > 100) {
this.logs = this.logs.slice(0, 100);
}
}
renderLogs() {
const container = document.getElementById('scrapingLogs');
if (!container) return;
const logsHTML = this.logs.map(log => `
<div class="log-entry ${log.type}">
<span class="log-timestamp">${log.timestamp}</span>
<span class="log-message">${log.message}</span>
</div>
`).join('');
container.innerHTML = logsHTML;
}
clearLogs() {
this.logs = [];
this.renderLogs();
this.showToast('لاگ‌ها پاک شدند', 'info');
}
getStatusClass(status) {
const statusMap = {
'idle': 'status-idle',
'running': 'status-running',
'completed': 'status-completed',
'failed': 'status-failed',
'stopped': 'status-stopped'
};
return statusMap[status] || 'status-unknown';
}
getStatusText(status) {
const statusMap = {
'idle': 'آماده',
'running': 'در حال اجرا',
'completed': 'تکمیل شده',
'failed': 'ناموفق',
'stopped': 'متوقف شده'
};
return statusMap[status] || 'نامشخص';
}
formatDate(dateString) {
if (!dateString) return 'نامشخص';
const date = new Date(dateString);
return date.toLocaleDateString('fa-IR');
}
showToast(message, type = 'info') {
if (typeof showToast === 'function') {
showToast(message, type);
} else {
console.log(`${type.toUpperCase()}: ${message}`);
}
}
}
// Initialize scraping control panel
const scrapingControlPanel = new ScrapingControlPanel();