// frontend/js/app.js import * as api from './api.js'; const PLATFORMS = [ { id: 'ozon', name: 'Ozon' }, { id: 'wb', name: 'Wildberries' }, { id: 'ym', name: 'Yandex Market' }, { id: 'mm', name: 'Magnit Market' }, { id: 'mega', name: 'MegaMarket' }, { id: 'ae', name: 'AliExpress' }, { id: 'avito', name: 'Avito' }, { id: 'lamoda', name: 'Lamoda' }, { id: 'lemana', name: 'Lemana PRO' }, { id: 'flowwow', name: 'Flowwow' } ]; let currentUser = null; document.addEventListener("DOMContentLoaded", async () => { initAuth(); initReports(); // Check if logged in const token = localStorage.getItem('token'); if (token) { try { currentUser = await api.getMe(); const planBadge = currentUser.plan === 'pro' ? '[PRO]' : '[FREE]'; document.getElementById('username-display').innerHTML = `Привет, ${currentUser.username} ${planBadge}`; showApp(); } catch (e) { showAuth(); } } else { showAuth(); } }); let isLoginMode = true; function initAuth() { const authForm = document.getElementById('auth-form'); const toggleBtn = document.getElementById('auth-toggle'); const title = document.getElementById('auth-title'); const logoutBtn = document.getElementById('logout-btn'); toggleBtn.addEventListener('click', (e) => { e.preventDefault(); isLoginMode = !isLoginMode; title.textContent = isLoginMode ? 'Вход в систему' : 'Регистрация'; toggleBtn.textContent = isLoginMode ? 'Нет аккаунта? Зарегистрироваться' : 'Уже есть аккаунт? Войти'; }); authForm.addEventListener('submit', async (e) => { e.preventDefault(); const username = document.getElementById('auth-username').value; const password = document.getElementById('auth-password').value; try { if (isLoginMode) { const res = await api.login(username, password); localStorage.setItem('token', res.token); } else { await api.register(username, password); alert('Регистрация успешна! Теперь вы можете войти.'); isLoginMode = true; title.textContent = 'Вход в систему'; toggleBtn.textContent = 'Нет аккаунта? Зарегистрироваться'; return; } window.location.reload(); } catch (err) { alert(err.message); } }); logoutBtn.addEventListener('click', () => { localStorage.removeItem('token'); window.location.reload(); }); } function showAuth() { document.getElementById('auth-section').classList.remove('hidden'); document.getElementById('main-app').classList.add('hidden'); document.getElementById('user-info').classList.add('hidden'); } function showApp() { document.getElementById('auth-section').classList.add('hidden'); document.getElementById('main-app').classList.remove('hidden'); document.getElementById('user-info').classList.remove('hidden'); initTabs(); initCases(); initIntegrations(); initBilling(); initDashboard(); } function initDashboard() { loadDashboard(); } async function loadDashboard() { try { const stats = await api.getDashboardStats(); const grid = document.getElementById('stats-grid'); grid.innerHTML = `

Всего кейсов

${stats.total_cases}

Активных интеграций

${stats.total_integrations}

${stats.platforms.join(', ').toUpperCase()}

В работе (Prepared/Sent)

${(stats.cases_by_status.prepared || 0) + (stats.cases_by_status.sent || 0)}

`; const tbody = document.querySelector('#recent-activity-table tbody'); tbody.innerHTML = ''; stats.recent_activity.forEach(a => { const tr = document.createElement('tr'); const pName = PLATFORMS.find(p => p.id === a.platform)?.name || a.platform; tr.innerHTML = ` ${a.id} ${pName} ${a.article} ${a.status} ${new Date(a.date).toLocaleDateString()} `; tbody.appendChild(tr); }); } catch (e) { console.error(e); } } function initBilling() { document.getElementById('current-plan-display').textContent = currentUser.plan.toUpperCase(); document.getElementById('upgrade-btn').addEventListener('click', async () => { if(currentUser.plan === 'pro') { alert('У вас уже тариф PRO!'); return; } if(confirm('Перейти на PRO тариф (симуляция оплаты)?')) { try { await api.upgradePlan(); alert('Оплата прошла успешно! Вы теперь PRO.'); window.location.reload(); } catch (err) { alert(err.message); } } }); } function initTabs() { const btns = document.querySelectorAll('.tab-btn'); const sections = ['dashboard-section', 'cases-section', 'integrations-section', 'billing-section']; btns.forEach(btn => { btn.addEventListener('click', () => { btns.forEach(b => b.classList.remove('active')); btn.classList.add('active'); const target = btn.dataset.target; sections.forEach(s => { const el = document.getElementById(s); if (el) el.classList.add('hidden'); }); document.getElementById(target).classList.remove('hidden'); document.getElementById('case-form-section').classList.add('hidden'); document.getElementById('case-detail-section').classList.add('hidden'); if(target === 'dashboard-section') loadDashboard(); if(target === 'cases-section') loadCases(); if(target === 'integrations-section') loadIntegrations(); }); }); } // ---- INTEGRATIONS ---- async function loadIntegrations() { const grid = document.getElementById('platforms-grid'); grid.innerHTML = 'Загрузка...'; try { const configured = await api.getConfiguredPlatforms(); grid.innerHTML = ''; PLATFORMS.forEach(p => { const isConfigured = configured.includes(p.id); const card = document.createElement('div'); card.className = `platform-card ${isConfigured ? 'active-platform' : ''}`; card.innerHTML = `

