// Демо-данные: 10 записей с реалистичными именами и датами
const DEMO_DATA = [
{ id: 1, fio: "Алиев А.С.", item: "Каска защитная", issueDate: "2025-01-15", returnDate: "2025-07-15", status: "В носке" },
{ id: 2, fio: "Смирнова Е.В.", item: "Ботинки кожаные", issueDate: "2025-02-01", returnDate: "2025-06-01", status: "Просрочено" },
{ id: 3, fio: "Ибрагимов Б.К.", item: "Костюм х/б", issueDate: "2025-03-10", returnDate: "2025-09-10", status: "В носке" },
{ id: 4, fio: "Петров И.Д.", item: "Перчатки рабочие", issueDate: "2025-01-20", returnDate: "2025-04-20", status: "Просрочено" },
{ id: 5, fio: "Ахметова Г.Т.", item: "Очки защитные", issueDate: "2025-04-05", returnDate: "2025-10-05", status: "В носке" },
{ id: 6, fio: "Козлов М.А.", item: "Респиратор", issueDate: "2025-02-15", returnDate: "2025-05-15", status: "Сдано" },
{ id: 7, fio: "Нурланова А.Е.", item: "Каска защитная", issueDate: "2025-05-01", returnDate: "2025-11-01", status: "В носке" },
{ id: 8, fio: "Васильченко П.П.", item: "Наушники противошумные", issueDate: "2025-03-20", returnDate: "2025-08-20", status: "Просрочено" },
{ id: 9, fio: "Омаров Д.Ж.", item: "Жилет сигнальный", issueDate: "2025-06-01", returnDate: "2025-12-01", status: "В носке" },
{ id: 10, fio: "Тимофеева О.Л.", item: "Сапоги резиновые", issueDate: "2025-01-10", returnDate: "2025-03-10", status: "Сдано" }
];
// Ключи для localStorage
const STORAGE_KEY = "specod_storage_v1";
const LOG_KEY = "specod_log_v1";
// Текущие данные
let items = [];
let logs = [];
let currentFilter = "Все";
// Инициализация при загрузке
document.addEventListener("DOMContentLoaded", () => {
loadData();
renderFilters();
renderTable();
renderLog();
updateCounts();
});
// Загрузка данных из localStorage или демо
function loadData() {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
items = JSON.parse(stored);
} else {
items = [...DEMO_DATA];
saveToStorage();
}
const storedLog = localStorage.getItem(LOG_KEY);
if (storedLog) {
logs = JSON.parse(storedLog);
} else {
logs = [{ type: "add", message: "Система инициализирована с демо-данными", timestamp: new Date().toISOString() }];
saveLogToStorage();
}
}
function saveToStorage() {
localStorage.setItem(STORAGE_KEY, JSON.stringify(items));
}
function saveLogToStorage() {
localStorage.setItem(LOG_KEY, JSON.stringify(logs));
}
// Фильтры
function renderFilters() {
const filters = ["Все", "В носке", "Сдано", "Просрочено"];
const container = document.getElementById("filters");
container.innerHTML = filters.map(f =>
``
).join("");
}
function setFilter(filter) {
currentFilter = filter;
renderFilters();
renderTable();
}
// Таблица
function renderTable() {
const tbody = document.getElementById("table-body");
const search = document.getElementById("search").value.toLowerCase();
let filtered = items.filter(item => {
// Обновляем статус просрочки
item = updateItemStatus(item);
// Фильтр по статусу
if (currentFilter !== "Все" && item.status !== currentFilter) return false;
// Поиск
if (search) {
return item.fio.toLowerCase().includes(search) || item.item.toLowerCase().includes(search);
}
return true;
});
if (filtered.length === 0) {
tbody.innerHTML = `
|
📋
Нет записей для отображения
|
`;
updateCounts();
return;
}
tbody.innerHTML = filtered.map((item, idx) => {
const isOverdue = item.status === "Просрочено";
return `
| ${idx + 1} |
${escapeHtml(item.fio)} |
${escapeHtml(item.item)} |
${formatDate(item.issueDate)} |
${formatDate(item.returnDate)} |
${item.status}
|
|
`;
}).join("");
updateCounts();
}
// Обновление статуса на основе даты
function updateItemStatus(item) {
const today = new Date();
today.setHours(0, 0, 0, 0);
const returnDate = new Date(item.returnDate);
if (item.status !== "Сдано" && returnDate < today) {
item.status = "Просрочено";
}
return item;
}
function getStatusClass(status) {
switch (status) {
case "В носке": return "status-worn";
case "Сдано": return "status-returned";
case "Просрочено": return "status-overdue";
default: return "status-worn";
}
}
// Счётчики
function updateCounts() {
// Пересчитываем статусы перед подсчётом
items = items.map(updateItemStatus);
saveToStorage();
const total = items.length;
const worn = items.filter(i => i.status === "В носке").length;
const returned = items.filter(i => i.status === "Сдано").length;
const overdue = items.filter(i => i.status === "Просрочено").length;
document.getElementById("count-total").textContent = total;
document.getElementById("count-worn").textContent = worn;
document.getElementById("count-returned").textContent = returned;
document.getElementById("count-overdue").textContent = overdue;
}
// Модальное окно
function openModal(isEdit = false) {
document.getElementById("modal").classList.remove("hidden");
document.getElementById("modal-title").textContent = isEdit ? "Редактирование выдачи" : "Новая выдача";
if (!isEdit) {
document.getElementById("form").reset();
document.getElementById("edit-id").value = "";
// Устанавливаем сегодняшнюю дату по умолчанию
document.getElementById("form-issue-date").value = new Date().toISOString().split("T")[0];
}
}
function closeModal() {
document.getElementById("modal").classList.add("hidden");
}
// Сохранение (добавление/редактирование)
function saveItem(event) {
event.preventDefault();
const id = document.getElementById("edit-id").value;
const fio = document.getElementById("form-fio").value.trim();
const item = document.getElementById("form-item").value.trim();
const issueDate = document.getElementById("form-issue-date").value;
const returnDate = document.getElementById("form-return-date").value;
if (id) {
// Редактирование
const idx = items.findIndex(i => i.id == id);
if (idx !== -1) {
const oldItem = { ...items[idx] };
items[idx] = { ...items[idx], fio, item, issueDate, returnDate };
logs.unshift({
type: "edit",
message: `Изменено: ${oldItem.fio} — ${oldItem.item}`,
timestamp: new Date().toISOString()
});
}
} else {
// Добавление
const newId = Date.now();
let status = "В носке";
const today = new Date();
today.setHours(0, 0, 0, 0);
const retDate = new Date(returnDate);
if (retDate < today) status = "Просрочено";
items.unshift({ id: newId, fio, item, issueDate, returnDate, status });
logs.unshift({
type: "add",
message: `Добавлено: ${fio} — ${item}`,
timestamp: new Date().toISOString()
});
}
saveToStorage();
saveLogToStorage();
closeModal();
renderTable();
renderLog();
}
// Редактирование
function editItem(id) {
const item = items.find(i => i.id === id);
if (!item) return;
document.getElementById("edit-id").value = item.id;
document.getElementById("form-fio").value = item.fio;
document.getElementById("form-item").value = item.item;
document.getElementById("form-issue-date").value = item.issueDate;
document.getElementById("form-return-date").value = item.returnDate;
openModal(true);
}
// Удаление
function deleteItem(id) {
const item = items.find(i => i.id === id);
if (!item) return;
if (confirm(`Вы уверены, что хотите удалить запись:\n${item.fio} — ${item.item}?`)) {
items = items.filter(i => i.id !== id);
logs.unshift({
type: "delete",
message: `Удалено: ${item.fio} — ${item.item}`,
timestamp: new Date().toISOString()
});
saveToStorage();
saveLogToStorage();
renderTable();
renderLog();
}
}
// Журнал изменений
function renderLog() {
const container = document.getElementById("log-container");
if (logs.length === 0) {
container.innerHTML = 'История пуста
';
return;
}
container.innerHTML = logs.map(log => {
const date = new Date(log.timestamp);
const dateStr = date.toLocaleDateString("ru-RU") + " " + date.toLocaleTimeString("ru-RU", { hour: "2-digit", minute: "2-digit" });
return `
${log.message}
(${dateStr})
`;
}).join("");
}
// Выгрузка в Excel (CSV с BOM)
function exportToExcel() {
const head = ["№", "ФИО", "Наименование", "Дата выдачи", "Дата возврата", "Статус"];
const rows = items.map((item, idx) => [
idx + 1,
item.fio,
item.item,
formatDate(item.issueDate),
formatDate(item.returnDate),
item.status
]);
const csvContent = "\uFEFF" + [
head.join(";"),
...rows.map(r => r.map(v => `"${String(v).replace(/"/g, '""')}"`).join(";"))
].join("\n");
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = `zhurnal_${new Date().toISOString().slice(0, 10)}.csv`;
link.click();
}
// Утилиты
function formatDate(dateStr) {
if (!dateStr) return "";
const [year, month, day] = dateStr.split("-");
return `${day}.${month}.${year}`;
}
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
// Закрытие модального окна по клику вне
document.getElementById("modal").addEventListener("click", (e) => {
if (e.target.id === "modal") closeModal();
});