samruk-ai-agent/index.html

278 lines
40 KiB
HTML
Raw 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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>План ПБ 2026 — Казахтелеком</title>
<style>
:root{--b:#0F1218;--c:#00E5FF;--w:#fff;--g5:#5B6573;--g1:#F2F4F7;--g2:#E5E7EB;--gn:#10B981;--rd:#EF4444;--am:#F59E0B}
*{box-sizing:border-box;margin:0;padding:0}
body{font:14px/1.4 Arial,sans-serif;color:var(--b);background:var(--g1)}
input,select,textarea,button{font:inherit;outline:none}
.btn{background:var(--c);color:var(--b);padding:10px 20px;border-radius:8px;font-weight:700;font-size:14px;border:none;cursor:pointer}.btn:hover{opacity:.85}
.btn-sm{padding:6px 12px;font-size:12px}.btn-red{background:var(--rd);color:#fff}.btn-gn{background:var(--gn);color:#fff}
#login{display:flex;align-items:center;justify-content:center;min-height:100vh;background:var(--b)}
#login>div{background:var(--w);border-radius:16px;padding:40px 36px;width:400px;max-width:90vw;text-align:center}
#login h1{font-size:22px;font-weight:800;margin-bottom:4px}#login h1 span{color:var(--c)}
#login p{color:var(--g5);font-size:13px;margin-bottom:28px}
#login input{display:block;width:100%;padding:12px 14px;border:1px solid var(--g2);border-radius:8px;font-size:14px;margin-bottom:14px}
#login .err{color:var(--rd);font-size:12px;margin-bottom:10px;display:none}
#app{display:none;max-width:1200px;margin:0 auto;padding:16px}
.top{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:2px solid var(--g2);margin-bottom:16px}
.top b{font-size:18px}.top b span{color:var(--c)}
.top .r{display:flex;align-items:center;gap:12px;font-size:13px;color:var(--g5)}
.tabs{display:flex;gap:4px;margin-bottom:16px}
.tab{padding:10px 20px;border:none;background:var(--w);cursor:pointer;font-size:14px;font-weight:600;color:var(--g5);border-radius:8px 8px 0 0}.tab.on{color:var(--b);border-bottom:3px solid var(--c)}
.pg{display:none}.pg.on{display:block}
.card{background:var(--w);border-radius:12px;padding:20px;margin-bottom:14px;border:1px solid var(--g2)}
.card h3{font-size:16px;margin-bottom:8px}
.row{display:flex;gap:12px;flex-wrap:wrap;margin-bottom:12px}
.stat{background:var(--w);border-radius:10px;padding:16px 20px;border:1px solid var(--g2);min-width:120px;flex:1;text-align:center}
.stat .n{font-size:26px;font-weight:800}.stat .l{font-size:12px;color:var(--g5)}.stat.r .n{color:var(--rd)}.stat.g .n{color:var(--gn)}.stat.a .n{color:var(--am)}
table{width:100%;border-collapse:collapse}
th,td{padding:8px 12px;text-align:left;font-size:13px}
th{font-weight:600;color:var(--g5);font-size:11px;text-transform:uppercase;border-bottom:2px solid var(--g2);cursor:pointer}th:hover{color:var(--b)}
td{border-bottom:1px solid var(--g2)}
tr.warn td{background:#FFFDF5}tr.late td{background:#FFF5F5}
.badge{display:inline-block;padding:3px 8px;border-radius:100px;font-size:11px;font-weight:700}
.badge.g{background:#D1FAE5;color:#065F46}.badge.a{background:#FEF3C7;color:#92400E}.badge.r{background:#FEE2E2;color:#991B1B}.badge.b{background:#DBEAFE;color:#1E40AF}.badge.w{background:#eee;color:#666}
.fr{display:flex;gap:8px;margin-bottom:10px;flex-wrap:wrap;align-items:center}
.fr input,.fr select{padding:8px 12px;border:1px solid var(--g2);border-radius:6px;font-size:13px;background:var(--w)}
.fr input{min-width:200px}
.modal-o{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:99;display:none;align-items:center;justify-content:center}.modal-o.on{display:flex}
.modal{background:var(--w);border-radius:14px;max-width:700px;width:94vw;max-height:90vh;overflow-y:auto;padding:28px}
.modal .x{float:right;border:none;background:none;font-size:24px;cursor:pointer;color:var(--g5)}
.fm-title{font-size:18px;font-weight:800;margin-bottom:6px;padding-right:28px}
.fm label{display:block;font-size:12px;font-weight:600;color:var(--g5);margin-bottom:3px;margin-top:10px}
.fm input,.fm select,.fm textarea{width:100%;padding:8px 12px;border:1px solid var(--g2);border-radius:6px;font-size:13px;margin-bottom:6px}
.fm textarea{min-height:60px;resize:vertical}
.fm .rdonly{background:var(--g1);color:var(--g5)}
.meta{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:8px;font-size:12px;color:var(--g5)}.meta strong{display:block;color:var(--b);font-size:13px}
.mt{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:10px}.mt span{padding:4px 10px;border:1px solid var(--g2);border-radius:100px;font-size:11px;font-weight:600;cursor:pointer}.mt span.on{background:var(--c);color:var(--b)}.mt span:hover{border-color:var(--c)}
.si{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--g1);border-radius:6px;margin-bottom:4px;font-size:12px}.si .n{font-weight:700;color:var(--c);font-size:14px;min-width:18px}
.fl{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--g1);border-radius:6px;margin-bottom:3px;font-size:12px}.fl .nm{font-weight:600;cursor:pointer}.fl .nm:hover{color:var(--c)}.fl .sz{font-size:10px;color:var(--g5);white-space:nowrap}.fl .tp{font-size:9px;background:var(--g2);padding:1px 4px;border-radius:3px;color:var(--g5)}
.up{border:2px dashed var(--g2);border-radius:8px;padding:12px;margin-top:6px;text-align:center}
.up p{font-size:12px;color:var(--g5);margin-bottom:8px}
.up input[type=file]{font-size:12px}
.up .types{font-size:10px;color:var(--g5);margin-top:6px}
.ai{background:#E8FCFF;border-radius:6px;padding:10px;margin:10px 0;font-size:12px}
.hi{font-size:11px;color:var(--g5);padding:2px 0}.hi .d{display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--c);margin-right:4px;vertical-align:middle}
@media(max-width:600px){#app{padding:8px}.row{flex-direction:column}.stat{min-width:auto}.meta{grid-template-columns:1fr}}
</style>
</head>
<body>
<div id="login">
<div>
<h1><span>План ПБ</span> 2026</h1>
<p>АО «Казахтелеком»</p>
<input id="lem" placeholder="curator@telecom.kz">
<input id="lpw" type="password" placeholder="Пароль (любой)">
<p class="err" id="lerr">Неверная почта</p>
<button class="btn" style="width:100%" onclick="doLogin()">Войти</button>
</div>
</div>
<div id="app">
<div class="top">
<b><span>План ПБ</span> 2026</b>
<div class="r"><span id="ul"></span> <button class="btn btn-sm btn-red" onclick="doLogout()">Выйти</button></div>
</div>
<div class="tabs">
<button class="tab on" data-pg="ev">📋 Мероприятия</button>
<button class="tab" data-pg="an">📊 Аналитика</button>
<button class="tab" data-pg="rp">📥 Отчёты</button>
</div>
<div class="pg on" id="pg-ev"></div>
<div class="pg" id="pg-an"></div>
<div class="pg" id="pg-rp"></div>
</div>
<div class="modal-o" id="mo"><div class="modal fm" id="mc"></div></div>
<script>
var sec=["I. Люди","II. Оборудование","III. Аварии и ЧС","IV. Информ. работа","V. ИИ"];
var br=["Дирекция ПБ","Дивизион «Сеть»","Корпоративный бизнес","Розничный бизнес","Сервисная фабрика","Телеком Комплект","Корпоративный университет","Управление проектами","Цифровой бизнес"];
var reg=["Центральный","Алматинский","Южный","Северный","Восточный","Западный"];
var st={wait:"Не начато",warn:"В процессе",late:"Просрочено",done:"Исполнено"};
var ms=["2026-01","2026-02","2026-03","2026-04","2026-05","2026-06","2026-07","2026-08","2026-09","2026-10","2026-11","2026-12"];
var mn=["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"];
function M(i){return mn[parseInt(ms[i].split("-")[1])-1]+" "+ms[i].split("-")[0]}
function esc(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
function sb(s){var m={done:"g",warn:"a",late:"r",wait:"w"};return'<span class="badge '+m[s]+'">'+st[s]+'</span>'}
var U={"curator@telecom.kz":{n:"Куратор",b:0,r:"cur"},"dpp@telecom.kz":{n:"Директор ДПБ",b:0,r:"br"},"ahmetov@telecom.kz":{n:"Ахметов К.Т.",b:6,r:"br"},"serikov@telecom.kz":{n:"Сериков А.М.",b:1,r:"br"},"nurlanov@telecom.kz":{n:"Нурланов Д.С.",b:8,r:"br"},"aliev@telecom.kz":{n:"Алиев Г.С.",b:4,r:"br"},"tulegenov@telecom.kz":{n:"Тулегенов Е.А.",b:2,r:"br"},"saparov@telecom.kz":{n:"Сапаров А.Д.",b:3,r:"br"},"maratov@telecom.kz":{n:"Маратов Ж.К.",b:5,r:"br"},"iskakov@telecom.kz":{n:"Искаков Р.Н.",b:7,r:"br"}};
var cu=null,cm=5,cr=0,esi=-1,ex={},sc2=null,sd2=1;
function getMD(id,ri,si){ri=ri||0;var k=si>=0?"sf_"+id+"_s"+si+"_r"+ri:"sf_"+id+"_r"+ri;var r=localStorage.getItem(k);return r?JSON.parse(r):{}}
function setMD(id,o,ri,si){ri=ri||0;var k=si>=0?"sf_"+id+"_s"+si+"_r"+ri:"sf_"+id+"_r"+ri;localStorage.setItem(k,JSON.stringify(o))}
function gsc(id){var r=localStorage.getItem("ss_"+id);return r?JSON.parse(r):[]}
function ssc(id,a){localStorage.setItem("ss_"+id,JSON.stringify(a))}
// ===== ALL 35 EVENTS =====
var ev=null;
function le(){var s=localStorage.getItem("se2");if(s){try{ev=JSON.parse(s);return}catch(e){}}ev=ge();se()}
function se(){localStorage.setItem("se2",JSON.stringify(ev||[]))}
function ge(){return [
{i:1,s:0,b:6,st:"warn",p:45,d:"31.12.2026",dn:"—",dnm:"Протоколы / Ведомость",r:"Генеральный директор КУ",t:"Обучение и повышение квалификации (VR, AR, симуляторы)",ai:"Охвачено 45% персонала. VR-тренажёры развёрнуты в 3 филиалах.",h:["15.01 — Создано","01.03 — Запущено"]},
{i:2,s:0,b:0,st:"done",p:100,d:"31.03.2026",dn:"28.03.2026",dnm:"Отчёт / ВНД",r:"Директор ДПБ, ДИТ",t:"Анализ и пересмотр ВНД согласно Стратегии ПБ",ai:"Завершён в срок.",h:["10.01 — Создано","28.03 — Утверждён"]},
{i:3,s:0,b:0,st:"warn",p:50,d:"31.12.2026",dn:"—",dnm:"Протоколы",r:"Главный админ. директор, Директор ДПБ",t:"Тематические совещания по вопросам ПБ",ai:"2 квартальных совещания.",h:["10.01 — Создано"],sub:[{l:"a",t:"С филиалами/ДАО, не менее 1 раза в квартал"},{l:"b",t:"Со структурными подразделениями, ежемесячно"},{l:"c",t:"С подрядными организациями, ежеквартально"}]},
{i:4,s:0,b:6,st:"warn",p:55,d:"31.12.2026",dn:"—",dnm:"Отчёты / Тесты",r:"Ген. директора филиалов",t:"Проверка знаний в формате тестирования",ai:"82% средний результат.",h:["01.02 — Создано"]},
{i:5,s:0,b:0,st:"done",p:100,d:"31.03.2026",dn:"25.03.2026",dnm:"Информация",r:"Директор ДПБ",t:"Нематериальное поощрение филиалов",ai:"Положение утверждено.",h:["25.03 — Утверждено"]},
{i:6,s:0,b:6,st:"warn",p:60,d:"30.06.2026",dn:"—",dnm:"ВНД по тренерам",r:"Ген. директор КУ, Упр. директор по персоналу",t:"Разработка ВНД по внутренним тренерам",ai:"Проект на финальном согласовании.",h:["01.03 — Создано"]},
{i:7,s:0,b:1,st:"warn",p:40,d:"31.12.2026",dn:"—",dnm:"Материалы обмена опытом",r:"Директор ДПБ",t:"Обмен опытом в области ПБ",ai:"1 выезд на KEGOC.",h:["15.02 — Создано"],sub:[{l:"a",t:"Обмен опытом на площадке Комитета HSE"},{l:"b",t:"Обмен опытом с иностранными компаниями"}]},
{i:8,s:0,b:4,st:"wait",p:15,d:"30.09.2026",dn:"—",dnm:"Акт / Well-being / Скрининг",r:"Директор ДПБ, Упр. директор по персоналу",t:"Анализ эффективности охраны здоровья",ai:"Медосмотры — Q3.",h:["01.04 — Создано"],sub:[{l:"a",t:"100% прохождение медосмотров"},{l:"b",t:"Неделя благополучия"},{l:"c",t:"Медицинский скрининг"},{l:"d",t:"Алгоритм учёта микротравм"}]},
{i:9,s:0,b:6,st:"wait",p:20,d:"31.12.2026",dn:"—",dnm:"Результаты конкурсов",r:"Директор ДПБ",t:"Участие в конкурсах профмастерства по ПБ",ai:"Определены 2 конкурса.",h:["01.05 — Создано"]},
{i:10,s:1,b:1,st:"warn",p:55,d:"31.12.2026",dn:"—",dnm:"Аналитическая справка",r:"Ген. директор ОДС, СФ, ДУП, ДИТ",t:"Техническое перевооружение изношенного оборудования",ai:"Заменено 55%.",h:["01.01 — Переходящее"]},
{i:11,s:1,b:1,st:"warn",p:70,d:"30.06.2026",dn:"—",dnm:"Процедура / Фотоотчёт",r:"Директор ДПБ",t:"Пересмотр нарядно-допускной системы",ai:"Пилот запущен.",h:["01.02 — Создано"]},
{i:12,s:1,b:8,st:"wait",p:8,d:"30.09.2026",dn:"—",dnm:"Справка / Фотоотчёт",r:"Ген. директора филиалов",t:"Цифровая маркировка техустройств (QR-коды)",ai:"ТЭО в разработке.",h:["01.05 — Создано"]},
{i:13,s:1,b:0,st:"warn",p:50,d:"31.12.2026",dn:"—",dnm:"Акты / График",r:"Директор ДПБ",t:"Проверки по проверочным листам БиОТ",ai:"Q1 завершены.",h:["01.01 — Создано"]},
{i:14,s:1,b:0,st:"warn",p:40,d:"31.12.2026",dn:"—",dnm:"Письмо",r:"Директор ДПБ",t:"Участие в перекрёстных аудитах ПК",ai:"Назначены 4 аудитора.",h:["15.01 — Аудиторы"]},
{i:15,s:1,b:0,st:"warn",p:48,d:"31.12.2026",dn:"—",dnm:"Справка / Журнал",r:"Директор ДПБ",t:"Проактивные инструменты: аудиты, Near Miss",ai:"147 Near Miss.",h:["01.01 — Создано"]},
{i:16,s:1,b:1,st:"done",p:85,d:"31.12.2026",dn:"—",dnm:"План-график / Акты",r:"Ген. директора филиалов",t:"Управление подрядными организациями",ai:"Q1 — 12 подрядчиков.",h:["15.01 — План"],sub:[{l:"a",t:"Аудит подрядчиков по чек-листу Фонда"},{l:"b",t:"Стартовые совещания с подрядчиками"}]},
{i:17,s:1,b:0,st:"warn",p:35,d:"31.12.2026",dn:"—",dnm:"Отчёты / Фотоотчёт",r:"Главный админ. директор, Директор ДПБ",t:"Контроль состояния ПБ на объектах",ai:"CEO-1: 2 филиала.",h:["01.02 — Создано"],sub:[{l:"a",t:"CEO-1 лично проверять филиал 1 раз в квартал"},{l:"b",t:"Первые руководители — внутренний контроль"}]},
{i:18,s:1,b:1,st:"done",p:90,d:"31.12.2026",dn:"—",dnm:"Ежемесячный отчёт",r:"Ген. директора филиалов, Директор ДПБ",t:"Контроль транспортной безопасности",ai:"34 нарушения. Тренд — снижение.",h:["01.01 — Создано"]},
{i:19,s:2,b:1,st:"warn",p:30,d:"31.12.2026",dn:"—",dnm:"Акты тренировок",r:"Упр. директор по безопасности",t:"Учебные тревоги и тренировки",ai:"1 учение. Пожарные: 1 из 2.",h:["01.02 — Создано"],sub:[{l:"a",t:"Одна учебная тревога по ликвидации аварии"},{l:"b",t:"Две тренировки по тушению пожара"},{l:"c",t:"Одно занятие по первой помощи"}]},
{i:20,s:2,b:0,st:"warn",p:65,d:"30.06.2026",dn:"—",dnm:"Приказ CMS / Акты штабов",r:"Упр. директор по безопасности",t:"Реагирование на ЧС: Crisis Management System",ai:"CMS внедрена.",h:["01.03 — Создано"],sub:[{l:"a",t:"Внедрить Crisis Management System"},{l:"b",t:"Обучение по действиям в ЧС"},{l:"c",t:"Два заседания штабов"}]},
{i:21,s:3,b:0,st:"done",p:100,d:"31.12.2026",dn:"15.02.2026",dnm:"Публикация",r:"Директор ДПБ, Пресс-секретарь",t:"Обращение Председателя Правления о ПБ",ai:"Опубликовано.",h:["15.02 — Опубликовано"]},
{i:22,s:3,b:0,st:"wait",p:15,d:"31.12.2026",dn:"—",dnm:"Протоколы",r:"Директор ДПБ, Департамент коммуникаций",t:"Стратсессии/Форумы и семинары для подрядчиков",ai:"Форум — октябрь.",h:["01.05 — Создано"],sub:[{l:"a",t:"Стратсессии/Форумы для первых руководителей"},{l:"b",t:"Семинары для подрядных организаций"}]},
{i:23,s:3,b:6,st:"wait",p:10,d:"30.09.2026",dn:"—",dnm:"Протокол Олимпиады",r:"Директор ДПБ",t:"Олимпиада по ПБ среди специалистов",ai:"Положение на согласовании.",h:["01.05 — Создано"]},
{i:24,s:3,b:0,st:"done",p:92,d:"31.12.2026",dn:"—",dnm:"Бюллетени",r:"Директор ДПБ",t:"Ознакомление с обстоятельствами НС",ai:"3 бюллетеня, 92%.",h:["01.01 — Создано"]},
{i:25,s:3,b:6,st:"warn",p:40,d:"31.12.2026",dn:"—",dnm:"Публикации / Материалы",r:"Упр. директор по персоналу, Директор ДПБ",t:"Молодежные проектные инициативы",ai:"2 истории в SK News.",h:["01.02 — Создано"],sub:[{l:"a",t:"Публикация историй в SK News"},{l:"b",t:"Посещение мест НС 2022-2025"},{l:"c",t:"Молодые специалисты в аудитах"},{l:"d",t:"Онлайн-семинары/эфиры"}]},
{i:26,s:3,b:2,st:"warn",p:50,d:"31.12.2026",dn:"—",dnm:"Видео / Постеры",r:"Директор ДПБ, Департамент коммуникаций",t:"Наглядная агитация по ПБ",ai:"2 видеоролика снято.",h:["01.02 — Создано"],sub:[{l:"a",t:"Видеоролики с участием работников"},{l:"b",t:"Серия «Безопасность будущего»"},{l:"c",t:"Подкаст с трудовыми династиями"},{l:"d",t:"Постеры, брошюры, рассылки"}]},
{i:27,s:3,b:3,st:"warn",p:30,d:"31.12.2026",dn:"—",dnm:"Фотофиксация",r:"Директор ДПБ",t:"Встречи с получившими производственные травмы",ai:"1 встреча проведена.",h:["01.03 — Создано"]},
{i:28,s:3,b:0,st:"warn",p:25,d:"31.12.2026",dn:"—",dnm:"Письма / Пресс-релизы",r:"Директор ДПБ, Департамент коммуникаций",t:"Пропаганда безопасности через семейные ценности",ai:"5 писем семьям.",h:["01.04 — Создано"],sub:[{l:"a",t:"Письма членам семьи отличившихся"},{l:"b",t:"Семейные дни охраны труда"},{l:"c",t:"Конкурс рисунков «Спецодежда будущего!»"}]},
{i:29,s:3,b:6,st:"late",p:40,d:"30.06.2026",dn:"—",dnm:"Сборник практик",r:"Директор ДПБ",t:"Корпоративный сборник лучших практик по ПБ",ai:"Риск срыва Q2.",h:["01.03 — Создано","01.06 — Эскалация"]},
{i:30,s:3,b:7,st:"warn",p:60,d:"31.12.2026",dn:"—",dnm:"Предложения / План",r:"Директор ДПБ",t:"Сбор предложений по цифровым решениям",ai:"18 предложений.",h:["01.01 — Создано"]},
{i:31,s:3,b:0,st:"warn",p:75,d:"30.06.2026",dn:"—",dnm:"Видеообзор",r:"Директор ДПБ",t:"Видеообзор кейсов происшествий в ПК",ai:"Монтаж 75%.",h:["01.03 — Создано"]},
{i:32,s:4,b:8,st:"warn",p:70,d:"30.06.2026",dn:"—",dnm:"Справка / Скриншоты",r:"Директор ДПБ",t:"Чат-бот ИИ-ассистент по ПБ",ai:"Чат-бот тестируется.",h:["01.02 — Создано"]},
{i:33,s:4,b:8,st:"wait",p:15,d:"31.12.2026",dn:"—",dnm:"Справка / Скриншоты",r:"Директор ДПБ",t:"Система анализа и предупреждения НС",ai:"ТЗ согласовывается.",h:["01.04 — Создано"]},
{i:34,s:4,b:8,st:"wait",p:10,d:"31.12.2026",dn:"—",dnm:"Справка / Скриншоты",r:"Директор ДПБ",t:"Электронный HSE паспорт работника",ai:"Концепция утверждена.",h:["01.05 — Создано"]},
{i:35,s:4,b:5,st:"wait",p:8,d:"31.12.2026",dn:"—",dnm:"Справка / Скриншоты",r:"Директор ДПБ",t:"Электронные наряды-допуски",ai:"Предпроект.",h:["01.05 — Создано"]}
];}
// Normalize field names after load
function ne(){ev.forEach(function(e){if(!e.id&&e.i)e.id=e.i;if(!e.s&&e.st)e.s=e.st;if(!e.due&&e.d)e.due=e.d;if(!e.done&&e.dn)e.done=e.dn;if(!e.dname&&e.dnm)e.dname=e.dnm;delete e.i;delete e.st;delete e.d;delete e.dn;delete e.dnm})}
function doLogin(){var e=document.getElementById("lem").value.trim().toLowerCase();if(U[e]){cu={em:e,n:U[e].n,b:U[e].b,r:U[e].r};localStorage.setItem("su",JSON.stringify(cu));show()}else document.getElementById("lerr").style.display="block"}
function doLogout(){localStorage.removeItem("su");cu=null;document.getElementById("login").style.display="flex";document.getElementById("app").style.display="none"}
function show(){document.getElementById("login").style.display="none";document.getElementById("app").style.display="block";document.getElementById("ul").innerHTML="<b>"+cu.n+"</b> · "+(cu.r==="cur"?"Все":br[cu.b]);switchPg("ev")}
function switchPg(n){document.querySelectorAll(".tab").forEach(function(t){t.classList.remove("on")});document.querySelector('[data-pg="'+n+'"]').classList.add("on");document.querySelectorAll(".pg").forEach(function(p){p.classList.remove("on")});document.getElementById("pg-"+n).classList.add("on");if(n==="ev")re();else if(n==="an")ra();else if(n==="rp")rr()}
document.querySelectorAll(".tab").forEach(function(t){t.addEventListener("click",function(){switchPg(this.dataset.pg)})});
function dls(e){if(e.s==="late")return"late";if(e.s==="done")return"";var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));if((d-new Date())/86400000<=30)return"warn"}return""}
// ===== EVENTS PAGE (no progress column) =====
function re(){
var sf=document.getElementById("sf2");sf=sf?sf.value:"";
var sr2=document.getElementById("sr2");sr2=sr2?sr2.value.toLowerCase():"";
var bf=document.getElementById("bf2");bf=bf?bf.value:"";
var list=ev||[];
if(sf)list=list.filter(function(e){return e.s===sf});
if(sr2)list=list.filter(function(e){return e.t.toLowerCase().indexOf(sr2)>=0||br[e.b].toLowerCase().indexOf(sr2)>=0});
if(bf)list=list.filter(function(e){return e.b===parseInt(bf)});
if(sc2){list.sort(function(a,b){var va=a[sc2],vb=b[sc2];if(typeof va==="string")va=va.toLowerCase(),vb=vb.toLowerCase();return va>vb?sd2:va<vb?-sd2:0})}
var h='<div class="card"><div class="fr"><input id="sr2" placeholder="Поиск..." oninput="re()"><select id="sf2" onchange="re()"><option value="">Все статусы</option><option value="wait">Не начато</option><option value="warn">В процессе</option><option value="done">Исполнено</option><option value="late">Просрочено</option></select><select id="bf2" onchange="re()"><option value="">Все филиалы</option>'+br.map(function(b,i){return'<option value="'+i+'">'+b+'</option>'}).join("")+'</select><span style="font-size:12px;color:var(--g5);margin-left:auto">Найдено: '+list.length+'</span></div>';
h+='<table><tr>';
[{k:null,l:"№"},{k:null,l:"Мероприятие"},{k:"b",l:"Филиал"},{k:"sec",l:"Раздел"},{k:"due",l:"Срок"},{k:"s",l:"Статус"},{k:null,l:""}].forEach(function(c){h+='<th onclick="sc2=\''+c.k+'\';sd2=sc2===c.k?-sd2:1;re()">'+c.l+(sc2===c.k?(sd2===1?' ▲':' ▼'):'')+'</th>'});
h+='</tr>';
list.forEach(function(e){
var hs=e.sub&&e.sub.length,s=gsc(e.id),sdd=hs?s.length:0,stt=hs?e.sub.length:0,cl=dls(e);
h+='<tr class="'+cl+'"><td>'+e.id+'</td><td style="font-size:12px;max-width:340px">';
if(hs)h+='<span onclick="toggleEx('+e.id+')" style="cursor:pointer;margin-right:4px">'+(ex[e.id]?'▼':'▶')+'</span>';
h+=esc(e.t);if(hs)h+=' <span style="font-size:10px;color:var(--g5)">('+sdd+'/'+stt+')</span>';
h+='</td><td style="font-size:11px">'+br[e.b]+'</td><td><span class="badge b">'+["I","II","III","IV","V"][e.sec]+'</span></td><td>'+e.due+'</td><td>'+sb(e.s)+'</td><td><button class="btn btn-sm" onclick="oe('+e.id+')">📝</button></td></tr>';
if(hs&&ex[e.id])e.sub.forEach(function(s,i){var ch=s.indexOf(i)>=0;h+='<tr style="background:var(--g1)"><td></td><td style="font-size:11px;padding-left:40px"><input type="checkbox" '+(ch?"checked":"")+' onchange="ts('+e.id+','+i+',this.checked)"> '+s.l+') '+esc(s.t)+'</td><td></td><td></td><td></td><td></td><td></td></tr>'});
});
h+='</table></div>';
document.getElementById("pg-ev").innerHTML=h;
}
function toggleEx(id){ex[id]=!ex[id];re()}
function ts(id,si,chk){var s=gsc(id);if(chk&&s.indexOf(si)<0)s.push(si);else if(!chk)s=s.filter(function(x){return x!==si});ssc(id,s);var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(e&&e.sub){var p=Math.round(s.length/e.sub.length*100);if(s.length===e.sub.length&&e.s!=="done")e.s="done";e.p=Math.max(e.p,p);e.h.push(new Date().toLocaleDateString()+" — подпункты "+s.length+"/"+e.sub.length);se()}re()}
// ===== ANALYTICS =====
function ra(){var all=ev||[],done=all.filter(function(e){return e.s==="done"}).length,late=all.filter(function(e){return e.s==="late"}).length,warn=all.filter(function(e){return e.s==="warn"}).length,wait=all.filter(function(e){return e.s==="wait"}).length;
var h='<div class="row"><div class="stat"><div class="l">Всего</div><div class="n">'+all.length+'</div></div><div class="stat g"><div class="l">Исполнено</div><div class="n">'+done+'</div></div><div class="stat a"><div class="l">В процессе</div><div class="n">'+warn+'</div></div><div class="stat r"><div class="l">Просрочено</div><div class="n">'+late+'</div></div><div class="stat"><div class="l">Не начато</div><div class="n">'+wait+'</div></div></div>';
var tq=0,rq={};reg.forEach(function(r,ri){rq[ri]=0});all.forEach(function(e){reg.forEach(function(ri){var d=getMD(e.id,ri,-1);for(var k in d){if(d.hasOwnProperty(k)&&d[k]){tq+=d[k].qty||0;rq[ri]+=d[k].qty||0}if(e.sub)e.sub.forEach(function(s,si){var sd=getMD(e.id,ri,si);for(var sk in sd){if(sd.hasOwnProperty(sk)&&sd[sk]){tq+=sd[sk].qty||0;rq[ri]+=sd[sk].qty||0}}})}})});
h+='<div class="card"><h3>Количественные показатели</h3><div class="row"><div class="stat" style="background:var(--c);color:var(--b)"><div class="l">Всего единиц</div><div class="n">'+tq+'</div></div>';reg.forEach(function(r,ri){if(rq[ri])h+='<div class="stat"><div class="l">'+r+'</div><div class="n">'+rq[ri]+'</div></div>'});h+='</div></div>';
h+='<div class="card"><h3>По филиалам</h3>';br.forEach(function(b,i){var it=all.filter(function(e){return e.b===i}),d=it.filter(function(e){return e.s==="done"}).length,p=it.length?Math.round(d/it.length*100):0;h+='<div class="fl" style="margin-bottom:4px"><span style="width:180px;font-size:12px;font-weight:600">'+b+'</span><div style="flex:1;height:6px;background:var(--g2);border-radius:6px;overflow:hidden"><div style="width:'+p+'%;height:100%;background:'+(p>=50?"var(--gn)":p>=25?"var(--am)":"var(--rd)")+';border-radius:6px"></div></div><span style="font-weight:700;font-size:11px">'+p+'%</span></div>'});h+='</div>';
document.getElementById("pg-an").innerHTML=h}
// ===== REPORTS =====
function rr(){var h='<div class="card"><h3>Сводный отчёт</h3><div class="fr"><select id="rf">'+ms.map(function(m,i){return'<option value="'+i+'">'+M(i)+'</option>'}).join("")+'</select><span>—</span><select id="rt">'+ms.map(function(m,i){return'<option value="'+i+'"'+(i===11?" selected":"")+'>'+M(i)+'</option>'}).join("")+'</select><button class="btn btn-sm" onclick="dCSV()">CSV</button><button class="btn btn-sm" onclick="dHTML()">HTML</button></div>';var b=0;for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0)b+=localStorage.getItem(k).length*2}h+='<p style="font-size:12px;color:var(--g5);margin-bottom:8px">Хранилище: '+(b>1048576?(b/1048576).toFixed(1)+" МБ":(b/1024).toFixed(0)+" КБ")+'</p>';h+='<button class="btn btn-sm btn-gn" onclick="exp()">💾 Сохранить</button> <button class="btn btn-sm" onclick="document.getElementById(\'if\').click()">📥 Загрузить</button> <input type="file" id="if" accept=".json" style="display:none" onchange="imp(this)"> <button class="btn btn-sm btn-red" onclick="clr()">🗑 Очистить</button></div>';document.getElementById("pg-rp").innerHTML=h}
function dCSV(){var f=parseInt(document.getElementById("rf").value),t=parseInt(document.getElementById("rt").value);var csv="\uFEFF№;Филиал;Мероприятие;Регион;Статус;Срок\n";(ev||[]).forEach(function(e){reg.forEach(function(r,ri){var d=getMD(e.id,ri,-1),rep="";for(var i=f;i<=t;i++){var m=ms[i];if(d[m]&&d[m].report)rep+=M(i)+": "+d[m].report.replace(/"/g,'""')+"; "}csv+=e.id+';'+br[e.b]+';"'+e.t.replace(/"/g,'""')+'";'+r+';'+st[e.s]+';'+e.due+';"'+rep+'"\n'})});var a=document.createElement("a");a.href=URL.createObjectURL(new Blob([csv]));a.download="otchet.csv";a.click()}
function dHTML(){var f=parseInt(document.getElementById("rf").value),t=parseInt(document.getElementById("rt").value);var h='<!DOCTYPE html><html><head><meta charset="utf-8"><title>Отчёт</title><style>body{font:13px/1.4 Arial;max-width:1000px;margin:0 auto;padding:20px}.ev{border:1px solid #ddd;border-radius:8px;padding:14px;margin-bottom:12px}.badge{display:inline-block;padding:2px 6px;border-radius:4px;font-size:10px;font-weight:700}.g{background:#D1FAE5;color:#065F46}.a{background:#FEF3C7;color:#92400E}.r{background:#FEE2E2;color:#991B1B}.m{background:#f5f5f5;padding:6px 10px;border-radius:4px;margin:4px 0}</style></head><body><h2>Сводный отчёт</h2>';ev.forEach(function(e){var cl={done:"g",warn:"a",late:"r",wait:""}[e.s];h+='<div class="ev"><h3>'+e.id+'. '+esc(e.t)+'</h3><p>'+br[e.b]+' | '+sec[e.sec]+' | Срок: '+e.due+' | <span class="badge '+cl+'">'+st[e.s]+'</span></p>';reg.forEach(function(r,ri){var d=getMD(e.id,ri,-1);for(var i=f;i<=t;i++){var m=ms[i];if(d[m]&&d[m].report){h+='<div class="m"><b>'+M(i)+' — '+r+'</b><p>'+esc(d[m].report)+'</p></div>'}}});h+='</div>'});h+='</body></html>';try{var a=document.createElement("a");a.href=URL.createObjectURL(new Blob(["\uFEFF"+h]));a.download="otchet.html";a.click()}catch(e){alert("Слишком большой")}}
function exp(){var d={events:ev,date:new Date().toISOString(),files:{},sc:{}};for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0)d.files[k]=localStorage.getItem(k);if(k.indexOf("ss_")===0)d.sc[k]=localStorage.getItem(k)}var a=document.createElement("a");a.href=URL.createObjectURL(new Blob([JSON.stringify(d)]));a.download="backup.json";a.click()}
function imp(inp){if(!inp.files.length)return;var r=new FileReader();r.onload=function(ev){try{var d=JSON.parse(ev.target.result);ev=d.events;ne();se();for(var k in d.files)localStorage.setItem(k,d.files[k]);for(var k in d.sc)localStorage.setItem(k,d.sc[k]);alert("OK. Обновите.");location.reload()}catch(e){alert("Ошибка")}};r.readAsText(inp.files[0])}
function clr(){if(!confirm("Удалить все файлы?"))return;var ks=[];for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0||k.indexOf("ss_")===0)ks.push(k)}ks.forEach(function(k){localStorage.removeItem(k)});alert("Очищено");rr()}
// ===== EDIT FORM =====
function oe(id,mi,ri,si){
if(typeof mi==="number")cm=mi;if(typeof ri==="number")cr=ri;esi=(typeof si==="number")?si:-1;
var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(!e)return;
var m=ms[cm],s=gsc(e.id),md=getMD(e.id,cr,-1),cd=md[m]||{report:"",files:[]},cfs=cd.files||[];
var h='<span class="x" onclick="closeM()">&times;</span>';
h+='<div class="fm-title">Форма внесения информации</div>';
h+='<p style="font-size:11px;color:var(--g5);margin-bottom:12px">Заполняется ответственным исполнителем</p>';
// Мероприятие (readonly)
h+='<label>Мероприятие</label><input class="rdonly" value="'+e.id+'. '+esc(e.t)+'" readonly>';
h+='<div class="meta"><div>Филиал<strong>'+br[e.b]+'</strong></div><div>Срок<strong>'+e.due+'</strong></div></div>';
// Подпункты
if(e.sub&&e.sub.length){h+='<label>Подпункты</label>';e.sub.forEach(function(s,i){var ch=s.indexOf(i)>=0;h+='<div class="si"><input type="checkbox" id="sc2_'+i+'" '+(ch?"checked":"")+'><span class="n">'+s.l+')</span> '+esc(s.t)+'</div>'});h+='<div style="height:6px"></div>'}
// Месяц
h+='<label>Месяц</label><div class="mt">';ms.forEach(function(_,i){h+='<span class="'+(i===cm?"on":"")+'" onclick="oe('+e.id+','+i+','+cr+','+esi+')">'+M(i)+'</span>'});h+='</div>';
h+='<label>Регион</label><div class="mt">';reg.forEach(function(r,i){h+='<span class="'+(i===cr?"on":"")+'" onclick="oe('+e.id+','+cm+','+i+','+esi+')">'+r+'</span>'});h+='</div>';
// Статус
h+='<label>Статус</label><select id="es2"><option value="wait"'+(e.s==="wait"?" selected":"")+'>Не начато</option><option value="warn"'+(e.s==="warn"?" selected":"")+'>В процессе</option><option value="done"'+(e.s==="done"?" selected":"")+'>Выполнено</option></select>';
// Описание
h+='<label>Описание</label><textarea id="mr2" placeholder="Опишите проведённую работу, достигнутые результаты, выполненные действия...">'+esc(cd.report||"")+'</textarea>';
h+='<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px"><div style="flex:1"><label>Количество</label><input type="number" id="mq2" min="0" value="'+(cd.qty||0)+'"></div></div>';
// Форма завершения
h+='<label>Форма завершения</label>';
if(cfs.length){cfs.forEach(function(f,i){var ic="📄";if(/\.(jpg|jpeg|png|gif|webp)/i.test(f.name))ic="🖼";else if(/\.pdf/i.test(f.name))ic="📕";else if(/\.(doc|docx)/i.test(f.name))ic="📝";else if(/\.(xls|xlsx)/i.test(f.name))ic="📊";else if(/\.(ppt|pptx)/i.test(f.name))ic="📽";h+='<div class="fl"><span class="nm" onclick="dlF2('+e.id+','+cm+','+i+','+cr+',-1)">'+ic+' '+esc(f.name)+'</span><span class="sz">'+(f.size/1024).toFixed(0)+' КБ</span><button onclick="rmF2('+e.id+','+cm+','+i+','+cr+',-1)" style="border:none;color:var(--rd);cursor:pointer;font-size:14px">×</button></div>'})}
h+='<div class="up"><p>📤 Загрузить подтверждающие документы</p><input type="text" id="fd2" placeholder="Описание файла" style="width:100%;margin-bottom:6px"><input type="file" id="fi2" multiple><button class="btn btn-sm" id="ub2" onclick="upF2('+e.id+','+cm+','+cr+',-1)" style="margin-top:6px">Загрузить</button><div class="types">Поддерживаются: PDF, DOC/DOCX, XLS/XLSX, фото, презентации</div></div>';
// Sub-items files
if(e.sub&&e.sub.length&&esi>=0){var s=e.sub[esi],sd=getMD(e.id,cr,esi),scd=sd[m]||{report:"",files:[]},scfs=scd.files||[];h+='<div style="border-top:2px solid var(--c);padding-top:12px;margin-top:12px"><b>📎 Подпункт '+s.l+')</b><p style="font-size:11px;color:var(--g5);margin:4px 0">'+esc(s.t)+'</p>';h+='<label>Описание подпункта</label><textarea id="mr2_s'+esi+'">'+esc(scd.report||"")+'</textarea>';h+='<label>Количество</label><input type="number" id="mq2_s'+esi+'" min="0" value="'+(scd.qty||0)+'">';scfs.forEach(function(f,fi){h+='<div class="fl"><span class="nm" onclick="dlF2('+e.id+','+cm+','+fi+','+cr+','+esi+')">📄 '+esc(f.name)+'</span><span class="sz">'+(f.size/1024).toFixed(0)+' КБ</span><button onclick="rmF2('+e.id+','+cm+','+fi+','+cr+','+esi+')" style="border:none;color:var(--rd);cursor:pointer">×</button></div>'});h+='<div class="up"><input type="text" id="fd2_s'+esi+'" placeholder="Описание" style="width:100%;margin-bottom:6px"><input type="file" id="fi2_s'+esi+'" multiple><button class="btn btn-sm" id="ub2_s'+esi+'" onclick="upF2('+e.id+','+cm+','+cr+','+esi+')" style="margin-top:6px">Загрузить</button></div></div>'}
// Sub-item buttons
if(e.sub&&e.sub.length){h+='<div style="margin-top:10px">';e.sub.forEach(function(s,i){h+='<button class="btn btn-sm" onclick="oe('+e.id+','+cm+','+cr+','+i+')" style="margin-right:4px;margin-bottom:4px;'+(esi===i?'background:var(--c);font-weight:700':'')+'">'+(esi===i?'📂 ':'📎 ')+s.l+')</button>'});h+='</div>'}
h+='<div style="margin-top:14px;display:flex;gap:8px"><button class="btn" onclick="sv('+e.id+','+cm+')">Сохранить</button><button class="btn" style="background:var(--g2)" onclick="closeM()">Отмена</button></div>';
document.getElementById("mc").innerHTML=h;
document.getElementById("mo").classList.add("on");
}
function sv(id,mk){mk=ms[mk];var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(!e)return;e.s=document.getElementById("es2").value;var mr=document.getElementById("mr2"),mq=document.getElementById("mq2");if(mr){var ad=getMD(id,cr,-1);if(!ad[mk])ad[mk]={report:"",files:[]};ad[mk].report=mr.value;if(mq)ad[mk].qty=parseInt(mq.value)||0;setMD(id,ad,cr,-1)}if(e.sub&&e.sub.length){var cks=[];e.sub.forEach(function(_,i){var el=document.getElementById("sc2_"+i);if(el&&el.checked)cks.push(i);var sr=document.getElementById("mr2_s"+i),sq=document.getElementById("mq2_s"+i);if(sr){var sd=getMD(id,cr,i);if(!sd[mk])sd[mk]={report:"",files:[]};sd[mk].report=sr.value;if(sq)sd[mk].qty=parseInt(sq.value)||0;setMD(id,sd,cr,i)}});ssc(id,cks)}var now=new Date().toLocaleDateString();e.h.push(now+" — "+cu.n+": "+st[e.s]);if(e.s==="done"&&e.done==="—")e.done=now;se();closeM();re()}
function closeM(){document.getElementById("mo").classList.remove("on")}
function upF2(eid,mk,ri,si){mk=ms[mk];var pfx=si>=0?"_s"+si:"",fi=document.getElementById("fi2"+pfx);if(!fi||!fi.files.length)return;var desc=(document.getElementById("fd2"+pfx)||{}).value;desc=(desc||"").trim();var btn=document.getElementById("ub2"+pfx);if(btn){btn.textContent="...";btn.disabled=true}var ad=getMD(eid,ri,si);if(!ad[mk])ad[mk]={report:"",files:[]};var arr=ad[mk].files,pr=0,sk=0;function fin(){try{setMD(eid,ad,ri,si)}catch(e){alert("Хранилище заполнено")}if(sk)alert(sk+" файлов >3 МБ");closeM();oe(eid,cm,ri,si>=0?si:undefined)}for(var i=0;i<fi.files.length;i++){(function(f){if(f.size>3072*1024){sk++;pr++;if(pr===fi.files.length)fin();return}var r=new FileReader();r.onload=function(ev){arr.push({name:f.name,size:f.size,type:f.type,desc:desc,date:new Date().toLocaleDateString(),data:ev.target.result});pr++;if(pr===fi.files.length)fin()};r.onerror=function(){pr++;if(pr===fi.files.length)fin()};r.readAsDataURL(f)})(fi.files[i])}}
function dlF2(eid,mk,idx,ri,si){si=si||-1;mk=ms[mk];var ad=getMD(eid,ri,si),arr=ad[mk]?ad[mk].files:null;if(!arr||!arr[idx]||!arr[idx].data)return;var f=arr[idx],a=document.createElement("a");a.href=f.data;a.download=f.name;document.body.appendChild(a);a.click();document.body.removeChild(a)}
function rmF2(eid,mk,idx,ri,si){si=si||-1;mk=ms[mk];var ad=getMD(eid,ri,si);if(!ad[mk]||!ad[mk].files)return;ad[mk].files.splice(idx,1);setMD(eid,ad,ri,si);closeM();oe(eid,cm,ri,si>=0?si:undefined)}
// ===== INIT =====
document.getElementById("mo").addEventListener("click",function(e){if(e.target===this)closeM()});
document.addEventListener("keydown",function(e){if(e.key==="Escape")closeM()});
le();ne();var su=localStorage.getItem("su");if(su){try{cu=JSON.parse(su);show()}catch(e){}}
</script>
</body>
</html>