${p.name}

${isConfigured ? '✅ Подключено' : '❌ Не настроено'}

`; card.querySelector('form').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const data = Object.fromEntries(formData); try { await api.saveCredentials(p.id, data); alert(`Настройки для ${p.name} сохранены!`); loadIntegrations(); } catch(err) { alert(err.message); } }); grid.appendChild(card); }); } catch (e) { grid.innerHTML = 'Ошибка загрузки интеграций.'; console.error(e); } } // ---- CASES ---- async function initCases() { document.getElementById('new-case-btn').addEventListener('click', () => { document.getElementById('cases-section').classList.add('hidden'); document.getElementById('case-form-section').classList.remove('hidden'); document.getElementById('case-form').reset(); }); document.getElementById('cancel-btn').addEventListener('click', () => { document.getElementById('case-form-section').classList.add('hidden'); document.getElementById('cases-section').classList.remove('hidden'); }); document.getElementById('back-to-list').addEventListener('click', () => { document.getElementById('case-detail-section').classList.add('hidden'); document.getElementById('cases-section').classList.remove('hidden'); loadCases(); }); document.getElementById('search-input').addEventListener('input', debounce(loadCases, 500)); document.getElementById('status-filter').addEventListener('change', loadCases); document.getElementById('platform-filter').addEventListener('change', loadCases); document.getElementById('case-form').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const data = Object.fromEntries(formData); try { const res = await api.createCase(data); const fileInput = document.getElementById('file-input'); if (fileInput.files.length > 0) { await api.uploadFiles(res.id, fileInput.files); } alert('Кейс успешно создан!'); document.getElementById('case-form-section').classList.add('hidden'); document.getElementById('cases-section').classList.remove('hidden'); loadCases(); } catch (err) { console.error(err); alert('Ошибка при сохранении'); } }); document.getElementById('export-csv-btn').addEventListener('click', () => { window.location.href = api.getExportCsvUrl(); }); loadCases(); } let currentViewCaseId = null; async function initReports() { document.getElementById('download-pdf-btn').addEventListener('click', () => { if (currentViewCaseId) { window.location.href = api.getCaseReportPdfUrl(currentViewCaseId); } }); } async function loadCases() { const article = document.getElementById('search-input').value; const status = document.getElementById('status-filter').value; const platform = document.getElementById('platform-filter').value; const tbody = document.querySelector('#cases-table tbody'); tbody.innerHTML = 'Загрузка...'; try { const cases = await api.fetchCases({ article, status, platform }); tbody.innerHTML = ''; if (cases.length === 0) { tbody.innerHTML = 'Нет жалоб'; return; } cases.forEach(c => { const tr = document.createElement('tr'); const pName = PLATFORMS.find(p => p.id === c.platform)?.name || c.platform; tr.innerHTML = ` ${c.id} ${pName} ${c.violator_article} ${c.status} ${new Date(c.created_at).toLocaleString()} `; tbody.appendChild(tr); }); } catch (err) { tbody.innerHTML = 'Ошибка сети'; } } window.viewCase = async function(id) { currentViewCaseId = id; document.getElementById('cases-section').classList.add('hidden'); const detailSection = document.getElementById('case-detail-section'); detailSection.classList.remove('hidden'); const caseObj = await api.getCase(id); const files = await api.listFiles(id); let html = `

Площадка: ${PLATFORMS.find(p => p.id === caseObj.platform)?.name || caseObj.platform}

Артикул нарушителя: ${caseObj.violator_article}

Ссылка: ${caseObj.violator_url}

Ваш артикул: ${caseObj.my_article || '-'}

Комментарий: ${caseObj.comment || '-'}

Статус: ${caseObj.status}

`; if (files && files.length > 0) { html += `

Файлы доказательств:

`; files.forEach(f => { const url = `http://localhost:5000/api/uploads/${f.path.split('/').pop()}`; html += `Док`; }); html += `
`; } document.getElementById('case-detail').innerHTML = html; }; window.deleteCase = async function(id) { if(confirm('Удалить этот кейс?')) { await api.deleteCase(id); loadCases(); } }; function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; }