/* Учёт заявок на пропуск — демо: хранение в localStorage. Демо-набор отдельно (key "kt_pass_demo_seed") от добавленных пользователем записей (key "kt_pass_requests") — показываем как есть, без смешивания и подмены. */ var STATUS = { new: { label: "Новая", pill: "info" }, processing: { label: "В обработке", pill: "warn" }, approved: { label: "Одобрена", pill: "ok" }, rejected: { label: "Отклонена", pill: "risk" } }; var STATUS_ORDER = ["new", "processing", "approved", "rejected"]; var DEMO = [ { id: 1042, name: "Ахметов Ерлан Сергеевич", purpose: "Въезд на технологическую территорию ЦОД Алматы", date: "2026-09-18" }, { id: 1041, name: "Бекеева Алия Нурлановна", purpose: "Обучение: работа с ОДЗ, учебный класс B", date: "2026-09-17" }, { id: 1040, name: "Сериков Данияр Олегович", purpose: "Работа подрядчика, зона монтажа №3", date: "2026-09-16" }, { id: 1039, name: "Махамбетова Гульнара", purpose: "Ревизия склада СИЗ", date: "2026-09-15" }, { id: 1038, name: "Токтаров Нурлан", purpose: "Въезд на территорию офиса №2", date: "2026-09-15" }, { id: 1037, name: "Абдрахманова Семина", purpose: "Курсы ИБ, 2 день", date: "2026-09-12" }, { id: 1036, name: "Куанышбаев Асхат", purpose: "Сопровождение инспекции", date: "2026-09-12" }, { id: 1035, name: "Омарова Жания", purpose: "Подача документов в отдел кадров", date: "2026-09-10" }, { id: 1034, name: "Нурланов Серик", purpose: "Доставка оборудования, грузовой въезд", date: "2026-09-05" } ]; var DEMO_STATUS = { 1042: "new", 1041: "new", 1040: "processing", 1039: "processing", 1038: "approved", 1037: "approved", 1036: "rejected", 1035: "rejected", 1034: "approved" }; /** Демо-набор: статусы приложены и зафиксированы, перезаписывать нельзя. */ function demoItems() { return DEMO.map(function (d) { return { id: d.id, name: d.name, purpose: d.purpose, date: d.date, status: DEMO_STATUS[d.id], demo: true }; }); } /** Записи, добавленные пользователем в этой сессии браузера. */ function loadUser() { try { var raw = localStorage.getItem("kt_pass_requests"); var arr = raw ? JSON.parse(raw) : []; return Array.isArray(arr) ? arr.filter(function (r) { return isReq(r); }) : []; } catch (e) { return []; } } function saveUser(arr) { try { localStorage.setItem("kt_pass_requests", JSON.stringify(arr)); } catch (e) { /* localStorage недоступен — работаем только в памяти */ } } function isReq(r) { return r && r.name && r.purpose && r.date && STATUS[r.status] != null && r.id > 0; } function nextId(user) { var m = 0; user.forEach(function (r) { if (r.id > m) m = r.id; }); return 10000 + user.length + 1 + (m >= 10000 ? m - 9999 : 0); } var state = { filter: "all", user: loadUser() }; var $form = document.getElementById("request-form"); var $kpiStrip = document.getElementById("kpi-strip"); var $tableWrap = document.getElementById("table-wrap"); var $tbody = document.getElementById("list-body"); var $empty = document.getElementById("list-empty"); var $emptyHint = document.getElementById("list-empty-hint"); var $total = document.getElementById("list-total"); var $toastStack = document.getElementById("toast-stack"); function esc(s) { return String(s).replace(/[&<>"']/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]; }); } function pad(n) { return String(n).length < 2 ? "0" + n : String(n); } function fmtDate(iso) { if (!iso) return "—"; var parts = iso.split("-"); if (parts.length !== 3) return iso; return parts[2] + "." + parts[1] + "." + parts[0]; } function statusInfo(s) { return STATUS[s] || STATUS.new; } function allItems() { var merged = state.user.map(function (r) { return { id: r.id, name: r.name, purpose: r.purpose, date: r.date, status: r.status, demo: false }; }).concat(demoItems()); merged.sort(function (a, b) { return b.id - a.id; }); return merged; } function visible() { var all = allItems(); if (state.filter === "all") return all; return all.filter(function (r) { return r.status === state.filter; }); } function renderKPI() { var all = allItems(); var counts = { all: all.length }; STATUS_ORDER.forEach(function (k) { counts[k] = 0; }); all.forEach(function (r) { counts[r.status] = (counts[r.status] || 0) + 1; }); function kpi(id, value, label) { var active = state.filter === id ? "true" : "false"; return '
' + '' + value + "" + '' + label + "" + "
"; } var KPIS = [ ["all", "Всего"], ["new", "Новые"], ["processing", "В обработке"], ["approved", "Одобрено"], ["rejected", "Отклонено"] ]; var parts = KPIS.map(function (k) { return kpi(k[0], counts[k[0]], k[1]); }); $kpiStrip.innerHTML = parts.join(""); } function plural(n, one, few, many) { var n10 = n % 10, n100 = n % 100; if (n10 === 1 && n100 !== 11) return one; if (n10 >= 2 && n10 <= 4 && (n100 < 12 || n100 > 14)) return few; return many; } function renderList() { var list = visible(); var total = allItems().length; $total.textContent = total + " " + plural(total, "заявка", "заявки", "заявок"); if (list.length === 0) { $tbody.innerHTML = ""; $tableWrap.hidden = true; $empty.hidden = false; $emptyHint.textContent = state.filter === "all" ? "Заявок пока нет — создайте первую в форме выше." : "Под выбранный статус заявки не нашлись."; return; } $tableWrap.hidden = false; $empty.hidden = true; var rows = list.map(function (r) { var st = statusInfo(r.status); var actions = ""; if (!r.demo) { if (r.status === "new") { actions += btnAction(r.id, "processing", "check", "В обработку"); } else if (r.status === "approved") { actions += btnAction(r.id, "new", "refresh", "Сменить статус"); } actions += btnAction(r.id, "delete", "trash", "Удалить", "ghost"); } return "" + '' + r.id + "" + "" + esc(r.name) + "" + '' + esc(r.purpose) + "" + '' + fmtDate(r.date) + "" + '' + st.label + "" + '' + (actions || "—") + "" + ""; }); $tbody.innerHTML = rows.join(""); } function btnAction(id, target, icon, label, variant) { return '"; } function render() { renderKPI(); renderList(); } function toast(text, tone) { var el = document.createElement("div"); el.className = "kt-ai-toast"; if (tone) el.setAttribute("data-tone", tone); el.textContent = text; $toastStack.appendChild(el); setTimeout(function () { el.remove(); }, 4000); } function setInvalid(input, bad) { input.setAttribute("data-invalid", bad ? "true" : "false"); var field = input.closest(".kt-ai-field"); if (field) { var err = field.querySelector(".error"); if (err) err.hidden = !bad; field.setAttribute("data-invalid", bad ? "true" : "false"); } } function setFilter(s) { state.filter = s; document.querySelectorAll(".kt-ai-filter-chip[data-status]").forEach(function (c) { c.setAttribute("data-active", c.getAttribute("data-status") === s ? "true" : "false"); }); renderKPI(); renderList(); } document.addEventListener("click", function (e) { var chip = e.target.closest(".kt-ai-filter-chip[data-status]"); if (chip) { setFilter(chip.getAttribute("data-status")); return; } var kpi = e.target.closest(".kt-ai-kpi[data-status]"); if (kpi) { setFilter(kpi.getAttribute("data-status")); return; } var act = e.target.closest(".kt-ai-btn[data-action]"); if (act) { var id = Number(act.getAttribute("data-id")); var target = act.getAttribute("data-action"); state.user = state.user.filter(function (r) { if (r.id !== id) return true; if (target === "delete") { toast("Заявка №" + id + " удалена"); return false; } r.status = target; toast( target === "processing" ? "Заявка №" + id + " перенесена в обработку" : target === "approved" ? "Заявка №" + id + " одобрена" : "Статус заявки №" + id + ": " + statusInfo(target).label ); return true; }); saveUser(state.user); render(); } }); document.getElementById("btn-reset").addEventListener("click", function () { setFilter("all"); }); ["f-name", "f-purpose", "f-date"].forEach(function (i) { document.getElementById(i).addEventListener("input", function () { setInvalid(this, false); }); }); $form.addEventListener("submit", function (e) { e.preventDefault(); var f = $form; var name = f.elements["f-name"].value.trim(); var purpose = f.elements["f-purpose"].value.trim(); var date = f.elements["f-date"].value; var ok = true; if (!name) { setInvalid(f.elements["f-name"], true); ok = false; } if (!purpose) { setInvalid(f.elements["f-purpose"], true); ok = false; } if (!date) { setInvalid(f.elements["f-date"], true); ok = false; } if (!ok) { toast("Проверьте поля формы", "warn"); return; } var item = { id: nextId(state.user), name: name, purpose: purpose, date: date, status: "new" }; state.user.push(item); saveUser(state.user); f.reset(); render(); toast("Заявка №" + item.id + " создана, статус: Новая"); $form.scrollIntoView({ behavior: "smooth", block: "nearest" }); }); (function init() { var today = new Date(); document.getElementById("f-date").valueAsDate = today; render(); })();