// Журнал заявок на ремонт оборудования. // Данные хранятся в localStorage; при первом открытии подставляются исходные записи. var STATUS_ORDER = [ "new", "assigned", "in_progress", "awaiting_parts", "resolved", "cancelled" ]; var STATUS_LABEL = { new: "Новая", assigned: "Назначена", in_progress: "В работе", awaiting_parts: "Ждёт запчасть", resolved: "Завершена", cancelled: "Отменена" }; var STATUS_TONE = { new: "info", assigned: "info", in_progress: "warn", awaiting_parts: "risk", resolved: "ok", cancelled: "muted" }; var SEED = [ { id: "РМ-2104", equipment: "Серверная стойка A-3", place: "ЦОД, 1 этаж, стойка 12", cls: "Срочный", status: "in_progress", created: "2026-09-18", updated: "2026-09-21", resp: "И. Ахметов", desc: "Сбой охлаждения: температура в стойке выше 30 °C, датчики показывают 38 °C. Требуется диагностика блоков кондиционирования." }, { id: "РМ-2103", equipment: "Транслирующая станция «Алматы-4»", place: "ДК-4, уровень 12", cls: "Срочный", status: "awaiting_parts", created: "2026-09-17", updated: "2026-09-20", resp: "С. Оспанов", desc: "Отказ модуля питания. Станция переведена на резервный канал, основной канал выведен из работы." }, { id: "РМ-2102", equipment: "Видеонаблюдение, парковка П-2", place: "Штаб, парковка 2", cls: "Повседневный", status: "new", created: "2026-09-21", updated: "2026-09-21", resp: null, desc: "Камера №7 не передаёт изображение. Блок питания в порядке, сигнал отсутствует." }, { id: "РМ-2101", equipment: "Принтер HP LaserJet M404", place: "БЦ «Тау Самал», кабинет 204", cls: "Повседневный", status: "resolved", created: "2026-09-10", updated: "2026-09-14", resp: "А. Нурланов", desc: "Замятие бумаги. Заменён роликовый узел подачи, тестовая печать выполнена." }, { id: "РМ-2100", equipment: "IP-телефон Cisco 8845", place: "Кабинет 315", cls: "Повседневный", status: "assigned", created: "2026-09-19", updated: "2026-09-21", resp: "М. Тлеубердиева", desc: "Не регистрируется на шлюзе после планового обновления прошивки." }, { id: "РМ-2099", equipment: "Климат-установка DX-140", place: "ЦОД, серверный зал 2", cls: "Срочный", status: "in_progress", created: "2026-09-15", updated: "2026-09-21", resp: "Т. Бекова", desc: "Течь фреонового контура. Выполнена локализация утечки, ожидается дозаправка." }, { id: "РМ-2098", equipment: "Рабочая станция, отдел поддержки", place: "Кабинет 108", cls: "Повседневный", status: "resolved", created: "2026-09-08", updated: "2026-09-12", resp: "М. Тлеубердиева", desc: "Зависания системы при загрузке. Перенесена ОС на новый диск." }, { id: "РМ-2097", equipment: "Патч-панель ОД-2", place: "Шкаф ОД-2, 2 этаж", cls: "Повседневный", status: "awaiting_parts", created: "2026-09-11", updated: "2026-09-18", resp: "И. Ахметов", desc: "Обрыв четырёх портов на секции 3. Заказать патч-корды и портовое исполнение." }, { id: "РМ-2096", equipment: "Система контроля доступа, крыло Б", place: "Здание Б, этаж 1", cls: "Срочный", status: "assigned", created: "2026-09-20", updated: "2026-09-21", resp: "С. Оспанов", desc: "Турникет №2 не считывает RFID-карты. Коммуникация с контроллером не отвечает." }, { id: "РМ-2095", equipment: "Кофемашина Breville", place: "Столовая, 3 этаж", cls: "Повседневный", status: "cancelled", created: "2026-09-05", updated: "2026-09-09", resp: null, desc: "Заявка дублирует РМ-2090, снята с исполнения." }, { id: "РМ-2094", equipment: "Проектор Epson EB-2250", place: "Зал заседаний 4", cls: "Повседневный", status: "resolved", created: "2026-09-02", updated: "2026-09-06", resp: "А. Нурланов", desc: "Потускнение картинки, замена лампы выполнена, яркость в норме." }, { id: "РМ-2093", equipment: "Генератор ГРА-250", place: "Подвал, генераторная", cls: "Срочный", status: "in_progress", created: "2026-09-16", updated: "2026-09-20", resp: "Т. Бекова", desc: "Не запускается при плановом тесте. Проверка системы запуска и топливного контура." }, { id: "РМ-2092", equipment: "Ноутбук Lenovo ThinkPad T14", place: "Кабинет 220", cls: "Повседневный", status: "new", created: "2026-09-22", updated: "2026-09-22", resp: null, desc: "Заряд аккумулятора держит 20 минут, замена батареи требуется." }, { id: "РМ-2091", equipment: "ОПТП-трасса, сегмент Д-3", place: "Линия Д-3, опоры 12–18", cls: "Срочный", status: "awaiting_parts", created: "2026-09-13", updated: "2026-09-19", resp: "С. Оспанов", desc: "Повреждение на сегменте после работ подрядчика. Ждём кабельный запас, согласован поставщик." }, { id: "РМ-2090", equipment: "Кофемашина Breville", place: "Столовая, 3 этаж", cls: "Повседневный", status: "resolved", created: "2026-08-30", updated: "2026-09-04", resp: "М. Тлеубердиева", desc: "Промывка и чистка, замена уплотнителя. Работает в штатном режиме." }, { id: "РМ-2089", equipment: "Коммутатор Cisco 3750", place: "Шкаф ОД-1, порт 2", cls: "Повседневный", status: "assigned", created: "2026-09-18", updated: "2026-09-21", resp: "А. Нурланов", desc: "Порт 2 гаснет при подключении терминала. Заменён кабель, порт в норме." }, { id: "РМ-2088", equipment: "Климат-установка DX-110", place: "ЦОД, серверный зал 1", cls: "Срочный", status: "resolved", created: "2026-08-25", updated: "2026-09-01", resp: "Т. Бекова", desc: "Заменён компрессор, температура в зале стабилизирована." }, { id: "РМ-2087", equipment: "Кресло оператора, рабочее место 7", place: "Оперативный зал, место 7", cls: "Повседневный", status: "new", created: "2026-09-22", updated: "2026-09-22", resp: null, desc: "Не регулируется по высоте." } ]; var LS_KEY = "zhurnal-zayavok-v1"; var state = { reqs: null, filter: "all", search: "", sortDesc: true, selectedId: null }; function $(id) { return document.getElementById(id); } function esc(s) { return String(s) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function pad2(n) { var s = String(n); return s.length < 2 ? "0" + s : s; } function fmtDate(d) { if (!d) return "—"; var parts = String(d).split("-"); if (parts.length !== 3) return String(d); return pad2(parseInt(parts[2], 10)) + "." + pad2(parseInt(parts[1], 10)) + "." + parts[0]; } function nextId() { var max = 2086; for (var i = 0; i < state.reqs.length; i++) { var m = /^РМ-(\d+)$/.exec(state.reqs[i].id || ""); if (m) { var n = parseInt(m[1], 10); if (n > max) max = n; } } return "РМ-" + (max + 1); } function loadReqs() { try { var raw = window.localStorage.getItem(LS_KEY); if (raw) { var arr = JSON.parse(raw); if (Object.prototype.toString.call(arr) === "[object Array]") return arr; } } catch (e) { /* повреждённое хранение — пересоздаём */ } return null; } function saveReqs() { try { window.localStorage.setItem(LS_KEY, JSON.stringify(state.reqs)); } catch (e) { /* приватный режим и т.п. */ } } function cloneSeed() { var out = []; for (var i = 0; i < SEED.length; i++) { var r = {}; for (var k in SEED[i]) r[k] = SEED[i][k]; out.push(r); } return out; } function resetToSeed() { state.reqs = cloneSeed(); saveReqs(); } // Фильтр: статус + поиск, сортировка по дате создания. function visibleReqs() { var q = state.search.trim().toLowerCase(); var out = []; for (var i = 0; i < state.reqs.length; i++) { var r = state.reqs[i]; if (state.filter !== "all" && r.status !== state.filter) continue; if (q) { var hay = (r.id + " " + r.equipment + " " + r.place + " " + (r.desc || "")).toLowerCase(); if (hay.indexOf(q) === -1) continue; } out.push(r); } out.sort(function (a, b) { var da = a.created || "", db = b.created || ""; if (da < db) return state.sortDesc ? 1 : -1; if (da > db) return state.sortDesc ? -1 : 1; return a.id < b.id ? 1 : a.id > b.id ? -1 : 0; }); return out; } function countByStatus() { var m = {}; for (var i = 0; i < STATUS_ORDER.length; i++) m[STATUS_ORDER[i]] = 0; for (var j = 0; j < state.reqs.length; j++) { var s = state.reqs[j].status; if (Object.prototype.hasOwnProperty.call(m, s)) m[s]++; } return m; } function findReq(id) { for (var i = 0; i < state.reqs.length; i++) { if (state.reqs[i].id === id) return state.reqs[i]; } return null; } function pillHtml(status) { var tone = STATUS_TONE[status] || "info"; return '' + esc(STATUS_LABEL[status] || status) + ""; } // ———————————————————————————————— // Рендер // ———————————————————————————————— function renderFilters() { var c = countByStatus(); var host = $("statusFilters"); if (!host) return; var parts = []; parts.push('"); for (var i = 0; i < STATUS_ORDER.length; i++) { var s = STATUS_ORDER[i]; var active = state.filter === s ? "true" : "false"; var label = statusWordForFilter(s); parts.push('"); } host.innerHTML = parts.join(""); } function statusWordForFilter(s) { var short = { new: "Новые", assigned: "Назначенные", in_progress: "В работе", awaiting_parts: "Ждут запчасть", resolved: "Завершённые", cancelled: "Отменённые" }; return short[s] || STATUS_LABEL[s]; } function renderTable() { var body = $("reqBody"); if (!body) return; var rows = visibleReqs(); if (rows.length === 0) { body.innerHTML = ""; var empty = $("emptyState"); if (empty) empty.hidden = false; } else { var empty2 = $("emptyState"); if (empty2) empty2.hidden = true; var html = []; for (var i = 0; i < rows.length; i++) { html.push(rowHtml(rows[i])); } body.innerHTML = html.join(""); } updateCount(); } function rowHtml(r) { var selected = state.selectedId === r.id ? "true" : "false"; var cls = esc(r.cls || "—"); return '
' + (r.desc ? esc(r.desc) : "—") + "
" + '' + '" + "