document.addEventListener('DOMContentLoaded', function() { const form = document.getElementById('wfmForm'); const resultsSection = document.getElementById('results'); const historyList = document.getElementById('historyList'); const uploadArea = document.getElementById('uploadArea'); const fileInput = document.getElementById('fileInput'); const uploadStatus = document.getElementById('uploadStatus'); const monthlyResults = document.getElementById('monthlyResults'); const tabs = document.querySelectorAll('.tab'); const modes = { manual: document.getElementById('manualMode'), upload: document.getElementById('uploadMode'), monthly: document.getElementById('monthlyMode') }; tabs.forEach(tab => { tab.addEventListener('click', function() { const mode = this.dataset.mode; tabs.forEach(t => t.classList.remove('active')); this.classList.add('active'); Object.keys(modes).forEach(k => modes[k].classList.remove('active')); modes[mode].classList.add('active'); if (mode === 'monthly') { loadMonthlyResults(); } }); }); form.addEventListener('submit', async function(e) { e.preventDefault(); const formData = new FormData(form); const params = {}; formData.forEach((value, key) => { if (value !== '') { params[key] = parseFloat(value); } }); try { const response = await fetch('/api/calculate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); const results = await response.json(); displayResults(results); loadHistory(); resultsSection.style.display = 'block'; resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); } catch (error) { alert('Ошибка расчёта: ' + error.message); } }); uploadArea.addEventListener('click', () => fileInput.click()); uploadArea.addEventListener('dragover', (e) => { e.preventDefault(); uploadArea.classList.add('dragover'); }); uploadArea.addEventListener('dragleave', () => { uploadArea.classList.remove('dragover'); }); uploadArea.addEventListener('drop', (e) => { e.preventDefault(); uploadArea.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { handleFile(files[0]); } }); fileInput.addEventListener('change', (e) => { if (e.target.files.length > 0) { handleFile(e.target.files[0]); } }); async function handleFile(file) { uploadStatus.innerHTML = '
Загрузка файла...
'; const formData = new FormData(); formData.append('file', file); try { const response = await fetch('/api/upload', { method: 'POST', body: formData }); const result = await response.json(); if (result.ok) { uploadStatus.innerHTML = '
✅ Файл загружен! Найдено месяцев: ' + result.months.length + '
'; if (result.months.length > 0) { displayMonthlyResults(result.months, result.globalParams); tabs[2].click(); } } else { uploadStatus.innerHTML = '
Ошибка: ' + result.error + '
'; } } catch (error) { uploadStatus.innerHTML = '
Ошибка загрузки: ' + error.message + '
'; } } function displayResults(results) { if (results.incoming) { document.getElementById('resIncoming').textContent = results.incoming.fte; document.getElementById('resIncomingSL').textContent = 'SL: ' + results.incoming.sl + '%'; } else { document.getElementById('resIncoming').textContent = '-'; document.getElementById('resIncomingSL').textContent = ''; } if (results.outgoing) { document.getElementById('resOutgoing').textContent = results.outgoing.fte; } else { document.getElementById('resOutgoing').textContent = '-'; } if (results.tickets) { document.getElementById('resTickets').textContent = results.tickets.fte; } else { document.getElementById('resTickets').textContent = '-'; } if (results.chats) { document.getElementById('resChats').textContent = results.chats.fte; } else { document.getElementById('resChats').textContent = '-'; } document.getElementById('resTotalSchedule').textContent = results.total.fteInSchedule.toFixed(1); document.getElementById('resTotalWithAbsence').textContent = results.total.fteWithAbsence.toFixed(1); } function displayMonthlyResults(months, params) { const totalFTE = months.reduce((sum, m) => sum + m.results.total.fteWithAbsence, 0); const avgFTE = totalFTE / months.length; let html = `

Итого за период

${avgFTE.toFixed(1)}
Среднее FTE в штате
${totalFTE.toFixed(1)}
Суммарно FTE (все месяцы)
${months.length}
Месяцев в расчёте

Детализация по месяцам

`; months.forEach(m => { html += ` `; }); html += `
Месяц Входящие Исходящие Тикеты Чаты FTE в графике FTE в штате
${m.month} ${m.incomingCalls.toLocaleString('ru-RU')} ${m.outgoingCalls ? m.outgoingCalls.toLocaleString('ru-RU') : '-'} ${m.tickets ? m.tickets.toLocaleString('ru-RU') : '-'} ${m.chats ? m.chats.toLocaleString('ru-RU') : '-'} ${m.results.total.fteInSchedule.toFixed(1)} ${m.results.total.fteWithAbsence.toFixed(1)}
`; monthlyResults.innerHTML = html; } async function loadHistory() { try { const response = await fetch('/api/history'); const history = await response.json(); if (history.length === 0) { historyList.innerHTML = '
История пуста
'; return; } historyList.innerHTML = history.map(calc => { const date = new Date(calc.date).toLocaleString('ru-RU'); const total = calc.results.total.fteWithAbsence.toFixed(1); return `
${total} FTE ${date}
Вх: ${calc.results.incoming ? calc.results.incoming.fte : '-'} | Исх: ${calc.results.outgoing ? calc.results.outgoing.fte : '-'} | Чаты: ${calc.results.chats ? calc.results.chats.fte : '-'}
`; }).join(''); } catch (error) { console.error('Ошибка загрузки истории:', error); } } async function loadMonthlyResults() { try { const response = await fetch('/api/monthly'); const data = await response.json(); if (!data || data.length === 0) { monthlyResults.innerHTML = `

Нет данных

Загрузите Excel файл во вкладке "Загрузить Excel" для расчёта по месяцам

`; return; } displayMonthlyResults(data, {}); } catch (error) { console.error('Ошибка:', error); monthlyResults.innerHTML = '
Ошибка загрузки данных
'; } } loadHistory(); });