536 lines
48 KiB
HTML
536 lines
48 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>ИИ-агент мониторинга ПБ — АО «Казахтелеком»</title>
|
||
<style>
|
||
:root{--ink:#0F1218;--cyan:#00E5FF;--cyan-50:#E8FCFF;--white:#fff;--gray-500:#5B6573;--gray-100:#F2F4F7;--gray-200:#E5E7EB;--gray-700:#374151;--green:#10B981;--red:#EF4444;--amber:#F59E0B;--blue:#3B82F6;--sidebar-w:260px}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;color:var(--ink);background:var(--gray-100);display:flex;min-height:100vh}
|
||
.sidebar{width:var(--sidebar-w);background:var(--ink);color:var(--white);position:fixed;top:0;left:0;bottom:0;z-index:100;display:flex;flex-direction:column;overflow-y:auto}
|
||
.sidebar .logo{padding:20px 24px;font-size:17px;font-weight:800;border-bottom:1px solid rgba(255,255,255,.1);line-height:1.3}
|
||
.sidebar .logo span{color:var(--cyan)}
|
||
.sidebar nav{padding:16px 0;flex:1}
|
||
.sidebar nav a{display:flex;align-items:center;gap:12px;padding:12px 24px;color:#9aa3b2;font-weight:500;transition:.15s;font-size:15px;cursor:pointer}
|
||
.sidebar nav a:hover,.sidebar nav a.active{color:var(--white);background:rgba(0,229,255,.08)}
|
||
.sidebar nav a.active{border-right:3px solid var(--cyan)}
|
||
.sidebar nav a .ico{font-size:18px;width:24px;text-align:center}
|
||
.sidebar .user{padding:20px 24px;border-top:1px solid rgba(255,255,255,.1);font-size:13px;color:#6b7280}
|
||
.main{margin-left:var(--sidebar-w);flex:1;padding:24px 32px;max-width:calc(100vw - var(--sidebar-w))}
|
||
.page{display:none}
|
||
.page.active{display:block}
|
||
.page h2{font-size:24px;font-weight:700;margin-bottom:20px}
|
||
.stats-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:16px;margin-bottom:24px}
|
||
.stat-card{background:var(--white);border-radius:12px;padding:20px 24px;border:1px solid var(--gray-200)}
|
||
.stat-card .lbl{font-size:13px;color:var(--gray-500);margin-bottom:4px}
|
||
.stat-card .num{font-size:32px;font-weight:800;line-height:1}
|
||
.stat-card .sub{font-size:13px;color:var(--gray-500);margin-top:4px}
|
||
.stat-card.red .num{color:var(--red)}.stat-card.green .num{color:var(--green)}.stat-card.amber .num{color:var(--amber)}.stat-card.blue .num{color:var(--blue)}
|
||
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-bottom:24px}
|
||
.grid3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:24px;margin-bottom:24px}
|
||
.panel{background:var(--white);border-radius:12px;border:1px solid var(--gray-200);padding:24px}
|
||
.panel h3{font-size:17px;font-weight:700;margin-bottom:16px}
|
||
.chart-stub{height:200px;background:var(--gray-100);border-radius:8px;display:flex;align-items:flex-end;gap:8px;padding:16px 16px 8px}
|
||
.chart-stub .bar{flex:1;background:var(--cyan);border-radius:4px 4px 0 0;min-height:4px}
|
||
.chart-stub .bar.red{background:var(--red)}.chart-stub .bar.amber{background:var(--amber)}.chart-stub .bar.green{background:var(--green)}
|
||
.chart-labels{display:flex;gap:8px;padding:8px 16px 0;font-size:11px;color:var(--gray-500);text-align:center}
|
||
.chart-labels span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
table{width:100%;border-collapse:collapse}
|
||
th,td{padding:10px 14px;text-align:left;font-size:13px}
|
||
th{font-weight:600;color:var(--gray-500);font-size:11px;text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid var(--gray-200)}
|
||
td{border-bottom:1px solid var(--gray-200)}
|
||
tr:hover td{background:var(--cyan-50)}
|
||
.badge{display:inline-block;padding:4px 10px;border-radius:100px;font-size:12px;font-weight:600}
|
||
.badge.green{background:#D1FAE5;color:#065F46}.badge.amber{background:#FEF3C7;color:#92400E}.badge.red{background:#FEE2E2;color:#991B1B}.badge.blue{background:#DBEAFE;color:#1E40AF}.badge.gray{background:var(--gray-100);color:var(--gray-700)}
|
||
.filters{display:flex;gap:12px;margin-bottom:20px;flex-wrap:wrap;align-items:center}
|
||
.filters select,.filters input{padding:10px 14px;border:1px solid var(--gray-200);border-radius:8px;font-size:14px;background:var(--white);min-width:160px}
|
||
.filters input{min-width:280px}
|
||
.filters .count{font-size:13px;color:var(--gray-500);margin-left:auto}
|
||
.ai-tag{display:inline-flex;align-items:center;gap:6px;background:var(--cyan-50);color:var(--ink);padding:4px 10px;border-radius:6px;font-size:12px;font-weight:600}
|
||
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:200;display:none;align-items:center;justify-content:center}
|
||
.modal-overlay.open{display:flex}
|
||
.modal{background:var(--white);border-radius:16px;max-width:860px;width:92vw;max-height:85vh;overflow-y:auto;padding:32px}
|
||
.modal h2{font-size:21px;margin-bottom:8px;padding-right:30px}
|
||
.modal .close{float:right;background:none;border:none;font-size:28px;cursor:pointer;line-height:1;color:var(--gray-500);margin:-8px -8px 0 0}
|
||
.modal .meta{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:20px 0}
|
||
.modal .meta .fld{font-size:13px;color:var(--gray-500)}
|
||
.modal .meta .fld strong{display:block;font-size:15px;color:var(--ink);margin-top:2px}
|
||
.modal .docs{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}
|
||
.modal .docs span{background:var(--gray-100);padding:6px 12px;border-radius:6px;font-size:13px}
|
||
.modal .ai-block{background:var(--cyan-50);border-radius:8px;padding:16px;margin:16px 0;font-size:14px}
|
||
.modal .ai-block h4{font-size:14px;margin-bottom:6px}
|
||
.modal .timeline{font-size:13px;color:var(--gray-500);line-height:2}
|
||
.modal .timeline strong{color:var(--ink)}
|
||
.rating-bar{display:flex;align-items:center;gap:12px;padding:8px 0}
|
||
.rating-bar .name{width:200px;font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||
.rating-bar .track{flex:1;height:10px;background:var(--gray-200);border-radius:10px;overflow:hidden}
|
||
.rating-bar .fill{height:100%;border-radius:10px}
|
||
.timeline-item{display:flex;gap:8px;font-size:13px;padding:3px 0;color:var(--gray-500);align-items:baseline}
|
||
.timeline-item .dot{width:8px;height:8px;border-radius:50%;background:var(--cyan);flex-shrink:0;margin-top:6px}
|
||
.section-tag{display:inline-block;padding:4px 8px;border-radius:4px;font-size:11px;font-weight:600;margin-right:6px;background:var(--gray-100);color:var(--gray-700)}
|
||
@media(max-width:900px){
|
||
.sidebar{width:60px}.sidebar .logo,.sidebar nav a span,.sidebar .user{display:none}
|
||
.sidebar nav a{justify-content:center;padding:12px 0;font-size:20px}
|
||
.main{margin-left:60px;max-width:calc(100vw - 60px);padding:16px}
|
||
.grid2,.grid3{grid-template-columns:1fr}
|
||
.stats-row{grid-template-columns:1fr 1fr}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<aside class="sidebar">
|
||
<div class="logo"><span>ИИ-Агент</span><br>Казахтелеком</div>
|
||
<nav>
|
||
<a class="active" data-page="dashboard"><span class="ico">📊</span> <span>Дашборд</span></a>
|
||
<a data-page="register"><span class="ico">📋</span> <span>Реестр (35)</span></a>
|
||
<a data-page="analytics"><span class="ico">📈</span> <span>Аналитика</span></a>
|
||
<a data-page="reports"><span class="ico">📑</span> <span>Отчёты</span></a>
|
||
<a data-page="risks"><span class="ico">⚠️</span> <span>Карта рисков</span></a>
|
||
</nav>
|
||
<div class="user">Директор ДПБ • АО «Казахтелеком»</div>
|
||
</aside>
|
||
<main class="main" id="mainContent"></main>
|
||
<div class="modal-overlay" id="modalOverlay"><div class="modal" id="modalContent"></div></div>
|
||
|
||
<script>
|
||
// ===== 35 МЕРОПРИЯТИЙ ПЛАНА ПБ КАЗАХТЕЛЕКОМ НА 2026 =====
|
||
const sections = [
|
||
'I. Люди. Повышение культуры безопасности',
|
||
'II. Безопасность при эксплуатации оборудования',
|
||
'III. Предупреждение и готовность к ликвидации аварий и ЧС',
|
||
'IV. Информационно-разъяснительная работа',
|
||
'V. Внедрение ИИ и цифровизации'
|
||
]
|
||
const branches = [
|
||
'Дирекция производственной безопасности',
|
||
'Объединение «Дивизион «Сеть»»',
|
||
'Дивизион по корпоративному бизнесу',
|
||
'Дивизион по розничному бизнесу',
|
||
'Сервисная фабрика',
|
||
'Дирекция «Телеком Комплект»',
|
||
'Корпоративный университет',
|
||
'Дирекция управления проектами',
|
||
'Дивизион цифрового бизнеса'
|
||
]
|
||
const statusMap = {done:'Исполнено',warn:'На контроле',late:'Просрочено',wait:'Не начато'}
|
||
|
||
// real plan data — 35 events
|
||
const E = [
|
||
// I. ЛЮДИ (1-9)
|
||
{id:1, sec:0, t:'Обучение и повышение квалификации работников (VR, AR, цифровые симуляторы)', b:6, d:sections[0], s:'warn', p:45, due:'31.12.2026', done:'—',
|
||
r:'Генеральный директор КУ / Директора филиалов и ДАО',
|
||
docs:['Протоколы обучения','Электронная ведомость'],
|
||
ai:'Обучение ведётся по графику. Охвачено 45% персонала. VR-тренажёры развёрнуты в 3 филиалах. Рисков срыва нет.',
|
||
h:['15.01 — Мероприятие создано','01.03 — Запущено обучение в Алматинском филиале','15.05 — VR-симуляторы установлены в 3 филиалах']},
|
||
{id:2, sec:0, t:'Анализ и пересмотр ВНД согласно Стратегии развития ПБ на 2024-2028 гг.', b:0, d:sections[0], s:'done', p:100, due:'31.03.2026', done:'28.03.2026',
|
||
r:'Директор ДПБ / Директор ДИТ / Директора филиалов',
|
||
docs:['Отчёт о проведённом анализе','Утверждённый ВНД'],
|
||
ai:'Анализ завершён в срок. ВНД пересмотрены. Ключевые показатели ПБ установлены. Замечаний нет.',
|
||
h:['10.01 — Мероприятие создано','15.02 — Проведён анализ ВНД','28.03 — Отчёт утверждён']},
|
||
{id:3, sec:0, t:'Тематические совещания по вопросам ПБ (руководство–филиалы, филиалы–СП, филиалы–подрядчики)', b:0, d:sections[0], s:'warn', p:50, due:'31.12.2026', done:'—',
|
||
r:'Главный административный директор / Директор ДПБ',
|
||
docs:['Протоколы совещаний (a, b, c)'],
|
||
ai:'Проведено 2 квартальных совещания руководства с филиалами. Ежемесячные совещания филиалов со СП — выполняется. Совещания с подрядчиками — график соблюдается.',
|
||
h:['10.01 — Мероприятие создано','15.02 — Совещание Q1 проведено','15.05 — Совещание Q2 проведено']},
|
||
{id:4, sec:0, t:'Проверка знаний в формате тестирования после инструктажей по ОТ', b:6, d:sections[0], s:'warn', p:55, due:'31.12.2026', done:'—',
|
||
r:'Директора филиалов и ДАО',
|
||
docs:['Отчёты о проделанной работе','Тесты для оценки знаний'],
|
||
ai:'Тестирование внедрено в 6 филиалах. Средний результат — 82%. Рекомендуется усилить тесты по пожарной безопасности.',
|
||
h:['01.02 — Мероприятие создано','01.04 — Внедрено тестирование','01.06 — Промежуточный отчёт']},
|
||
{id:5, sec:0, t:'Нематериальное поощрение филиалов/ДАО со снижением НС, пожаров и аварий', b:0, d:sections[0], s:'done', p:100, due:'31.03.2026', done:'25.03.2026',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Информация о нематериальном поощрении'],
|
||
ai:'Положение о поощрении утверждено. Определены 3 филиала-лидера за 2023-2025 гг. Поощрение доведено до коллективов.',
|
||
h:['15.01 — Проект положения','01.03 — Согласование','25.03 — Утверждено']},
|
||
{id:6, sec:0, t:'Разработка ВНД по внутренним тренерам (отбор, подготовка, доплата)', b:6, d:sections[0], s:'warn', p:60, due:'30.06.2026', done:'—',
|
||
r:'Генеральный директор КУ / Управляющий директор по персоналу',
|
||
docs:['ВНД по внутренним тренерам','Перечень внутренних тренеров'],
|
||
ai:'Проект ВНД на финальном согласовании. Перечень тренеров сформирован (12 чел). Риск: доплаты требуют бюджета.',
|
||
h:['01.03 — Мероприятие создано','15.04 — Проект ВНД','01.06 — Перечень тренеров']},
|
||
{id:7, sec:0, t:'Обмен опытом в области ПБ (Комитет HSE, выезды, онлайн-семинары)', b:1, d:sections[0], s:'warn', p:40, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Материалы обмена опытом'],
|
||
ai:'Проведён 1 выезд на площадку KEGOC. Онлайн-семинар с иностранной компанией запланирован на июль. Активность средняя.',
|
||
h:['15.02 — Мероприятие создано','01.04 — Выезд на KEGOC','15.05 — План семинаров']},
|
||
{id:8, sec:0, t:'Анализ эффективности охраны здоровья (медосмотры, Well-being Week, скрининг, микротравмы)', b:4, d:sections[0], s:'wait', p:15, due:'30.09.2026', done:'—',
|
||
r:'Директор ДПБ / Управляющий директор по персоналу',
|
||
docs:['Заключительный Акт','Программа Well-being','Отчёт о скрининге','Отчёт о микротравмах'],
|
||
ai:'Медосмотры по графику — Q3. Well-being Week запланирован на сентябрь. Алгоритм микротравм в разработке. Ранний этап.',
|
||
h:['01.04 — Мероприятие создано','01.06 — Проект алгоритма микротравм']},
|
||
{id:9, sec:0, t:'Участие в международных/национальных конкурсах профмастерства по ПБ', b:6, d:sections[0], s:'wait', p:20, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Результаты конкурсов','Пакет материалов'],
|
||
ai:'Определены 2 конкурса для участия. Заявки готовятся. Срок — до конца года.',
|
||
h:['01.05 — Мероприятие создано','01.06 — Отобраны конкурсы']},
|
||
|
||
// II. БЕЗОПАСНОСТЬ ПРИ ЭКСПЛУАТАЦИИ ОБОРУДОВАНИЯ (10-18)
|
||
{id:10, sec:1, t:'Техническое перевооружение изношенного оборудования, зданий и сооружений', b:1, d:sections[1], s:'warn', p:55, due:'31.12.2026', done:'—',
|
||
r:'Генеральный директор ОДС / Директор СФ / Директор ДУП / Директор ДИТ',
|
||
docs:['Аналитическая справка по филиалам/ДАО'],
|
||
ai:'По плану 2024-2027. Заменено 55% единиц оборудования. Карагандинский филиал отстаёт на 12%. Рекомендуется усилить контроль.',
|
||
h:['01.01 — Переходящее с 2024','01.04 — Промежуточный отчёт','01.06 — 55% исполнения']},
|
||
{id:11, sec:1, t:'Пересмотр и актуализация нарядно-допускной системы (сертификаты безопасности)', b:1, d:sections[1], s:'warn', p:70, due:'30.06.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Переутверждённая процедура наряд-допусков','Фотоотчёт','Протоколы обучения'],
|
||
ai:'Процедура пересмотрена. Пилот сертификатов безопасности запущен в ВКО филиале. Обучение новых процедур — 85% персонала.',
|
||
h:['01.02 — Мероприятие создано','01.04 — Проект процедуры','15.05 — Пилот в ВКО']},
|
||
{id:12, sec:1, t:'Внедрение цифровой маркировки опасных техустройств (QR-коды)', b:8, d:sections[1], s:'wait', p:8, due:'30.09.2026', done:'—',
|
||
r:'Директора филиалов и ДАО',
|
||
docs:['Справка о внедрении','Фотоотчёт'],
|
||
ai:'Проект на стадии ТЭО. QR-коды не заказаны. Риск срыва срока — низкий, начало работ запланировано на июль.',
|
||
h:['01.05 — Мероприятие создано','01.06 — ТЭО в разработке']},
|
||
{id:13, sec:1, t:'Ежеквартальные проверки по проверочным листам БиОТ, пром- и пожарной безопасности', b:0, d:sections[1], s:'warn', p:50, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ',
|
||
docs:['Акты проверок','График проверок'],
|
||
ai:'Q1 проверки завершены в 7 из 8 филиалов. Q2 — идёт по графику. Выявлено 23 нарушения, устранено 18.',
|
||
h:['01.01 — Мероприятие создано','31.03 — Q1 проверки','01.06 — Q2 начаты']},
|
||
{id:14, sec:1, t:'Участие в перекрёстных аудитах ПК согласно Плану-графику', b:0, d:sections[1], s:'warn', p:40, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ',
|
||
docs:['Письмо о предоставлении кандидата'],
|
||
ai:'Назначены 4 аудитора от Казахтелеком. Участвовали в 2 аудитах KEGOC и КазТрансОйл. График соблюдается.',
|
||
h:['15.01 — Назначены аудиторы','01.03 — Аудит KEGOC','15.04 — Аудит КазТрансОйл']},
|
||
{id:15, sec:1, t:'Проактивные инструменты (поведенческие аудиты, Near Miss, право приостановки)', b:0, d:sections[1], s:'warn', p:48, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Аналитическая справка','Журнал опережающих индикаторов'],
|
||
ai:'Зарегистрировано 147 Near Miss за полугодие (+12% к 2025). Поведенческие аудиты — 320 шт. Данные вносятся в журнал СУО.',
|
||
h:['01.01 — Мероприятие создано','01.04 — Q1: 68 Near Miss','01.06 — Q2: 79 Near Miss']},
|
||
{id:16, sec:1, t:'Повышение эффективности управления подрядными организациями (аудиты, стартовые совещания)', b:1, d:sections[1], s:'done', p:85, due:'31.12.2026', done:'—',
|
||
r:'Директора филиалов и ДАО',
|
||
docs:['План-график перекрёстных аудитов','Акты проверки','Протоколы совещаний'],
|
||
ai:'Q1 — 12 подрядчиков проверено. Стартовые совещания — 100% охват перед допуском. Рекомендации: усилить контроль подрядчиков в Алматинском филиале.',
|
||
h:['15.01 — План-график','01.03 — Q1 проверки','01.06 — Q2 проверки начаты']},
|
||
{id:17, sec:1, t:'Контроль состояния ПБ на объектах (CEO-1, первые руководители филиалов)', b:0, d:sections[1], s:'warn', p:35, due:'31.12.2026', done:'—',
|
||
r:'Главный административный директор / Директор ДПБ',
|
||
docs:['Отчёты по результатам проверок','График проверок','Фотоотчёт'],
|
||
ai:'CEO-1 проверил 2 филиала (ЗКО, Атырау). Первые руководители филиалов — 6 выездов. Активность ниже плана. Рекомендуется график CEO-1 на Q3.',
|
||
h:['01.02 — Мероприятие создано','15.03 — Проверка ЗКО','01.05 — Проверка Атырау']},
|
||
{id:18, sec:1, t:'Контроль транспортной безопасности (ежемесячный мониторинг нарушений)', b:1, d:sections[1], s:'done', p:90, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Ежемесячный сводный отчёт о нарушениях'],
|
||
ai:'Январь-май — 34 нарушения. Применены штрафные санкции к 12 водителям подрядчиков. Тренд на снижение (-15% к 2025).',
|
||
h:['01.01 — Мероприятие создано','01.02 — Отчёт январь','01.06 — Отчёт май']},
|
||
|
||
// III. ПРЕДУПРЕЖДЕНИЕ И ГОТОВНОСТЬ К ЛИКВИДАЦИИ АВАРИЙ И ЧС (19-20)
|
||
{id:19, sec:2, t:'Учебные тревоги и тренировки (аварии, пожары, первая помощь)', b:1, d:sections[2], s:'warn', p:30, due:'31.12.2026', done:'—',
|
||
r:'Управляющий директор по безопасности / Руководители ДАО',
|
||
docs:['Акты о проведении тренировок','Пресс-релизы'],
|
||
ai:'Проведено 1 учение по ликвидации аварии (ВКО). Пожарные тренировки: 1 из 2. Занятия по первой помощи запланированы на Q3. Необходимо ускорить.',
|
||
h:['01.02 — Мероприятие создано','15.03 — Учение ВКО','15.05 — Пожарная тренировка №1']},
|
||
{id:20, sec:2, t:'Усиление реагирования на ЧС (Crisis Management System, обучение, штабы)', b:0, d:sections[2], s:'warn', p:65, due:'30.06.2026', done:'—',
|
||
r:'Управляющий директор по безопасности / Директора филиалов',
|
||
docs:['Приказ о внедрении CMS','Материалы обучения','Акты заседаний штабов'],
|
||
ai:'Приказ о CMS подписан. Обучение проведено для 60% ответственных. Одно заседание штаба проведено, второе — в июне.',
|
||
h:['01.03 — Мероприятие создано','01.04 — Приказ CMS','15.05 — Заседание штаба №1']},
|
||
|
||
// IV. ИНФОРМАЦИОННО-РАЗЪЯСНИТЕЛЬНАЯ РАБОТА (21-31)
|
||
{id:21, sec:3, t:'Выпуск обращения Председателя Правления о важности соблюдения требований ПБ', b:0, d:sections[3], s:'done', p:100, due:'31.12.2026', done:'15.02.2026',
|
||
r:'Директор ДПБ / Пресс-секретарь ЦА',
|
||
docs:['Публикация на информационных порталах'],
|
||
ai:'Обращение опубликовано на корпоративном портале и в SK News. Охват — 100% персонала. Задача выполнена досрочно.',
|
||
h:['15.01 — Проект обращения','01.02 — Подписание','15.02 — Публикация']},
|
||
{id:22, sec:3, t:'Стратегические сессии/Форумы для первых руководителей и семинары для подрядчиков', b:0, d:sections[3], s:'wait', p:15, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Департамент по коммуникациям',
|
||
docs:['Протоколы форумов/сессий','Протоколы семинаров'],
|
||
ai:'Форум запланирован на октябрь. Семинары для подрядчиков — 2 площадки определены. Начало подготовки.',
|
||
h:['01.05 — Мероприятие создано','01.06 — Определены площадки']},
|
||
{id:23, sec:3, t:'Олимпиада по производственной безопасности среди специалистов ПБ', b:6, d:sections[3], s:'wait', p:10, due:'30.09.2026', done:'—',
|
||
r:'Директор ДПБ',
|
||
docs:['Протокол итогов Олимпиады'],
|
||
ai:'Положение об Олимпиаде на согласовании. Задания не разработаны. Рекомендуется начать подготовку в июне.',
|
||
h:['01.05 — Мероприятие создано','01.06 — Проект положения']},
|
||
{id:24, sec:3, t:'Ознакомление работников с обстоятельствами НС с тяжёлым/летальным исходом', b:0, d:sections[3], s:'done', p:92, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Информационные бюллетени','Листы ознакомления'],
|
||
ai:'За полугодие разослано 3 бюллетеня по НС в ПК Фонда. Ознакомление — 92% персонала. Рекомендация: догнать до 100% к Q3.',
|
||
h:['01.01 — Мероприятие создано','15.02 — Бюллетень №1','01.05 — Бюллетень №3']},
|
||
{id:25, sec:3, t:'Молодёжные проектные инициативы (SK News, выезды, аудиты, онлайн-эфиры)', b:6, d:sections[3], s:'warn', p:40, due:'31.12.2026', done:'—',
|
||
r:'Управляющий директор по персоналу / Директор ДПБ',
|
||
docs:['Публикации в SK News','Материалы мероприятий'],
|
||
ai:'Опубликовано 2 истории в SK News. Проведён 1 выезд молодых специалистов. 3 молодых специалиста привлечены в перекрёстные аудиты.',
|
||
h:['01.02 — Мероприятие создано','15.03 — Публикация №1','01.05 — Выезд']},
|
||
{id:26, sec:3, t:'Наглядная агитация (видеоролики, подкасты, постеры, брошюры)', b:2, d:sections[3], s:'warn', p:50, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Департамент по коммуникациям',
|
||
docs:['Видеоролики','Постеры и брошюры'],
|
||
ai:'Снято 2 видеоролика («Безопасность будущего», профилактика ДТП). Постеры распространены. Подкаст в разработке. Хороший темп.',
|
||
h:['01.02 — Мероприятие создано','01.04 — Видеоролик №1','01.06 — Видеоролик №2']},
|
||
{id:27, sec:3, t:'Организация встреч коллектива с получившими производственные травмы', b:3, d:sections[3], s:'warn', p:30, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Фотофиксация'],
|
||
ai:'Проведена 1 встреча в Карагандинском филиале. Получены согласия от 3 работников. Рекомендуется расширить на другие филиалы.',
|
||
h:['01.03 — Мероприятие создано','01.05 — Встреча в Караганде']},
|
||
{id:28, sec:3, t:'Пропаганда безопасности через семейные ценности (письма, Семейный день, конкурс рисунков)', b:0, d:sections[3], s:'warn', p:25, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Департамент по коммуникациям',
|
||
docs:['Информационное письмо','Пресс-релизы'],
|
||
ai:'Направлено 5 писем семьям отличившихся. Семейный день ОТ запланирован на август. Конкурс рисунков анонсирован.',
|
||
h:['01.04 — Мероприятие создано','15.05 — Письма семьям']},
|
||
{id:29, sec:3, t:'Разработка корпоративного сборника лучших практик по ПБ', b:6, d:sections[3], s:'late', p:40, due:'30.06.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Корпоративный сборник лучших практик'],
|
||
ai:'Сборник в разработке. Опрошено 4 из 8 филиалов. Есть риск срыва срока Q2 — осталось 26 дней. Требуется эскалация.',
|
||
h:['01.03 — Мероприятие создано','01.05 — Опрошены 4 филиала','01.06 — Эскалация: риск срыва']},
|
||
{id:30, sec:3, t:'Сбор предложений по цифровым решениям для системы управления ПБ', b:7, d:sections[3], s:'warn', p:60, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Предложения по улучшению','План реализации'],
|
||
ai:'Собрано 18 предложений. 5 приняты в реализацию. Идёт консолидация в ДПБ. Активность хорошая.',
|
||
h:['01.01 — Мероприятие создано','01.04 — 10 предложений','01.06 — 18 предложений']},
|
||
{id:31, sec:3, t:'Разработка видеообзора кейсов происшествий в ПК', b:0, d:sections[3], s:'warn', p:75, due:'30.06.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Видеообзор'],
|
||
ai:'Видеообзор смонтирован на 75%. Озвучка запланирована на 15 июня. Срок Q2 — укладываемся.',
|
||
h:['01.03 — Мероприятие создано','01.05 — Сценарий утверждён','01.06 — Монтаж 75%']},
|
||
|
||
// V. ВНЕДРЕНИЕ ИИ И ЦИФРОВИЗАЦИИ (32-35)
|
||
{id:32, sec:4, t:'Внедрение чат-бота ИИ-ассистента по производственной безопасности', b:8, d:sections[4], s:'warn', p:70, due:'30.06.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Справка о функционировании','Скриншоты'],
|
||
ai:'Чат-бот разработан, проходит тестирование в ЦА. База НПА загружена. Пилотный запуск — 15 июня. Успеваем в Q2.',
|
||
h:['01.02 — Мероприятие создано','01.04 — Разработка','01.06 — Тестирование']},
|
||
{id:33, sec:4, t:'Внедрение системы анализа и предупреждения НС и критических происшествий', b:8, d:sections[4], s:'wait', p:15, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Справка о функционировании','Скриншоты'],
|
||
ai:'ТЗ на систему согласовывается. Интеграция с платформой Фонда — прорабатывается. Ранний этап, рисков срыва нет.',
|
||
h:['01.04 — Мероприятие создано','01.06 — ТЗ на согласовании']},
|
||
{id:34, sec:4, t:'Запуск электронного HSE паспорта на каждого работника', b:8, d:sections[4], s:'wait', p:10, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Справка о функционировании','Скриншоты'],
|
||
ai:'Концепция HSE паспорта утверждена. Выбран подрядчик. Интеграция с КЦС — в плане на Q3. Ранний этап.',
|
||
h:['01.05 — Мероприятие создано','01.06 — Концепция утверждена']},
|
||
{id:35, sec:4, t:'Внедрение системы электронных нарядов-допусков на работы повышенной опасности', b:5, d:sections[4], s:'wait', p:8, due:'31.12.2026', done:'—',
|
||
r:'Директор ДПБ / Директора филиалов и ДАО',
|
||
docs:['Справка о функционировании','Скриншоты'],
|
||
ai:'Проект на предпроектной стадии. Анализ рынка решений проведён. Ожидается выбор платформы в Q3.',
|
||
h:['01.05 — Мероприятие создано','01.06 — Анализ рынка']}
|
||
]
|
||
|
||
const events = E
|
||
const allBranches = [...new Set(events.map(e=>e.b))].map(i=>branches[i])
|
||
|
||
// ===== HELPERS =====
|
||
function pctBar(p){return `<div class="track"><div class="fill" style="width:${p}%;background:${p>=80?'var(--green)':p>=40?'var(--amber)':'var(--red)'}"></div></div> ${p}%`}
|
||
function sBadge(s){const map={done:'green',warn:'amber',late:'red',wait:'gray'};return `<span class="badge ${map[s]||'gray'}">${statusMap[s]||s}</span>`}
|
||
function secBadge(s){return `<span class="badge blue">${['I','II','III','IV','V'][s]}</span>`}
|
||
|
||
// ===== PAGES =====
|
||
function pageDashboard(){
|
||
let done=events.filter(e=>e.s==='done').length
|
||
let late=events.filter(e=>e.s==='late').length
|
||
let warn=events.filter(e=>e.s==='warn').length
|
||
let wait=events.filter(e=>e.s==='wait').length
|
||
let total=events.length
|
||
let donePct=Math.round(done/total*100)
|
||
|
||
return `<div class="page active"><h2>Дашборд производственной безопасности</h2>
|
||
<div class="stats-row">
|
||
<div class="stat-card"><div class="lbl">Всего мероприятий</div><div class="num">${total}</div><div class="sub">План ПБ на 2026 год</div></div>
|
||
<div class="stat-card green"><div class="lbl">Исполнено</div><div class="num">${done}</div><div class="sub">${donePct}% от плана</div></div>
|
||
<div class="stat-card amber"><div class="lbl">На контроле</div><div class="num">${warn}</div></div>
|
||
<div class="stat-card red"><div class="lbl">Просрочено</div><div class="num">${late}</div></div>
|
||
<div class="stat-card blue"><div class="lbl">Не начато</div><div class="num">${wait}</div></div>
|
||
</div>
|
||
<div class="grid2">
|
||
<div class="panel">
|
||
<h3>Исполнение по разделам</h3>
|
||
${sections.map((s,i)=>{
|
||
let items=events.filter(e=>e.sec===i)
|
||
let pct=Math.round(items.filter(e=>e.s==='done').length/Math.max(1,items.length)*100)
|
||
return `<div class="rating-bar"><span class="name" style="font-size:12px">${s.replace(/^[IVX]+\.\s/,'')}</span><div class="track"><div class="fill" style="width:${pct}%;background:var(--cyan)"></div></div><span style="font-size:13px;font-weight:700;width:40px;text-align:right">${pct}%</span></div>`
|
||
}).join('')}
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Рейтинг филиалов</h3>
|
||
${allBranches.map((b,i)=>{
|
||
let items=events.filter(e=>e.b===i||(e.b===i&&branches[e.b]===b))
|
||
// recalc for actual branch index
|
||
let _items=events.filter(e=>branches[e.b]===b)
|
||
let pct=Math.round(_items.filter(e=>e.s==='done').length/Math.max(1,_items.length)*100)
|
||
return `<div class="rating-bar"><span class="name">${b}</span><div class="track"><div class="fill" style="width:${pct}%;background:${pct>=50?'var(--green)':pct>=25?'var(--amber)':'var(--red)'}"></div></div><span style="font-size:13px;font-weight:700;width:40px;text-align:right">${pct}%</span></div>`
|
||
}).join('')}
|
||
</div>
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Динамика исполнения по кварталам</h3>
|
||
<div class="chart-stub">
|
||
<div class="bar green" style="height:45%"></div>
|
||
<div class="bar amber" style="height:60%"></div>
|
||
<div class="bar" style="height:70%"></div>
|
||
<div class="bar" style="height:${donePct}%"></div>
|
||
</div>
|
||
<div class="chart-labels"><span>Q1 (факт)</span><span>Q2 (прогноз)</span><span>Q3 (план)</span><span>Q4 (цель: 100%)</span></div>
|
||
</div>
|
||
</div>`
|
||
}
|
||
|
||
function pageRegister(filter='',secFilter='',statusFilter=''){
|
||
let list=events
|
||
if(filter) list=list.filter(e=>e.t.toLowerCase().includes(filter.toLowerCase())||branches[e.b].toLowerCase().includes(filter.toLowerCase()))
|
||
if(secFilter!=='') list=list.filter(e=>e.sec===parseInt(secFilter))
|
||
if(statusFilter) list=list.filter(e=>e.s===statusFilter)
|
||
|
||
return `<div class="page active"><h2>Реестр мероприятий</h2>
|
||
<div class="filters">
|
||
<input placeholder="Поиск по названию или филиалу..." oninput="refreshPage('register',this.value,document.getElementById('secFilter')?.value||'',document.getElementById('statusFilter')?.value||'')" id="searchInput">
|
||
<select onchange="refreshPage('register',document.getElementById('searchInput')?.value||'',this.value,document.getElementById('statusFilter')?.value||'')" id="secFilter">
|
||
<option value="">Все разделы</option>
|
||
${sections.map((s,i)=>`<option value="${i}">${s}</option>`).join('')}
|
||
</select>
|
||
<select onchange="refreshPage('register',document.getElementById('searchInput')?.value||'',document.getElementById('secFilter')?.value||'',this.value)" id="statusFilter">
|
||
<option value="">Все статусы</option>
|
||
<option value="done">Исполнено</option><option value="warn">На контроле</option><option value="late">Просрочено</option><option value="wait">Не начато</option>
|
||
</select>
|
||
<span class="count">Найдено: ${list.length}</span>
|
||
</div>
|
||
<div class="panel" style="overflow-x:auto">
|
||
<table>
|
||
<thead><tr><th>№</th><th>Мероприятие</th><th>Раздел</th><th>Филиал</th><th>Срок</th><th>Прогресс</th><th>Статус</th></tr></thead>
|
||
<tbody>${list.map(e=>`<tr style="cursor:pointer" onclick="openEvent(${e.id})">
|
||
<td>${e.id}</td><td><strong>${e.t}</strong></td><td><span class="badge blue">${['I','II','III','IV','V'][e.sec]}</span></td>
|
||
<td style="font-size:12px">${branches[e.b]}</td><td style="font-size:12px">${e.due}</td>
|
||
<td style="white-space:nowrap">${pctBar(e.p)}</td><td>${sBadge(e.s)}</td></tr>`).join('')}</tbody>
|
||
</table>
|
||
</div>
|
||
</div>`
|
||
}
|
||
|
||
function pageAnalytics(){
|
||
let branchRatings=allBranches.map(bi=>{
|
||
let items=events.filter(e=>branches[e.b]===bi)
|
||
let done=items.filter(e=>e.s==='done').length
|
||
let late=items.filter(e=>e.s==='late').length
|
||
return {name:bi,done,late,total:items.length,pct:Math.round(done/Math.max(1,items.length)*100)}
|
||
}).sort((a,b)=>b.pct-a.pct)
|
||
|
||
let sectionStats=sections.map((s,i)=>{
|
||
let items=events.filter(e=>e.sec===i)
|
||
let done=items.filter(e=>e.s==='done').length
|
||
return {name:s.replace(/^[IVX]+\.\s/,''),done,total:items.length,pct:Math.round(done/Math.max(1,items.length)*100)}
|
||
})
|
||
|
||
return `<div class="page active"><h2>Аналитика</h2>
|
||
<div class="grid2">
|
||
<div class="panel">
|
||
<h3>Рейтинг филиалов/ДАО</h3>
|
||
${branchRatings.map((r,i)=>`<div class="rating-bar">
|
||
<span class="name">${i+1}. ${r.name}</span>
|
||
<div class="track"><div class="fill" style="width:${r.pct}%;background:${r.pct>=50?'var(--green)':r.pct>=25?'var(--amber)':'var(--red)'}"></div></div>
|
||
<span style="font-size:13px;font-weight:700;width:60px;text-align:right">${r.pct}% (${r.done}/${r.total})</span></div>`).join('')}
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Исполнение по разделам Плана</h3>
|
||
${sectionStats.map(s=>`<div class="rating-bar">
|
||
<span class="name" style="font-size:12px">${s.name}</span>
|
||
<div class="track"><div class="fill" style="width:${s.pct}%;background:var(--cyan)"></div></div>
|
||
<span style="font-size:13px;font-weight:700;width:60px;text-align:right">${s.pct}% (${s.done}/${s.total})</span></div>`).join('')}
|
||
</div>
|
||
</div>
|
||
<div class="panel" style="margin-top:16px">
|
||
<h3>Просроченные мероприятия</h3>
|
||
${events.filter(e=>e.s==='late').map(e=>`<div class="rating-bar">
|
||
<span class="name" style="font-size:12px">${e.t.slice(0,50)}...</span>
|
||
<span style="font-size:12px;color:var(--red);font-weight:700">${e.due}</span>
|
||
<span class="badge red">${branches[e.b]}</span></div>`).join('')||'<p style="color:var(--gray-500)">Просрочек нет</p>'}
|
||
</div>
|
||
</div>`
|
||
}
|
||
|
||
function pageReports(){
|
||
return `<div class="page active"><h2>Формирование отчётности</h2>
|
||
<div class="stats-row">
|
||
<div class="stat-card"><div class="lbl">Ежемесячный отчёт</div><div class="num" style="font-size:20px">Май 2026</div><div class="sub"><span class="badge green">Сформирован</span></div></div>
|
||
<div class="stat-card"><div class="lbl">Квартальный отчёт</div><div class="num" style="font-size:20px">Q2 2026</div><div class="sub"><span class="badge amber">В обработке</span></div></div>
|
||
<div class="stat-card"><div class="lbl">Годовой отчёт</div><div class="num" style="font-size:20px">2026</div><div class="sub"><span class="badge gray">Ожидается</span></div></div>
|
||
</div>
|
||
<div class="panel" style="margin-top:16px">
|
||
<h3>Все отчёты</h3>
|
||
<table>
|
||
<thead><tr><th>Тип отчёта</th><th>Период</th><th>Статус</th><th>Дата</th><th>Формат</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Ежемесячный отчёт</td><td>Май 2026</td><td><span class="badge green">Готов</span></td><td>01.06.2026</td><td>PDF, Excel</td></tr>
|
||
<tr><td>Аналитическая справка</td><td>Май 2026</td><td><span class="badge green">Готов</span></td><td>02.06.2026</td><td>PDF, Word</td></tr>
|
||
<tr><td>Презентация для совещания</td><td>Июнь 2026</td><td><span class="badge amber">В работе</span></td><td>—</td><td>PPTX</td></tr>
|
||
<tr><td>Квартальный отчёт</td><td>Q2 2026</td><td><span class="badge amber">В работе</span></td><td>—</td><td>PDF, Excel</td></tr>
|
||
<tr><td>Рейтинг филиалов</td><td>Июнь 2026</td><td><span class="badge green">Готов</span></td><td>04.06.2026</td><td>PDF</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>`
|
||
}
|
||
|
||
function pageRisks(){
|
||
let risks=events.filter(e=>e.s==='late'||e.s==='warn').map(e=>{
|
||
let level=e.s==='late'?'high':e.p<30?'low':e.p<60?'medium':'low'
|
||
let reason=e.s==='late'?'Просрочен срок исполнения':e.p<30?'Ранний этап, риск отставания':e.p<60?'Требуется ускорение':'Незначительное отставание'
|
||
return {event:e.t,branch:branches[e.b],level,reason}
|
||
})
|
||
let hi=risks.filter(r=>r.level==='high').length
|
||
let md=risks.filter(r=>r.level==='medium').length
|
||
let lo=risks.filter(r=>r.level==='low').length
|
||
return `<div class="page active"><h2>Карта рисков</h2>
|
||
<div class="stats-row">
|
||
<div class="stat-card red"><div class="lbl">Высокий риск</div><div class="num">${hi}</div></div>
|
||
<div class="stat-card amber"><div class="lbl">Средний риск</div><div class="num">${md}</div></div>
|
||
<div class="stat-card blue"><div class="lbl">Низкий риск</div><div class="num">${lo}</div></div>
|
||
</div>
|
||
<div class="panel">
|
||
<h3>Реестр рисков</h3>
|
||
<table>
|
||
<thead><tr><th>Мероприятие</th><th>Филиал/ДАО</th><th>Уровень</th><th>Причина</th></tr></thead>
|
||
<tbody>${risks.map(r=>`<tr>
|
||
<td style="font-size:12px"><strong>${r.event.slice(0,65)}...</strong></td>
|
||
<td style="font-size:12px">${r.branch}</td>
|
||
<td>${r.level==='high'?'<span class="badge red">Высокий</span>':r.level==='medium'?'<span class="badge amber">Средний</span>':'<span class="badge blue">Низкий</span>'}</td>
|
||
<td style="font-size:12px">${r.reason}</td></tr>`).join('')}</tbody>
|
||
</table>
|
||
</div>
|
||
</div>`
|
||
}
|
||
|
||
function openEvent(id){
|
||
let e=events.find(x=>x.id===id); if(!e) return
|
||
document.getElementById('modalContent').innerHTML=`
|
||
<button class="close" onclick="closeModal()">×</button>
|
||
<div style="display:flex;gap:8px;align-items:center;margin-bottom:12px">
|
||
<span class="badge blue">Раздел ${['I','II','III','IV','V'][e.sec]}</span>
|
||
<span class="ai-tag">🤖 Анализ ИИ</span>
|
||
</div>
|
||
<h2>${e.t}</h2>
|
||
<div class="meta">
|
||
<div class="fld">Филиал/ДАО<strong>${branches[e.b]}</strong></div>
|
||
<div class="fld">Направление<strong>${e.d}</strong></div>
|
||
<div class="fld">Срок исполнения<strong>${e.due}</strong></div>
|
||
<div class="fld">Факт исполнения<strong>${e.done}</strong></div>
|
||
<div class="fld">Ответственный<strong>${e.r}</strong></div>
|
||
<div class="fld">Прогресс<strong>${pctBar(e.p)}</strong></div>
|
||
<div class="fld">Статус<strong>${sBadge(e.s)}</strong></div>
|
||
</div>
|
||
${e.docs.length?`<div style="font-weight:600;margin:8px 0 4px;font-size:14px">Форма завершения / материалы:</div><div class="docs">${e.docs.map(d=>`<span>📄 ${d}</span>`).join('')}</div>`:''}
|
||
<div class="ai-block"><h4>🤖 Выводы ИИ-агента</h4>${e.ai}</div>
|
||
<div style="font-weight:600;margin:8px 0 4px;font-size:14px">История изменений:</div>
|
||
<div class="timeline">${e.h.map(h=>`<div class="timeline-item"><div class="dot"></div>${h}</div>`).join('')}</div>
|
||
`
|
||
document.getElementById('modalOverlay').classList.add('open')
|
||
}
|
||
function closeModal(){document.getElementById('modalOverlay').classList.remove('open')}
|
||
|
||
function navTo(page,filter='',secFilter='',statusFilter=''){
|
||
document.querySelectorAll('.sidebar nav a').forEach(a=>a.classList.remove('active'))
|
||
document.querySelector(`[data-page="${page}"]`)?.classList.add('active')
|
||
let content
|
||
switch(page){
|
||
case 'dashboard': content=pageDashboard(); break
|
||
case 'register': content=pageRegister(filter,secFilter,statusFilter); break
|
||
case 'analytics': content=pageAnalytics(); break
|
||
case 'reports': content=pageReports(); break
|
||
case 'risks': content=pageRisks(); break
|
||
default: content=pageDashboard()
|
||
}
|
||
document.getElementById('mainContent').innerHTML=content
|
||
}
|
||
function refreshPage(page,filter,secFilter,statusFilter){navTo(page,filter,secFilter,statusFilter)}
|
||
document.querySelectorAll('.sidebar nav a').forEach(a=>a.addEventListener('click',e=>{e.preventDefault();navTo(a.dataset.page)}))
|
||
document.getElementById('modalOverlay').addEventListener('click',function(e){if(e.target===this)closeModal()})
|
||
document.addEventListener('keydown',e=>{if(e.key==='Escape')closeModal()})
|
||
navTo('dashboard')
|
||
</script>
|
||
</body>
|
||
</html> |