let currentTab = 'biot'; let currentSubtab = null; let events = { biot: [], ctpsr_main: [], gloves: [] }; let currentFilter = 'все'; async function loadEvents() { try { const [biotRes, ctpsrRes, glovesRes] = await Promise.all([ fetch('/api/events?tab=biot'), fetch('/api/events?tab=ctpsr_main'), fetch('/api/events?tab=gloves') ]); events.biot = await biotRes.json(); events.ctpsr_main = await ctpsrRes.json(); events.gloves = await glovesRes.json(); console.log('Loaded events:', { biot: events.biot.length, ctpsr_main: events.ctpsr_main.length, gloves: events.gloves.length }); } catch (e) { console.error('Ошибка загрузки:', e); } } function switchTab(tab) { currentTab = tab; document.querySelectorAll('.tab').forEach(function(t) { t.classList.remove('active'); }); var activeBtn = document.querySelector('.tab[onclick="switchTab(\'' + tab + '\')"]'); if (activeBtn) activeBtn.classList.add('active'); var subtabsContainer = document.getElementById('subtabs'); if (tab === 'ctpsr') { subtabsContainer.style.display = 'flex'; currentSubtab = 'ctpsr_main'; document.getElementById('page-title').textContent = 'Информация по ЦТПСР'; } else { subtabsContainer.style.display = 'none'; currentSubtab = null; document.getElementById('page-title').textContent = tab === 'biot' ? 'Информация по БиОТ' : 'Мероприятия'; } console.log('switchTab:', tab, 'currentSubtab:', currentSubtab); render(); } function switchSubtab(subtab) { currentSubtab = subtab; document.querySelectorAll('.subtab').forEach(function(t) { t.classList.remove('active'); }); var activeBtn = document.querySelector('.subtab[onclick="switchSubtab(\'' + subtab + '\')"]'); if (activeBtn) activeBtn.classList.add('active'); console.log('switchSubtab:', subtab); render(); } function escapeHtml(text) { if (!text) return ''; var div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function formatDate(dateStr) { if (!dateStr) return ''; var d = new Date(dateStr); return d.toLocaleDateString('ru-RU', { day: 'numeric', month: 'long', year: 'numeric' }); } function setFilter(status) { currentFilter = status; render(); } function render() { var search = document.getElementById('search').value.toLowerCase(); var key = currentSubtab || currentTab; var currentEvents = events[key] || []; var isGloves = key === 'gloves'; console.log('render key:', key, 'events count:', currentEvents.length); var filtered; if (isGloves) { filtered = currentEvents.filter(function(e) { return (e.quantity && e.quantity.toLowerCase().includes(search)) || (e.location && e.location.toLowerCase().includes(search)) || (e.responsible && e.responsible.toLowerCase().includes(search)); }); } else { filtered = currentEvents.filter(function(e) { var matchSearch = e.title.toLowerCase().includes(search) || (e.description && e.description.toLowerCase().includes(search)) || (e.organizer && e.organizer.toLowerCase().includes(search)); var matchFilter = currentFilter === 'все' || e.status === currentFilter; return matchSearch && matchFilter; }); } var statsEl = document.getElementById('stats'); var chipsEl = document.getElementById('chips'); if (!isGloves) { var statuses = ['запланировано', 'в процессе', 'завершено', 'отменено']; var counts = { все: currentEvents.length }; statuses.forEach(function(s) { counts[s] = currentEvents.filter(function(ev) { return ev.status === s; }).length; }); statsEl.innerHTML = `
${counts.все}
Всего
${counts['запланировано']}
Запланировано
${counts['в процессе']}
В процессе
${counts['завершено']}
Завершено
`; chipsEl.innerHTML = ['все', ...statuses].map(function(s) { return `
${s.charAt(0).toUpperCase() + s.slice(1)} (${counts[s] || 0})
`; }).join(''); } else { statsEl.innerHTML = ''; chipsEl.innerHTML = ''; } var container = document.getElementById('events'); if (filtered.length === 0) { container.innerHTML = `

Нет записей

Нажмите «Добавить», чтобы создать первую запись

`; return; } if (isGloves) { container.innerHTML = `
${filtered.map(function(e) { return ``; }).join('')}
Количество Место эксплуатации Ответственное лицо Последнее испытание Следующее испытание Срок (мес) Действия
${escapeHtml(e.quantity || '')} ${escapeHtml(e.location || '')} ${escapeHtml(e.responsible || '')} ${e.lastTestDate ? formatDate(e.lastTestDate) : ''} ${e.nextTestDate ? formatDate(e.nextTestDate) : ''} ${e.expiryMonths ? e.expiryMonths + ' мес.' : ''}
`; } else { container.innerHTML = filtered.map(function(e) { return `
${escapeHtml(e.title)}
${e.status}
${e.date ? `📅 ${formatDate(e.date)}` : ''} ${e.time ? `⏰ ${e.time}` : ''} ${e.location ? `📍 ${escapeHtml(e.location)}` : ''} ${e.organizer ? `👤 ${escapeHtml(e.organizer)}` : ''}
${e.description ? `
${escapeHtml(e.description)}
` : ''}
`; }).join(''); } } function openModal(editId = null) { var modal = document.getElementById('modal'); var form = document.getElementById('form'); var title = document.getElementById('modal-title'); console.log('=== OPEN MODAL ==='); console.log('currentTab:', currentTab, 'currentSubtab:', currentSubtab); form.reset(); document.getElementById('eventId').value = ''; var key = currentSubtab || currentTab; var isGloves = key === 'gloves'; console.log('key:', key, 'isGloves:', isGloves); var glovesFields = document.getElementById('gloves-fields'); var eventFields = document.getElementById('event-fields'); glovesFields.style.display = isGloves ? 'block' : 'none'; eventFields.style.display = isGloves ? 'none' : 'block'; // Убираем required у скрытых полей var glovesInputs = glovesFields.querySelectorAll('input, textarea'); var eventInputs = eventFields.querySelectorAll('input, textarea, select'); glovesInputs.forEach(function(input) { input.required = isGloves && input.id !== 'notes'; }); eventInputs.forEach(function(input) { input.required = !isGloves; }); if (editId) { var item = events[key].find(function(e) { return e.id === editId; }); if (item) { title.textContent = isGloves ? 'Изменить запись' : 'Изменить мероприятие'; document.getElementById('eventId').value = item.id; if (isGloves) { document.getElementById('quantity').value = item.quantity || ''; document.getElementById('location').value = item.location || ''; document.getElementById('responsible').value = item.responsible || ''; document.getElementById('lastTestDate').value = item.lastTestDate || ''; document.getElementById('nextTestDate').value = item.nextTestDate || ''; document.getElementById('expiryMonths').value = item.expiryMonths || ''; document.getElementById('notes').value = item.notes || ''; } else { document.getElementById('title').value = item.title; document.getElementById('date').value = item.date; document.getElementById('time').value = item.time || ''; document.getElementById('eventLocation').value = item.location || ''; document.getElementById('organizer').value = item.organizer || ''; document.getElementById('status').value = item.status; document.getElementById('description').value = item.description || ''; } } } else { title.textContent = isGloves ? 'Добавить перчатки' : 'Добавить мероприятие'; } modal.classList.add('on'); } function closeModal() { document.getElementById('modal').classList.remove('on'); } function editEvent(id) { openModal(id); } function addNew() { openModal(null); } async function deleteEvent(id) { if (!confirm('Вы уверены, что хотите удалить эту запись?')) return; var key = currentSubtab || currentTab; await fetch('/api/events/' + id + '?tab=' + key, { method: 'DELETE' }); await loadEvents(); render(); } document.getElementById('form').addEventListener('submit', async function(e) { e.preventDefault(); var id = document.getElementById('eventId').value; var key = currentSubtab || currentTab; var isGloves = key === 'gloves'; var btn = e.target.querySelector('button[type="submit"]'); var originalText = btn.textContent; console.log('=== FORM SUBMIT ==='); console.log('key:', key, 'isGloves:', isGloves, 'currentSubtab:', currentSubtab, 'currentTab:', currentTab); // Временно убираем required у всех полей, чтобы браузер не блокировал var allInputs = e.target.querySelectorAll('input, textarea, select'); var requiredBackup = []; allInputs.forEach(function(input, i) { requiredBackup[i] = input.required; input.required = false; }); btn.textContent = 'Сохранение...'; btn.disabled = true; var data = isGloves ? { quantity: document.getElementById('quantity').value, location: document.getElementById('location').value, responsible: document.getElementById('responsible').value, lastTestDate: document.getElementById('lastTestDate').value, nextTestDate: document.getElementById('nextTestDate').value, expiryMonths: document.getElementById('expiryMonths').value, notes: document.getElementById('notes').value } : { title: document.getElementById('title').value, date: document.getElementById('date').value, time: document.getElementById('time').value, location: document.getElementById('eventLocation').value, organizer: document.getElementById('organizer').value, status: document.getElementById('status').value, description: document.getElementById('description').value }; console.log('Data to save:', data); var url = id ? '/api/events/' + id + '?tab=' + key : '/api/events?tab=' + key; console.log('POST to:', url); try { var response = await fetch(url, { method: id ? 'PUT' : 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); var responseText = await response.text(); console.log('Response status:', response.status, 'body:', responseText); if (!response.ok) { throw new Error('Сервер вернул ' + response.status + ': ' + responseText); } var result = JSON.parse(responseText); console.log('Server response:', result); // Возвращаем required обратно allInputs.forEach(function(input, i) { input.required = requiredBackup[i]; }); closeModal(); await loadEvents(); render(); alert('✓ Запись сохранена!'); } catch (error) { // Возвращаем required обратно allInputs.forEach(function(input, i) { input.required = requiredBackup[i]; }); console.error('Error saving:', error); alert('Ошибка сохранения: ' + error.message); } finally { btn.textContent = originalText; btn.disabled = false; } }); document.getElementById('modal').addEventListener('click', function(e) { if (e.target === e.currentTarget) closeModal(); }); loadEvents();