https-git-vibe42-kz-111/script.js
2026-09-10 09:03:22 +00:00

375 lines
14 KiB
JavaScript
Raw Permalink 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 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 = `
<div class="stat-card">
<div class="number">${counts.все}</div>
<div class="label">Всего</div>
</div>
<div class="stat-card">
<div class="number">${counts['запланировано']}</div>
<div class="label">Запланировано</div>
</div>
<div class="stat-card">
<div class="number">${counts['в процессе']}</div>
<div class="label">В процессе</div>
</div>
<div class="stat-card">
<div class="number">${counts['завершено']}</div>
<div class="label">Завершено</div>
</div>
`;
chipsEl.innerHTML = ['все', ...statuses].map(function(s) {
return `<div class="chip ${currentFilter === s ? 'active' : ''}" onclick="setFilter('${s}')">
${s.charAt(0).toUpperCase() + s.slice(1)} (${counts[s] || 0})
</div>`;
}).join('');
} else {
statsEl.innerHTML = '';
chipsEl.innerHTML = '';
}
var container = document.getElementById('events');
if (filtered.length === 0) {
container.innerHTML = `
<div class="empty-state">
<h3>Нет записей</h3>
<p>Нажмите «Добавить», чтобы создать первую запись</p>
</div>
`;
return;
}
if (isGloves) {
container.innerHTML = `
<div style="overflow-x: auto;">
<table class="gloves-table">
<thead>
<tr>
<th>Количество</th>
<th>Место эксплуатации</th>
<th>Ответственное лицо</th>
<th>Последнее испытание</th>
<th>Следующее испытание</th>
<th>Срок (мес)</th>
<th>Действия</th>
</tr>
</thead>
<tbody>
${filtered.map(function(e) {
return `<tr>
<td>${escapeHtml(e.quantity || '')}</td>
<td>${escapeHtml(e.location || '')}</td>
<td>${escapeHtml(e.responsible || '')}</td>
<td>${e.lastTestDate ? formatDate(e.lastTestDate) : ''}</td>
<td>${e.nextTestDate ? formatDate(e.nextTestDate) : ''}</td>
<td>${e.expiryMonths ? e.expiryMonths + ' мес.' : ''}</td>
<td>
<button class="btn btn-edit" onclick="editEvent(${e.id})">Изменить</button>
<button class="btn btn-delete" onclick="deleteEvent(${e.id})">Удалить</button>
</td>
</tr>`;
}).join('')}
</tbody>
</table>
</div>
`;
} else {
container.innerHTML = filtered.map(function(e) {
return `<div class="event-card">
<div class="event-header">
<div class="event-title">${escapeHtml(e.title)}</div>
<span class="event-status status-${e.status.replace(/ /g, '_')}">${e.status}</span>
</div>
<div class="event-meta">
${e.date ? `<span>📅 ${formatDate(e.date)}</span>` : ''}
${e.time ? `<span>⏰ ${e.time}</span>` : ''}
${e.location ? `<span>📍 ${escapeHtml(e.location)}</span>` : ''}
${e.organizer ? `<span>👤 ${escapeHtml(e.organizer)}</span>` : ''}
</div>
${e.description ? `<div class="event-description">${escapeHtml(e.description)}</div>` : ''}
<div class="event-actions">
<button class="btn btn-edit" onclick="editEvent(${e.id})">Изменить</button>
<button class="btn btn-delete" onclick="deleteEvent(${e.id})">Удалить</button>
</div>
</div>`;
}).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();