Полная переработка без Chart.js — чистая статика

This commit is contained in:
Dauren777 2026-06-04 12:11:59 +00:00
parent 8de0864b6b
commit 82d0fe1161

280
app.html
View File

@ -4,175 +4,167 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ПАБ — Система</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
<style>
:root{--ink:#0F1218;--cyan:#00B4D8;--cl:#48CAE4;--white:#fff;--g5:#5B6573;--g1:#F2F4F7;--g2:#E2E6EB;--red:#E63946;--green:#2D6A4F;--orange:#E76F51;--r:8px;--rl:14px;--sh:0 2px 12px rgba(0,0,0,.06)}
*{box-sizing:border-box;margin:0;padding:0}
body{font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,system-ui,sans-serif;color:var(--ink);background:var(--g1);min-height:100vh}
.ah{background:var(--ink);color:var(--white);padding:0 24px;display:flex;align-items:center;justify-content:space-between;height:56px;position:sticky;top:0;z-index:100}
.ah .la{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px}
.ah nav{display:flex;gap:4px}
.ah nav a{color:#9aa3b2;text-decoration:none;padding:7px 14px;border-radius:var(--r);font-size:13px;font-weight:600;transition:all .2s;cursor:pointer}
.ah nav a:hover,.ah nav a.ac{color:var(--white);background:rgba(255,255,255,.08)}
.ah .ua{display:flex;align-items:center;gap:10px;font-size:13px}
.ah .ua .role{color:var(--cl);font-weight:600}
body{font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#0F1218;background:#F2F4F7;min-height:100vh}
.ah{background:#0F1218;color:#fff;padding:0 24px;display:flex;align-items:center;justify-content:space-between;height:56px;position:sticky;top:0;z-index:100}
.ah nav a{color:#9aa3b2;text-decoration:none;padding:7px 14px;border-radius:8px;font-size:13px;font-weight:600;cursor:pointer}.ah nav a.ac,.ah nav a:hover{color:#fff;background:rgba(255,255,255,.08)}
.acont{max-width:1140px;margin:0 auto;padding:24px}
.pn{display:none}.pn.ac{display:block}
.fg{margin-bottom:14px}.fg label{display:block;font-size:11px;font-weight:700;color:var(--g5);margin-bottom:4px;text-transform:uppercase}
.fg input,.fg select,.fg textarea{width:100%;padding:9px 10px;border:2px solid var(--g2);border-radius:var(--r);font-size:13px;font-family:inherit;outline:none}
.fg input:focus,.fg select:focus,.fg textarea:focus{border-color:var(--cyan)}
.ph{margin-bottom:20px}.ph h2{font-size:26px;font-weight:800}
.card{background:#fff;border-radius:14px;padding:20px;box-shadow:0 2px 12px rgba(0,0,0,.06);margin-bottom:14px}
.card h3{font-size:16px;font-weight:700;margin-bottom:10px}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px;margin-bottom:14px}
.st{background:#fff;border-radius:14px;padding:16px;box-shadow:0 2px 12px rgba(0,0,0,.06);text-align:center}
.st .n{font-size:30px;font-weight:800}.st .l{font-size:11px;color:#5B6573;text-transform:uppercase;margin-top:4px}
.gr .n{color:#2D6A4F}.rd .n{color:#E63946}.bl .n{color:#00B4D8}
.btn{display:inline-flex;align-items:center;gap:6px;padding:9px 18px;border-radius:8px;font-size:13px;font-weight:700;border:none;cursor:pointer;font-family:inherit}
.bp{background:#00B4D8;color:#fff}.bo{background:transparent;border:2px solid #E2E6EB;color:#0F1218}.bd{background:#E63946;color:#fff}
table{width:100%;border-collapse:collapse;font-size:13px;background:#fff;border-radius:14px;overflow:hidden}
th{background:#0F1218;color:#fff;padding:10px 12px;text-align:left;font-size:11px;text-transform:uppercase}
td{padding:8px 12px;border-bottom:1px solid #F2F4F7}tr:hover td{background:#F2F4F7}
.badge{display:inline-block;padding:2px 8px;border-radius:20px;font-size:10px;font-weight:700}
.bs{background:#EDF7F0;color:#2D6A4F}.bd2{background:#FFEBED;color:#E63946}.bw{background:#FFF3EF;color:#E76F51}
.fg{margin-bottom:12px}.fg label{display:block;font-size:11px;font-weight:700;color:#5B6573;margin-bottom:3px;text-transform:uppercase}
.fg input,.fg select,.fg textarea{width:100%;padding:9px 10px;border:2px solid #E2E6EB;border-radius:8px;font-size:13px;font-family:inherit;outline:none}
.fg input:focus,.fg select:focus,.fg textarea:focus{border-color:#00B4D8}
.fg textarea{resize:vertical;min-height:60px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:10px 20px;border-radius:var(--r);font-size:14px;font-weight:700;border:none;cursor:pointer;font-family:inherit;transition:all .2s;white-space:nowrap;text-decoration:none}
.bp{background:var(--cyan);color:var(--white)}.bp:hover{background:var(--cl)}
.bd{background:var(--red);color:var(--white)}.bd:hover{background:#c1121f}
.bo{background:transparent;color:var(--ink);border:2px solid var(--g2)}.bo:hover{border-color:var(--cyan);color:var(--cyan)}
.bs{padding:6px 14px;font-size:12px}
.fh{background:var(--white);border-radius:var(--rl);padding:24px 28px;box-shadow:var(--sh);margin-bottom:16px}
.fh h3{font-size:17px;font-weight:700;margin-bottom:16px}
.hg{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px}.hg.c2{grid-template-columns:1fr 1fr}.hg.c4{grid-template-columns:1fr 1fr 1fr 1fr}
.hg .fg label{font-size:11px;font-weight:700;color:var(--g5);display:block;margin-bottom:3px;text-transform:uppercase}
.hg .fg input,.hg .fg select{width:100%;padding:8px 10px;border:2px solid var(--g2);border-radius:var(--r);font-size:13px;font-family:inherit;outline:none;background:var(--white)}.hg .fg input:focus,.hg .fg select:focus{border-color:var(--cyan)}
.ot{display:flex;gap:12px;margin-top:12px}.tb{flex:1;padding:10px;border:2px solid var(--g2);border-radius:var(--r);text-align:center;cursor:pointer;font-size:13px;font-weight:700;background:var(--white);transition:all .2s}
.tb.sel{border-color:var(--green);background:#EDF7F0;color:var(--green)}.tb.dng.sel{border-color:var(--red);background:#FFEBED;color:var(--red)}.tb.dng{color:#5B6573}
.cs{background:var(--white);border-radius:var(--rl);box-shadow:var(--sh);margin-bottom:12px;overflow:hidden}
.ch{display:flex;align-items:center;justify-content:space-between;padding:14px 20px;background:var(--g1);cursor:pointer;user-select:none}
.ch .ct{font-size:15px;font-weight:700}
.cbody{padding:16px 20px}
.cl2{display:grid;grid-template-columns:1fr 1fr;gap:6px 24px}.cl2.c3{grid-template-columns:1fr 1fr 1fr}.cl2.c1{grid-template-columns:1fr}
.ci{display:flex;align-items:flex-start;gap:8px;padding:6px 0;font-size:13px;cursor:pointer}
.ci input[type=checkbox]{margin-top:2px;width:16px;height:16px;accent-color:var(--red);cursor:pointer;flex-shrink:0}
.ci.ck label{color:var(--red);font-weight:600}.ci label{cursor:pointer;flex:1}
.ci .oi{width:100%;margin-top:4px;padding:6px 8px;border:1px solid var(--g2);border-radius:4px;font-size:12px;display:none}.ci.ck .oi.vs{display:block}
.cf{display:flex;align-items:center;justify-content:space-between;padding:10px 20px;background:var(--g1);border-top:1px solid var(--g2);font-size:12px;color:var(--g5);font-weight:600}
.cf .tc{color:var(--red);font-weight:700}.cf .tc.zr{color:var(--green)}
.ast{display:flex;align-items:center;gap:6px;cursor:pointer;font-size:12px;font-weight:700;padding:4px 12px;border-radius:20px;transition:all .2s}.ast.ac2{background:#EDF7F0;color:var(--green)}.ast input{display:none}
.vb{background:var(--white);border-radius:var(--rl);padding:20px 24px;box-shadow:var(--sh);margin-top:16px}
.vb h3{font-size:15px;font-weight:700;margin-bottom:14px}
.vg{display:grid;grid-template-columns:40px 1.3fr 1fr .8fr 1fr 1fr 1fr .8fr 30px;gap:6px;margin-bottom:6px;align-items:end}
.vg.hr{font-size:11px;font-weight:700;color:var(--g5);text-transform:uppercase;margin-bottom:4px}
.vg input,.vg select{padding:7px 8px;border:1px solid var(--g2);border-radius:var(--r);font-size:12px;font-family:inherit;outline:none;width:100%}.vg input:focus,.vg select:focus{border-color:var(--cyan)}
.vrn{font-size:12px;font-weight:700;color:var(--g5);text-align:center;padding-top:8px}.rvb{background:0;border:none;color:var(--red);cursor:pointer;font-size:18px;padding:4px}
.fa2{display:flex;gap:10px;margin-top:20px}.fs{background:#EDF7F0;border:2px solid var(--green);border-radius:var(--r);padding:24px 28px;color:var(--green);font-weight:600;margin-top:14px;display:none;animation:fadeIn .3s ease;text-align:center}@keyframes fadeIn{from{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}
.sg{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;margin-bottom:24px}.sc{background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)}
.sc .sl{font-size:12px;font-weight:700;color:var(--g5);text-transform:uppercase;margin-bottom:4px}.sc .sv{font-size:32px;font-weight:800;line-height:1}
.gr .sv{color:var(--green)}.rd .sv{color:var(--red)}.bl .sv{color:var(--cyan)}.or .sv{color:var(--orange)}
.cg{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:16px;margin-bottom:16px}.cc{background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)}.cc h3{font-size:15px;font-weight:700;margin-bottom:14px}.cc canvas{max-height:260px}
.fb{display:flex;gap:10px;margin-bottom:20px;flex-wrap:wrap;align-items:center}.fb select,.fb input{padding:8px 12px;border:2px solid var(--g2);border-radius:var(--r);font-size:13px;font-family:inherit;outline:none;background:var(--white)}.fb select:focus,.fb input:focus{border-color:var(--cyan)}
.tw{overflow-x:auto}.dt{width:100%;border-collapse:collapse;background:var(--white);border-radius:var(--rl);overflow:hidden;box-shadow:var(--sh);font-size:13px}
.dt th{background:var(--ink);color:var(--white);padding:11px 14px;text-align:left;font-size:12px;font-weight:700;text-transform:uppercase}
.dt td{padding:10px 14px;border-bottom:1px solid var(--g1)}.dt tr:hover td{background:var(--g1)}
.badge{display:inline-block;padding:3px 10px;border-radius:20px;font-size:11px;font-weight:700}.badge-s{background:#EDF7F0;color:var(--green)}.badge-d{background:#FFEBED;color:var(--red)}.badge-w{background:#FFF3EF;color:var(--orange)}
.nd{text-align:center;padding:40px 20px;color:var(--g5);font-size:15px}
.rb{display:flex;height:20px;border-radius:10px;overflow:hidden;margin-top:6px}.rs{background:var(--green);transition:width .5s}.ru{background:var(--red);transition:width .5s}
.rl2{display:flex;justify-content:space-between;font-size:11px;color:var(--g5);margin-top:3px}
.vl{color:var(--cyan);cursor:pointer;font-weight:600}.vl:hover{text-decoration:underline}
.sa{background:#FFF3EF;border:1px solid var(--orange);border-radius:var(--rl);padding:16px 20px;margin-bottom:20px;display:none}.sa.sh{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px}
.sa .at{font-size:14px;font-weight:600;color:var(--orange)}.sa.dg{background:#FFEBED;border-color:var(--red)}.sa.dg .at{color:var(--red)}
@media(max-width:768px){.ah{padding:0 12px;height:auto;flex-wrap:wrap;gap:6px;padding-top:8px;padding-bottom:8px}.ah nav{order:3;width:100%;overflow-x:auto}.acont{padding:16px 12px}.hg{grid-template-columns:1fr 1fr}.hg.c4{grid-template-columns:1fr 1fr}.cl2{grid-template-columns:1fr}.cl2.c3{grid-template-columns:1fr 1fr}.cg{grid-template-columns:1fr}.sg{grid-template-columns:1fr 1fr}.vg{grid-template-columns:30px 1fr 1fr;row-gap:4px}.vg.hr{display:none}}
.hg{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}.hg.c2{grid-template-columns:1fr 1fr}
.ci{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:13px}
.ci input[type=checkbox]{margin-top:2px;width:15px;height:15px;accent-color:#E63946;cursor:pointer;flex-shrink:0}
.ci.ck label{color:#E63946;font-weight:600}
.ot{display:flex;gap:10px;margin-top:10px}
.tb{flex:1;padding:10px;border:2px solid #E2E6EB;border-radius:8px;text-align:center;cursor:pointer;font-size:13px;font-weight:700}
.tb.sf{background:#EDF7F0;border-color:#2D6A4F;color:#2D6A4F}
.tb.df{background:#FFEBED;border-color:#E63946;color:#E63946}
.fs{background:#EDF7F0;border:2px solid #2D6A4F;border-radius:8px;padding:20px;color:#2D6A4F;font-weight:600;margin-top:14px;display:none;text-align:center}
@media(max-width:768px){.ah{padding:0 10px;flex-wrap:wrap;height:auto;padding-top:8px}.ah nav{width:100%;overflow-x:auto}.acont{padding:12px}.hg{grid-template-columns:1fr 1fr}.stats{grid-template-columns:1fr 1fr}}
</style>
</head>
<body>
<header class="ah"><div class="la">🛡️ ПАБ Система</div><nav><a onclick="swP('NA')" class="ac">Новый аудит</a><a onclick="swP('MS')">Мой график</a><a onclick="swP('DB')">Дашборд</a><a onclick="swP('VL')">Нарушения</a><a onclick="swP('HS')">История</a></nav><div class="ua"><span class="role" id="dn"></span><button class="btn bo bs" style="color:#9aa3b2;border-color:#3a4452" onclick="doLogout()">Выход</button></div></header>
<header class="ah"><div style="font-weight:700">🛡️ ПАБ Система</div><nav><a onclick="showPanel('NA')" class="ac">Новый аудит</a><a onclick="showPanel('MS')">Мой график</a><a onclick="showPanel('DB')">Дашборд</a><a onclick="showPanel('VL')">Нарушения</a><a onclick="showPanel('HS')">История</a></nav><span style="font-size:13px"><span id="dn" style="color:#48CAE4;font-weight:600"></span> <button class="btn bo" style="color:#9aa3b2;border-color:#3a4452;font-size:12px;padding:4px 10px" onclick="doLogout()">Выход</button></span></header>
<div class="acont">
<div class="sa" id="sa"><span class="at" id="sat"></span><button class="btn bp bs" onclick="sendScheduleReminder()">✉️ Напомнить</button></div>
<div id="pNA" class="pn ac">
<div style="margin-bottom:24px"><h2 style="font-size:26px;font-weight:800">📋 Бланк ПАБ</h2><p style="color:var(--g5)">Заполните все категории</p></div>
<div class="fh"><h3>📝 Данные аудита</h3>
<div class="hg c4"><div class="fg"><label>Бланк №</label><input type="number" id="pn" min="1"></div><div class="fg"><label>Дата</label><input type="date" id="pd"></div><div class="fg"><label>Начало</label><input type="time" id="ps"></div><div class="fg"><label>Конец</label><input type="time" id="pe"></div></div>
<div class="hg" style="margin-top:12px"><div class="fg"><label>Место</label><input id="pl" placeholder="Цех, участок"></div><div class="fg"><label>Тип работы</label><input id="pw" placeholder="Ремонт линий связи"></div><div class="fg"><label>Регион</label><select id="pr"><option value="">-- Выберите --</option><option>Центральный</option><option>Алматинский</option><option>Восточный</option><option>Западный</option><option>Северный</option><option>Южный</option><option>Другое</option></select></div></div>
<div class="hg" style="margin-top:12px"><div class="fg"><label>Кол-во наблюдаемых</label><input type="number" id="pc" min="1" value="1"></div><div class="fg"></div><div class="fg"></div></div>
<div class="hg c2" style="margin-top:12px"><div class="fg"><label>ФИО наблюдателя</label><input id="po"></div><div class="fg"><label>Должность</label><input id="por"></div></div>
<div class="hg c2" style="margin-top:12px"><div class="fg"><label>ФИО руководителя</label><input id="psv"></div><div class="fg"><label>Должность</label><input id="psr"></div></div>
<div class="hg" style="margin-top:12px"><div class="fg"><label>Email</label><input type="email" id="pem"></div><div class="fg"></div><div class="fg"></div></div>
<div class="fg" style="margin-top:14px"><label>Отметка БиОТ ДПБ</label><div class="ot"><div class="tb sel" id="os" onclick="setO('safe')">ВСЕ БЕЗОПАСНО</div><div class="tb dng" id="od" onclick="setO('danger')">ЕСТЬ ОПАСНО</div></div></div></div>
<div id="cats"></div>
<div class="vb"><h3>📄 Несоответствия и меры</h3><div class="vg hr" style="display:grid"><span></span><span>Несоответствие</span><span>Исполнитель</span><span>Вид</span><span>Меры</span><span>Ответственный</span><span>Дата</span><span>Завершение</span><span></span></div><div id="vr"></div><button class="btn bo bs" onclick="addVio()" style="margin-top:8px">+ Добавить</button></div>
<div class="vb"><h3>💬 Итог диалога</h3><p style="font-size:12px;color:var(--g5);margin-bottom:14px">Результаты беседы</p><div class="cl2 c1"><div class="ci"><input type="checkbox" id="d0"><div><label for="d0">Работник привёл примеры безопасных действий</label></div></div><div class="ci"><input type="checkbox" id="d1"><div><label for="d1">Были обсуждены риски / проблемы</label></div></div><div class="ci"><input type="checkbox" id="d2"><div><label for="d2">Определены корректирующие меры</label></div></div><div class="ci"><input type="checkbox" id="d3"><div><label for="d3">Предложения работника зафиксированы</label></div></div><div class="ci"><input type="checkbox" id="d4"><div><label for="d4">Другое</label><input class="oi" id="do" placeholder="Укажите..."></div></div></div><div class="vb"><h3>📎 Фото и документы</h3><div class="fg"><label>Ссылки на документы (Google Drive, SharePoint и др.)</label><textarea id="pdoc" placeholder="Вставьте ссылки на фото, сканы документов, протоколы..."></textarea></div><div class="fg"><label>Прикрепить файлы с компьютера</label><input type="file" id="pfiles" multiple accept="image/*,.pdf,.doc,.docx" onchange="showFileNames()" style="padding:8px"><div id="fileNames" style="font-size:12px;color:var(--g5);margin-top:6px"></div></div></div>
<div class="fa2"><button class="btn bp" onclick="submitAudit()">💾 Сохранить</button><button class="btn bo" onclick="resetF()">🗑️ Очистить</button></div>
<div class="fs" id="fs"><div style="font-size:28px;margin-bottom:6px"></div><div style="font-size:18px;font-weight:800;margin-bottom:8px">Аудит успешно отправлен!</div><div id="sd" style="font-size:14px;color:var(--ink);margin-bottom:14px"></div><div style="display:flex;gap:10px;flex-wrap:wrap;justify-content:center"><button class="btn bo bs" onclick="printConfirm()">🖨️ Распечатать</button></div></div>
<div id="pnNA" class="pn ac">
<div class="ph"><h2>📋 Бланк ПАБ</h2></div>
<div class="card"><h3>📝 Данные аудита</h3>
<div class="hg"><div class="fg"><label>Бланк №</label><input type="number" id="pn"></div><div class="fg"><label>Дата</label><input type="date" id="pd"></div><div class="fg"><label>Регион</label><select id="pr"><option value="">--</option><option>Центральный</option><option>Алматинский</option><option>Восточный</option><option>Западный</option><option>Северный</option><option>Южный</option></select></div></div>
<div class="hg"><div class="fg"><label>Место</label><input id="pl"></div><div class="fg"><label>Тип работы</label><input id="pw"></div><div class="fg"><label>Кол-во наблюдаемых</label><input type="number" id="pc" value="1"></div></div>
<div class="hg c2"><div class="fg"><label>ФИО наблюдателя</label><input id="po"></div><div class="fg"><label>Должность</label><input id="por"></div></div>
<div class="fg"><label>Отметка</label><div class="ot"><div class="tb sf" id="os" onclick="setO('safe')">ВСЕ БЕЗОПАСНО</div><div class="tb" id="od" onclick="setO('danger')">⚠️ ЕСТЬ ОПАСНО</div></div></div></div>
<div class="card"><h3>📄 Категории наблюдения</h3><div id="cats"></div></div>
<div class="card"><h3>💬 Итог диалога</h3>
<div class="ci"><input type="checkbox" id="d0"><label for="d0">Работник привёл примеры безопасных действий</label></div>
<div class="ci"><input type="checkbox" id="d1"><label for="d1">Были обсуждены риски / проблемы</label></div>
<div class="ci"><input type="checkbox" id="d2"><label for="d2">Определены корректирующие меры</label></div>
<div class="ci"><input type="checkbox" id="d3"><label for="d3">Предложения работника зафиксированы</label></div>
</div>
<div id="pMS" class="pn"><div style="margin-bottom:24px"><h2 style="font-size:26px;font-weight:800">📅 Мой график</h2><p style="color:var(--g5)">Выполнение норматива</p></div><div id="msc"></div></div>
<div id="pDB" class="pn"><div style="margin-bottom:24px"><h2 style="font-size:26px;font-weight:800">📊 Дашборд</h2><p style="color:var(--g5)">Аналитика</p></div><div id="dbc"></div></div>
<div id="pVL" class="pn"><div style="margin-bottom:24px"><h2 style="font-size:26px;font-weight:800">⚠️ Несоответствия</h2><p style="color:var(--g5)">Контроль мер</p></div><div id="vlc"></div></div>
<div id="pHS" class="pn"><div style="margin-bottom:24px"><h2 style="font-size:26px;font-weight:800">📁 История</h2><p style="color:var(--g5)">Архив аудитов</p></div><div class="fb"><select onchange="rHT()" id="hfs"><option value="all">Все</option><option value="safe">Безопасно</option><option value="danger">С нарушениями</option></select><input type="date" id="hfd" onchange="rHT()"><input type="text" id="hfl" oninput="rHT()" placeholder="Поиск..."><button class="btn bo bs" onclick="exportCSV()">📥 CSV</button></div><div class="tw"><table class="dt"><thead><tr><th>Бланк №</th><th>Дата</th><th>Время</th><th>Место</th><th>Наблюдатель</th><th>Статус</th><th>Нарушений</th><th></th></tr></thead><tbody id="hbd"></tbody></table></div></div>
<button class="btn bp" onclick="submitAudit()" style="margin-right:10px">💾 Сохранить аудит</button><button class="btn bo" onclick="resetF()">🗑️ Очистить</button>
<div class="fs" id="fs"><div style="font-size:24px"></div><div style="font-size:16px;font-weight:800">Аудит успешно отправлен!</div><div id="sd" style="font-size:13px;color:#0F1218;margin-top:8px"></div></div>
</div>
<div id="pnMS" class="pn">
<div class="ph"><h2>📅 Мой график</h2></div><div id="msc">Загрузка...</div>
</div>
<div id="pnDB" class="pn">
<div class="ph"><h2>📊 Дашборд</h2></div><div id="dbc">Загрузка...</div>
</div>
<div id="pnVL" class="pn">
<div class="ph"><h2>⚠️ Несоответствия</h2></div><div id="vlc">Загрузка...</div>
</div>
<div id="pnHS" class="pn">
<div class="ph"><h2>📁 История</h2></div>
<button class="btn bo" onclick="exportCSV()" style="margin-bottom:10px">📥 CSV</button>
<table><thead><tr><th>Бланк</th><th>Дата</th><th>Место</th><th>Наблюдатель</th><th>Статус</th><th>Нарушений</th><th></th></tr></thead><tbody id="hbd"><tr><td colspan="7" style="text-align:center;padding:20px;color:#5B6573">Нет записей</td></tr></tbody></table>
</div>
</div>
<script>
var CATS=[{id:"reaction",title:"1. Реакция работника",items:["Приводит в порядок СИЗ","Меняет положение","Перестраивает работу","Прекращает работу","Наклоняется, прячется","Меняет инструмент","Подсоединяет или устанавливает необходимые защитные устройства","Другое"]},{id:"posture",title:"2. Положение/поза работника",items:["Столкновения и удары","Защемление предметом","Падение","Повторяющиеся движения","Статичные позы","Другое"]},{id:"ppe",title:"3. Отсутствие СИЗ",items:["Голова (каски, подшлемник и т.д.)","Уши (беруши, наушники)","Глаза и лицо (щитки, очки, маски и т.д.)","Органы дыхания (противогазы, респираторы, маски и т.п.)","Руки (перчатки, рукавицы и т.д.)","Тела (спецодежда, фартук, страховочный пояс)","Ноги (спец обувь)","Другое"]},{id:"tools",title:"4. Инструменты и оборудование",items:["Используется самодельный инструмент","Инструменты в ненадлежащем состоянии","Инструменты используются не по назначению","Оборудование находится в ненадлежащем состоянии","Лестницы и стремянки отсутствуют, используются неправильно или находятся в ненадлежащем состоянии","Ограждения отсутствуют, используются неправильно или находятся в ненадлежащем состоянии","Переносное освещение находится в ненадлежащем состоянии","Другое"]},{id:"rules",title:"5. Инструкции и правила",items:["Отсутствие наряда","Инструкции не соответствуют выполняемым работам","Требования инструкций и/или правил безопасности не соблюдаются","Инструктажи не проведены","В недостаточной степени прописаны и выполнены технические мероприятия","В недостаточной степени выполнены подготовка рабочего места и допуск","В недостаточной степени заполнен наряд","Отсутствие удостоверения у работника","Неприменение СИЗ при их наличии во время аудита","Другое"]},{id:"conditions",title:"6. Условия на рабочем месте",items:["Шум","Освещенность","Пыль","Задымленность","Беспорядок на рабочем месте","Загромождение путей прохода","Нерациональное размещение инструментов, приборов, оборудования","Повышенная температура/Пониженная температура","Другое"]},{id:"transport",title:"7. Транспорт",items:["Ремни безопасности отсутствуют, неисправны или не используются","Опасный стиль вождения","Состояние водителя не соответствует требованиям","Использование мобильного средства связи во время движения","Несоблюдение правил дорожного движения","Состояние транспортного средства не соответствует требованиям безопасности","Другое"]}];
var PQ={"Директор департамента ЦА":{c:1,p:"halfyear",l:"1 раз в полгода"},"Директор департамента филиала":{c:1,p:"halfyear",l:"1 раз в полгода"},"Региональный директор филиала":{c:1,p:"quarter",l:"1 раз в квартал"},"Директор ДЭСД":{c:1,p:"quarter",l:"1 раз в квартал"},"Начальник ТУСМ":{c:1,p:"quarter",l:"1 раз в квартал"},"Руководитель структурного подразделения":{c:1,p:"quarter",l:"1 раз в квартал"},"Начальник центра/службы/цеха":{c:1,p:"month",l:"1 раз в месяц"},"Начальник участка":{c:2,p:"month",l:"2 раза в месяц"},"Инженер БиОТ":{c:1,p:"month",l:"1 раз в месяц"},"Работник отдела БиОТ":{c:1,p:"month",l:"1 раз в месяц"},"Аудитор":{c:1,p:"month",l:"1 раз в месяц"},"Бригадир":{c:1,p:"month",l:"1 раз в месяц"},"Руководитель":{c:1,p:"quarter",l:"1 раз в квартал"},"Работник":{c:1,p:"quarter",l:"1 раз в квартал"}};
var U,editId,charts={},lastSubmitted,vrc=6;
var U,editId,lastSubmitted,vrc=6;
try{U=JSON.parse(sessionStorage.getItem("pab_user"));if(!U)location.href="index.html"}catch(e){location.href="index.html"}
document.getElementById("dn").textContent=U.login+" ("+U.role+")";
function isA(){return U&&U.login==="admin"}function getU(){try{return JSON.parse(localStorage.getItem("pab_users")||"{}")}catch(e){return{}}}function allU(){var r=getU();r.admin={pass:"admin",name:"Администратор",role:"Руководитель",email:"admin@telecom.kz",branch:"АО «Казахтелеком»",dept:"ЦА",region:"Центральный",oblast:"—",city:"г. Астана"};return r}function getA(){try{return JSON.parse(localStorage.getItem("pab_audits")||"[]")}catch(e){return[]}}function saveA(d){localStorage.setItem("pab_audits",JSON.stringify(d))}function gq(r){return PQ[r]||{c:1,p:"month",l:"1 раз в месяц"}}
function getUserQuota(user){
if(user.freq){
var parts=user.freq.split(",");
if(parts.length===2){
var c=parseInt(parts[0]),p=parts[1],pl={month:"месяц",quarter:"квартал",halfyear:"полгода"};
var l=c+" раз(а) в "+ (pl[p]||p);
return{c:c,p:p,l:l};
}
}
return gq(user.role);
}function gp(p){var n=new Date();if(p==="month")return{s:new Date(n.getFullYear(),n.getMonth(),1),l:n.toLocaleString("ru",{month:"long",year:"numeric"})};if(p==="quarter"){var q=Math.floor(n.getMonth()/3);return{s:new Date(n.getFullYear(),q*3,1),l:(q+1)+"-й квартал "+n.getFullYear()}}if(p==="halfyear"){var h=n.getMonth()<6?0:1;return{s:new Date(n.getFullYear(),h*6,1),l:(h+1)+"-е полугодие "+n.getFullYear()}}return{s:new Date(2020,0,1),l:"весь период"}}function esc(s){return(s||"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
document.getElementById("dn").textContent=U.login;
function isA(){return U&&U.login==="admin"}
function getU(){try{return JSON.parse(localStorage.getItem("pab_users")||"{}")}catch(e){return{}}}
function allU(){var r=getU();r.admin={pass:"admin",name:"Администратор",role:"Руководитель",email:"admin@telecom.kz",branch:"АО «Казахтелеком»",dept:"ЦА",region:"Центральный",oblast:"—",city:"г. Астана"};return r}
function getA(){try{return JSON.parse(localStorage.getItem("pab_audits")||"[]")}catch(e){return[]}}
function saveA(d){localStorage.setItem("pab_audits",JSON.stringify(d))}
function gq(role){var q={c:1,p:"month",l:"1 раз в месяц"};return q}
function getUserQuota(u){if(u.freq){var p=u.freq.split(",");if(p.length===2)return{c:parseInt(p[0]),p:p[1],l:parseInt(p[0])+" раз(а) в "+(p[1]==="month"?"месяц":p[1]==="quarter"?"квартал":"полгода")}}return gq(u.role)}
function gp(p){var n=new Date();if(p==="month")return{s:new Date(n.getFullYear(),n.getMonth(),1),l:n.toLocaleString("ru",{month:"long",year:"numeric"})};if(p==="quarter"){var q=Math.floor(n.getMonth()/3);return{s:new Date(n.getFullYear(),q*3,1),l:(q+1)+"-й квартал "+n.getFullYear()}}return{s:new Date(n.getFullYear(),n.getMonth()<6?0:6,1),l:(n.getMonth()<6?1:2)+"-е полугодие "+n.getFullYear()}}
function swP(n){
["NA","MS","DB","VL","HS"].forEach(function(id){var el=document.getElementById("p"+id);if(el)el.classList.remove("ac")});
var panel=document.getElementById("p"+n);if(panel)panel.classList.add("ac");
document.querySelectorAll("nav a").forEach(function(a){var dp=a.getAttribute("onclick")||"";a.classList.toggle("ac",dp.indexOf("'"+n+"'")>=0)});
if(n==="MS")rMS();if(n==="DB")rDB();if(n==="VL")rVL();if(n==="HS")rHT();if(n==="NA")checkSA()
var CATS=[{id:"reaction",title:"1. Реакция работника",items:["Приводит в порядок СИЗ","Меняет положение","Перестраивает работу","Прекращает работу","Наклоняется, прячется","Меняет инструмент","Подсоединяет защитные устройства","Другое"]},{id:"posture",title:"2. Поза работника",items:["Столкновения и удары","Защемление","Падение","Повторяющиеся движения","Статичные позы","Другое"]},{id:"ppe",title:"3. Отсутствие СИЗ",items:["Голова (каски)","Уши (беруши)","Глаза и лицо (очки)","Органы дыхания","Руки (перчатки)","Тела (спецодежда)","Ноги (обувь)","Другое"]},{id:"tools",title:"4. Инструменты и оборудование",items:["Самодельный инструмент","Ненадлежащее состояние","Не по назначению","Оборудование в плохом состоянии","Лестницы/стремянки","Ограждения","Переносное освещение","Другое"]},{id:"rules",title:"5. Инструкции и правила",items:["Отсутствие наряда","Инструкции не соответствуют","Требования не соблюдаются","Инструктажи не проведены","Тех. мероприятия не выполнены","Подготовка места не выполнена","Наряд не заполнен","Нет удостоверения","Неприменение СИЗ","Другое"]},{id:"conditions",title:"6. Условия труда",items:["Шум","Освещенность","Пыль","Задымленность","Беспорядок","Загромождение проходов","Нерациональное размещение","Температура","Другое"]},{id:"transport",title:"7. Транспорт",items:["Ремни безопасности","Опасное вождение","Состояние водителя","Телефон за рулём","Нарушение ПДД","Состояние ТС","Другое"]}];
// Build categories
var ch="";CATS.forEach(function(c){ch+="<div style=\"border:1px solid #E2E6EB;border-radius:8px;margin-bottom:8px;padding:12px;background:#F2F4F7\"><b>"+c.title+"</b><br>"+c.items.map(function(it,i){return"<div class=\"ci\"><input type=\"checkbox\" id=\"cb-"+c.id+"-"+i+"\" onchange=\"updateCT('"+c.id+"')\"><label for=\"cb-"+c.id+"-"+i+"\">"+it+"</label></div>"}).join("")+"<div style=\"margin-top:6px;font-size:12px;color:#5B6573\">Отмечено: <b id=\"cnt-"+c.id+"\">0</b></div></div>"});document.getElementById("cats").innerHTML=ch;
function updateCT(id){var cnt=0;CATS.find(function(c){return c.id===id}).items.forEach(function(_,i){if(document.getElementById("cb-"+id+"-"+i)&&document.getElementById("cb-"+id+"-"+i).checked)cnt++});document.getElementById("cnt-"+id).textContent=cnt}
function setO(t){var os=document.getElementById("os"),od=document.getElementById("od");os.className="tb"+(t==="safe"?" sf":"");od.className="tb"+(t==="danger"?" df":"")}
// Init form
document.getElementById("pd").value=new Date().toISOString().split("T")[0];
document.getElementById("po").value=U.name;document.getElementById("por").value=U.role||"";
document.getElementById("pr").value=U.region||"";
function showPanel(n){
["NA","MS","DB","VL","HS"].forEach(function(id){document.getElementById("pn"+id).classList.remove("ac")});
document.getElementById("pn"+n).classList.add("ac");
document.querySelectorAll("nav a").forEach(function(a){a.classList.toggle("ac",a.getAttribute("onclick").indexOf("'"+n+"'")>=0)});
if(n==="MS")rMS();if(n==="DB")rDB();if(n==="VL")rVL();if(n==="HS")rHS();
}
function doLogout(){sessionStorage.removeItem("pab_user");location.href="index.html"}
// ===== BUILD CATS =====
var catsHTML="";CATS.forEach(function(c){var col=c.items.length>7?"c3":(c.items.length<=4?"c1":"");catsHTML+="<div class=\"cs\"><div class=\"ch\" onclick=\"var b=document.getElementById('body-"+c.id+"');b.style.display=b.style.display==='none'?'block':'none'\"><span class=\"ct\">"+c.title+"</span><span class=\"cb2 as\" id=\"badge-"+c.id+"\">ВСЕ БЕЗОПАСНО</span></div><div class=\"cbody\" id=\"body-"+c.id+"\" style=\"display:block\"><div class=\"ast ac2\" id=\"as-"+c.id+"\" onclick=\"toggleAllSafe('"+c.id+"')\"><input type=\"checkbox\" checked id=\"ascb-"+c.id+"\">ВСЕ БЕЗОПАСНО</div><div class=\"cl2 "+col+"\">"+c.items.map(function(it,i){return"<div class=\"ci\" id=\"item-"+c.id+"-"+i+"\"><input type=\"checkbox\" id=\"cb-"+c.id+"-"+i+"\" onchange=\"onCheckItem('"+c.id+"',"+i+")\"><div><label for=\"cb-"+c.id+"-"+i+"\">"+it+"</label>"+(it==="Другое"?"<input class=\"oi\" id=\"other-"+c.id+"\" placeholder=\"Укажите...\">":"")+"</div></div>"}).join("")+"</div></div><div class=\"cf\"><span>Итого: <span class=\"tc zr\" id=\"total-"+c.id+"\">0</span></span></div></div>"});document.getElementById("cats").innerHTML=catsHTML;
function rMS(){
var c=document.getElementById("msc");if(!c)return;
if(isA()){
var all=allU();var rows="",wc=0;
for(var k in all){if(k==="admin")continue;wc++;var u=all[k];var q=getUserQuota(u);var p=gp(q.p);var d=getA().filter(function(a){return a.createdBy===k&&new Date(a.date)>=p.s}).length;var pct=Math.round(d/q.c*100);var st=d>q.c?"🔵 +"+(d-q.c):d>=q.c?"🟢 OK":"🔴 -"+(q.c-d);rows+="<tr><td>"+u.name+"</td><td>"+u.role+"</td><td>"+(u.branch||"—")+"</td><td>"+(u.region||"—")+"</td><td>"+q.l+"</td><td>"+d+"/"+q.c+"</td><td>"+st+"</td><td>"+p.l+"</td></tr>"}
c.innerHTML=wc===0?"<div class=\"card\"><h3>👥 График работников</h3><p style=\"color:#5B6573\">Нет зарегистрированных работников. Зарегистрируйте их на странице входа.</p></div>":"<div class=\"card\"><h3>👥 График всех работников</h3></div><table><thead><tr><th>ФИО</th><th>Должность</th><th>Филиал</th><th>Регион</th><th>Норма</th><th>Прогресс</th><th>Статус</th><th>Период</th></tr></thead><tbody>"+rows+"</tbody></table>";
return;
}
var q=getUserQuota(U);var p=gp(q.p);var d=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var pct=Math.round(d/q.c*100);var over=d>q.c;var cl=over?"#00B4D8":d>=q.c?"#2D6A4F":d>=q.c/2?"#E76F51":"#E63946";
c.innerHTML="<div class=\"card\"><h3>📅 "+p.l+"</h3><div style=\"font-size:12px;color:#5B6573;margin-bottom:8px\">Минимум: <b>"+q.l+"</b> | "+U.role+"</div><div style=\"height:14px;border-radius:7px;background:#E2E6EB;overflow:hidden;margin-bottom:6px\"><div style=\"height:100%;border-radius:7px;width:"+Math.min(pct,200)+"%;background:"+cl+";transition:width .5s\"></div></div><div style=\"font-size:13px;font-weight:600\">Проведено: <b>"+d+"</b> из <b>"+q.c+"</b>"+(over?" — <span style=\"color:#00B4D8\">✅ +"+(d-q.c)+" сверх плана!</span>":d>=q.c?" — ✅ план выполнен":" — <span style=\"color:#E63946\">осталось "+(q.c-d)+"</span>")+"</div></div><div class=\"card\"><h3>👤 "+U.name+"</h3><div style=\"font-size:13px\">"+U.role+" | "+(U.branch||"—")+" | "+(U.region||"—")+" | "+(U.city||"—")+"</div></div>"+(d>0?"<div class=\"card\"><h3>📋 Последние аудиты</h3>"+getA().filter(function(a){return a.createdBy===U.login}).slice(0,5).map(function(a){return"<div style=\"padding:6px 0;border-bottom:1px solid #F2F4F7;font-size:13px\">"+a.date+" — "+a.location+" — <span class=\"badge "+(a.overallSafe?"bs":"bd2")+"\">"+(a.overallSafe?"Безопасно":"Нарушений: "+a.totalViolations)+"</span></div>"}).join("")+"</div>":"");
}
// ===== VIO =====
var vioHTML="";for(var i=0;i<vrc;i++)vioHTML+=mkV(i+1);document.getElementById("vr").innerHTML=vioHTML;
document.getElementById("vr").onclick=function(e){if(e.target.classList.contains("rvb")){var n=parseInt(e.target.getAttribute("data-row"));removeVR(n)}};
document.getElementById("d4").onchange=function(){var o=document.getElementById("do");o.style.display=this.checked?"block":"none";o.classList.toggle("vs",this.checked)};
function rDB(){
var c=document.getElementById("dbc");if(!c)return;
var a=getA(),all=allU();var t=a.length,sf=a.filter(function(x){return x.overallSafe}).length,wd=a.filter(function(x){return !x.overallSafe}).length,tv=a.reduce(function(s,x){return s+(x.totalViolations||0)},0);
var ot=0,bh=0,ov=0;for(var k in all){if(k==="admin")continue;var u=all[k];var q=getUserQuota(u);if(!q.p)continue;var p=gp(q.p);var d=a.filter(function(x){return x.createdBy===k&&new Date(x.date)>=p.s}).length;if(d>q.c)ov++;else if(d>=q.c)ot++;else bh++}
var adb=isA()?"<div style=\"margin-bottom:12px;display:flex;gap:8px;flex-wrap:wrap\"><button class=\"btn bp\" onclick=\"downloadFullCSV()\">📥 CSV</button><button class=\"btn bo\" onclick=\"showAllUsers()\">👥 Пользователи</button></div>":"";
c.innerHTML=adb+"<div class=\"stats\"><div class=\"st\"><div class=\"n\">"+t+"</div><div class=\"l\">Всего аудитов</div></div><div class=\"st gr\"><div class=\"n\">"+sf+"</div><div class=\"l\">Безопасно</div></div><div class=\"st rd\"><div class=\"n\">"+wd+"</div><div class=\"l\">С нарушениями</div></div><div class=\"st rd\"><div class=\"n\">"+tv+"</div><div class=\"l\">Нарушений</div></div><div class=\"st bl\"><div class=\"n\">"+ov+"</div><div class=\"l\">Перевыполняют</div></div><div class=\"st gr\"><div class=\"n\">"+ot+"</div><div class=\"l\">Выполняют</div></div><div class=\"st rd\"><div class=\"n\">"+bh+"</div><div class=\"l\">Отстают</div></div></div>"+(t>0?"<div class=\"card\"><h3>📂 Нарушения по категориям</h3>"+CATS.map(function(cat){var cnt=a.reduce(function(s,x){var c=x.categories&&x.categories[cat.id];return s+(c?c.items.length:0)},0);return"<div style=\"display:flex;align-items:center;gap:10px;margin-bottom:6px\"><div style=\"width:160px;font-size:12px\">"+cat.title.split(". ")[1]+"</div><div style=\"flex:1;height:10px;background:#E2E6EB;border-radius:5px;overflow:hidden\"><div style=\"height:100%;background:#E63946;border-radius:5px;width:"+Math.min(100,cnt*10)+"%\"></div></div><div style=\"font-size:12px;font-weight:700;width:30px\">"+cnt+"</div></div>"}).join("")+"</div>":"");
}
function showFileNames(){var f=document.getElementById("pfiles");var d=document.getElementById("fileNames");if(!f||!d)return;var names=[];for(var i=0;i<f.files.length;i++)names.push(f.files[i].name);d.textContent=names.length>0?"📄 "+names.join(", "):""}
function rVL(){var c=document.getElementById("vlc");if(!c)return;var a=getA(),td=new Date().toISOString().split("T")[0],av=[];a.forEach(function(x){if(!x.violations)return;x.violations.forEach(function(v){var dd=v.date||"",dn=v.done&&v.done.trim();var st="pending";if(dn)st="done";else if(dd&&dd<td)st="overdue";av.push({nc:v.nc,ex:v.executor,tp:v.type,ms:v.measure,rs:v.responsible,dt:dd,dn:v.done||"",st:st,ad:x.date,an:x.number||"—"})})});c.innerHTML="<div class=\"stats\"><div class=\"st\"><div class=\"n\">"+av.length+"</div><div class=\"l\">Всего</div></div><div class=\"st gr\"><div class=\"n\">"+av.filter(function(v){return v.st==="done"}).length+"</div><div class=\"l\">Устранено</div></div><div class=\"st rd\"><div class=\"n\">"+av.filter(function(v){return v.st==="overdue"}).length+"</div><div class=\"l\">Просрочено</div></div><div class=\"st\"><div class=\"n\" style=\"color:#E76F51\">"+av.filter(function(v){return v.st==="pending"}).length+"</div><div class=\"l\">В работе</div></div></div>"+(av.length>0?"<table><thead><tr><th></th><th>Несоответствие</th><th>Аудит</th><th>Исполнитель</th><th>Меры</th><th>Срок</th><th>Статус</th></tr></thead><tbody>"+av.map(function(v,i){var sc=v.st==="done"?"bs":v.st==="overdue"?"bd2":"bw";var sl=v.st==="done"?"Устранено":v.st==="overdue"?"Просрочено":"В работе";return"<tr><td>"+(i+1)+"</td><td>"+v.nc+"</td><td>"+v.ad+"</td><td>"+v.ex+"</td><td>"+(v.ms||"—")+"</td><td>"+(v.dt||"—")+"</td><td><span class=\"badge "+sc+"\">"+sl+"</span></td></tr>"}).join("")+"</tbody></table>":"<p style=\"color:#5B6573;padding:20px\">Несоответствий не найдено</p>")}
function setO(t){var os=document.getElementById("os"),od=document.getElementById("od");if(!os||!od)return;if(t==="safe"){os.style.background="#EDF7F0";os.style.borderColor="#2D6A4F";os.style.color="#2D6A4F";os.textContent="✅ ВСЕ БЕЗОПАСНО";od.style.background="#fff";od.style.borderColor="#E2E6EB";od.style.color="#5B6573";od.textContent="☐ ЕСТЬ ОПАСНО"}else{os.style.background="#fff";os.style.borderColor="#E2E6EB";os.style.color="#5B6573";os.textContent="☐ ВСЕ БЕЗОПАСНО";od.style.background="#FFEBED";od.style.borderColor="#E63946";od.style.color="#E63946";od.textContent="⚠️ ЕСТЬ ОПАСНО"}}
function toggleAllSafe(id){var cb=document.getElementById("ascb-"+id),tog=document.getElementById("as-"+id);if(!cb||!tog)return;var is=!cb.checked;cb.checked=is;if(is){tog.classList.add("ac2");var cat=CATS.find(function(c){return c.id===id});if(cat)cat.items.forEach(function(_,i){var e=document.getElementById("cb-"+id+"-"+i);if(e){e.checked=false;e.parentElement.classList.remove("ck")}var o=document.getElementById("other-"+id);if(o){o.style.display="none";o.classList.remove("vs")}})}else{tog.classList.remove("ac2")}updateCatTotal(id)}
function onCheckItem(id,idx){var cb=document.getElementById("cb-"+id+"-"+idx);if(!cb)return;if(cb.checked){cb.parentElement.classList.add("ck");document.getElementById("ascb-"+id).checked=false;document.getElementById("as-"+id).classList.remove("ac2")}else{cb.parentElement.classList.remove("ck")}var cat=CATS.find(function(c){return c.id===id});if(cat&&cat.items[idx]==="Другое"){var o=document.getElementById("other-"+id);if(o){if(cb.checked){o.style.display="block";o.classList.add("vs")}else{o.style.display="none";o.classList.remove("vs")}}}updateCatTotal(id)}
function updateCatTotal(id){var cat=CATS.find(function(c){return c.id===id});if(!cat)return;var cnt=0;cat.items.forEach(function(_,i){if(document.getElementById("cb-"+id+"-"+i)&&document.getElementById("cb-"+id+"-"+i).checked)cnt++});var te=document.getElementById("total-"+id);if(te){te.textContent=cnt;if(cnt===0)te.classList.add("zr");else te.classList.remove("zr")}var b=document.getElementById("badge-"+id);if(b){if(cnt===0){b.textContent="ВСЕ БЕЗОПАСНО";b.classList.add("as")}else{b.textContent="Нарушений: "+cnt;b.classList.remove("as")}}}
function mkV(num,data){var d=data||{};return"<div class=\"vg\" id=\"vioRow"+num+"\" style=\"display:grid\"><span class=\"vrn\">"+num+"</span><input class=\"v-nc\" placeholder=\"Описание\" value=\""+esc(d.nc||"")+"\"><input class=\"v-exec\" placeholder=\"Исполнитель\" value=\""+esc(d.executor||"")+"\"><select class=\"v-type\"><option"+(d.type==="Нарушение"?" selected":"")+">Нарушение</option><option"+(d.type==="Замечание"?" selected":"")+">Замечание</option><option"+(d.type==="Риск"?" selected":"")+">Риск</option></select><input class=\"v-measure\" placeholder=\"Меры\" value=\""+esc(d.measure||"")+"\"><input class=\"v-resp\" placeholder=\"Ответственный\" value=\""+esc(d.responsible||"")+"\"><input type=\"date\" class=\"v-date\" value=\""+esc(d.date||"")+"\"><input class=\"v-done\" placeholder=\"Завершение\" value=\""+esc(d.done||"")+"\"><button class=\"rvb\" data-row=\""+num+"\">×</button></div>"}
function addVio(){vrc++;document.getElementById("vr").insertAdjacentHTML("beforeend",mkV(vrc))}
function removeVR(n){if(vrc<=1)return;var r=document.getElementById("vioRow"+n);if(r)r.remove();var rs=document.querySelectorAll("#vr .vg");vrc=rs.length;rs.forEach(function(r,i){r.id="vioRow"+(i+1);r.querySelector(".vrn").textContent=i+1;var b=r.querySelector(".rvb");if(b)b.setAttribute("data-row",(i+1))})}
function getVR(){var rs=[];document.querySelectorAll("#vr .vg").forEach(function(r){var nc=r.querySelector(".v-nc").value.trim();if(!nc)return;rs.push({nc:nc,executor:r.querySelector(".v-exec").value.trim()||"",type:r.querySelector(".v-type").value||"Нарушение",measure:r.querySelector(".v-measure").value.trim()||"",responsible:r.querySelector(".v-resp").value.trim()||"",date:r.querySelector(".v-date").value||"",done:r.querySelector(".v-done").value.trim()||""})});return rs}
function getDL(){var r=[];["Работник привёл примеры безопасных действий","Были обсуждены риски / проблемы","Определены корректирующие меры","Предложения работника зафиксированы","Другое"].forEach(function(l,i){var cb=document.getElementById("d"+i);if(cb&&cb.checked)r.push({item:l,other:l==="Другое"?document.getElementById("do").value.trim()||"":null})});return r}
function setDL(items){for(var i=0;i<5;i++){var cb=document.getElementById("d"+i);if(cb)cb.checked=false}var o=document.getElementById("do");if(o){o.value="";o.style.display="none";o.classList.remove("vs")}items.forEach(function(di){var idx=["Работник привёл примеры безопасных действий","Были обсуждены риски / проблемы","Определены корректирующие меры","Предложения работника зафиксированы","Другое"].indexOf(di.item);if(idx>=0){var cb=document.getElementById("d"+idx);if(cb){cb.checked=true;if(di.item==="Другое"&&di.other){var oo=document.getElementById("do");oo.value=di.other;oo.style.display="block";oo.classList.add("vs")}}}})}
function rHS(){var a=getA(),tb=document.getElementById("hbd");if(!tb)return;tb.innerHTML=a.length===0?"<tr><td colspan=\"7\" style=\"text-align:center;padding:20px;color:#5B6573\">Нет записей</td></tr>":a.map(function(x){var ab=isA()?"<a style=\"color:#00B4D8;cursor:pointer;font-weight:600\" onclick=\"editA("+x.id+")\">✏️</a> <button class=\"btn bd\" style=\"padding:4px 8px;font-size:11px\" onclick=\"delA("+x.id+")\">🗑️</button>":"чтение";return"<tr><td>"+(x.number||"—")+"</td><td>"+x.date+"</td><td>"+x.location+"</td><td>"+x.observer+"</td><td><span class=\"badge "+(x.overallSafe?"bs":"bd2")+"\">"+(x.overallSafe?"Безопасно":"Нарушения")+"</span></td><td>"+(x.totalViolations||0)+"</td><td>"+ab+"</td></tr>"}).join("")}
function submitAudit(){if(editId&&!isA()){alert("Только администратор");return}var loc=document.getElementById("pl").value.trim();if(!loc){alert("Укажите место");return}var cats={},tv=0;CATS.forEach(function(cat){var ch=[];cat.items.forEach(function(item,i){var cb=document.getElementById("cb-"+cat.id+"-"+i);if(cb&&cb.checked){var ov=item==="Другое"?(document.getElementById("other-"+cat.id).value.trim()||""):null;ch.push({item:item,other:ov})}});cats[cat.id]={items:ch,allSafe:ch.length===0};tv+=ch.length});var e={id:editId||Date.now(),number:document.getElementById("pn").value.trim(),date:document.getElementById("pd").value,timeStart:document.getElementById("ps").value,timeEnd:document.getElementById("pe").value,location:loc,region:document.getElementById("pr").value,workType:document.getElementById("pw").value.trim(),workerCount:parseInt(document.getElementById("pc").value)||1,observer:document.getElementById("po").value.trim()||U.name,observerRole:document.getElementById("por").value.trim(),supervisor:document.getElementById("psv").value.trim(),supervisorRole:document.getElementById("psr").value.trim(),email:document.getElementById("pem").value.trim()||U.email||"",overallSafe:document.getElementById("os").classList.contains("sel"),categories:cats,totalViolations:tv,violations:getVR(),dialogue:getDL(),docs:document.getElementById("pdoc").value.trim(),createdBy:U.login,createdAt:new Date().toISOString()};var audits=getA();if(editId){audits=audits.map(function(a){return a.id===editId?e:a});editId=null}else{audits.unshift(e)}saveA(audits);lastSubmitted=e;resetF();document.getElementById("sd").innerHTML="<b>Бланк №"+(e.number||"—")+"</b> | "+e.date+" | <b>"+(e.overallSafe?"БЕЗОПАСНО":"НАРУШЕНИЙ: "+e.totalViolations)+"</b>";document.getElementById("fs").style.display="block";setTimeout(function(){document.getElementById("fs").style.display="none"},30000);if(!isA())checkSA()}
function resetF(){document.getElementById("pn").value="";document.getElementById("pd").value=new Date().toISOString().split("T")[0];document.getElementById("ps").value="";document.getElementById("pe").value="";document.getElementById("pl").value="";document.getElementById("pr").value=U.region||"";document.getElementById("pw").value="";document.getElementById("pc").value="1";document.getElementById("po").value=U.name;document.getElementById("por").value="";document.getElementById("psv").value="";document.getElementById("psr").value="";document.getElementById("pem").value=U.email||"";document.getElementById("pdoc").value="";document.getElementById("pfiles").value="";document.getElementById("fileNames").textContent="";setO("safe");editId=null;CATS.forEach(function(cat){document.getElementById("ascb-"+cat.id).checked=true;document.getElementById("as-"+cat.id).classList.add("ac2");cat.items.forEach(function(_,i){var cb=document.getElementById("cb-"+cat.id+"-"+i);if(cb){cb.checked=false;cb.parentElement.classList.remove("ck")}var o=document.getElementById("other-"+cat.id);if(o){o.value="";o.style.display="none";o.classList.remove("vs")}});updateCatTotal(cat.id)});document.getElementById("vr").innerHTML="";vrc=6;for(var i=0;i<vrc;i++)document.getElementById("vr").innerHTML+=mkV(i+1);setDL([]);return true}
function sendEmailConfirm(){if(!lastSubmitted)return;var e=lastSubmitted,to=e.email||U.email||"";if(!to||to.indexOf("@")<0){alert("Нет email");return}location.href="mailto:"+encodeURIComponent(to)+"?subject="+encodeURIComponent("ПАБ "+(e.number||""))+"&body="+encodeURIComponent("Подтверждение ПАБ\nБланк: "+(e.number||"")+"\ата: "+e.date+"\nМесто: "+e.location+"\nСтатус: "+(e.overallSafe?"БЕЗОПАСНО":"НАРУШЕНИЙ: "+e.totalViolations))}
function printConfirm(){if(!lastSubmitted)return;var e=lastSubmitted;var w=window.open("","_blank","width=700,height=800");w.document.write("<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>ПАБ</title><style>body{font:14px/1.5 Arial;max-width:700px;margin:40px auto}@media print{button{display:none}}</style></head><body><button onclick=\"window.print()\">🖨️ Печать</button><h1>БЛАНК ПАБ №"+(e.number||"—")+" от "+e.date+"</h1><p>Место: "+e.location+" | Наблюдатель: "+e.observer+" | Статус: "+(e.overallSafe?"БЕЗОПАСНО":"НАРУШЕНИЙ: "+e.totalViolations)+"</p></body></html>");w.document.close()}
function submitAudit(){
if(editId&&!isA()){alert("Только администратор может редактировать");return}
var loc=document.getElementById("pl").value.trim();if(!loc){alert("Укажите место проведения");return}
var cats={},tv=0;CATS.forEach(function(cat){var ch=[];cat.items.forEach(function(item,i){var cb=document.getElementById("cb-"+cat.id+"-"+i);if(cb&&cb.checked)ch.push({item:item})});cats[cat.id]={items:ch,allSafe:ch.length===0};tv+=ch.length});
var dl=[];if(document.getElementById("d0").checked)dl.push("Работник привёл примеры безопасных действий");if(document.getElementById("d1").checked)dl.push("Были обсуждены риски / проблемы");if(document.getElementById("d2").checked)dl.push("Определены корректирующие меры");if(document.getElementById("d3").checked)dl.push("Предложения работника зафиксированы");
var e={id:editId||Date.now(),number:document.getElementById("pn").value.trim(),date:document.getElementById("pd").value,location:loc,region:document.getElementById("pr").value,workType:document.getElementById("pw").value.trim(),workerCount:parseInt(document.getElementById("pc").value)||1,observer:document.getElementById("po").value.trim()||U.name,observerRole:document.getElementById("por").value.trim(),overallSafe:document.getElementById("os").classList.contains("sf"),categories:cats,totalViolations:tv,dialogue:dl,createdBy:U.login,createdAt:new Date().toISOString()};
var audits=getA();if(editId){audits=audits.map(function(a){return a.id===editId?e:a});editId=null}else{audits.unshift(e)}saveA(audits);lastSubmitted=e;
document.getElementById("sd").innerHTML="<b>Бланк №"+(e.number||"—")+"</b> | "+e.date+" | "+(e.overallSafe?"БЕЗОПАСНО":"НАРУШЕНИЙ: "+e.totalViolations);document.getElementById("fs").style.display="block";setTimeout(function(){document.getElementById("fs").style.display="none"},20000);
resetF();
}
function checkSA(){if(!U||isA()){document.getElementById("sa").classList.remove("sh","dg");return}var q=getUserQuota(U);if(!q.p)return;var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var need=Math.max(0,q.c-done);var sa=document.getElementById("sa"),at=document.getElementById("sat");sa.classList.remove("sh","dg");if(need>0){at.textContent="⚠️ Отставание ("+p.l+"): "+done+" из "+q.c+". Осталось: "+need;sa.classList.add("sh");if(need>=q.c)sa.classList.add("dg")}}
function sendScheduleReminder(){if(!U)return;var q=getUserQuota(U);var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var need=Math.max(0,q.c-done);var to=U.email||"";if(!to||to.indexOf("@")<0){alert("Нет email");return}location.href="mailto:"+encodeURIComponent(to)+"?subject="+encodeURIComponent("График ПАБ "+p.l)+"&body="+encodeURIComponent("График: "+q.l+"\ериод: "+p.l+"\nВыполнено: "+done+" из "+q.c+(need>0?"\nОтставание: "+need:"\nГрафик выполнен!"))}
function rMS(){var c=document.getElementById("msc");if(!c)return;document.getElementById("sa").classList.remove("sh","dg");if(isA()){var all=allU();var rows="",wCount=0;for(var k in all){if(k==="admin")continue;wCount++;var u=all[k];var q=getUserQuota({role:u.role,freq:u.freq||""});var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===k&&new Date(a.date)>=p.s}).length;var pct=Math.round(done/q.c*100);var cl=pct>=200?"#00B4D8":pct>=100?"#2D6A4F":pct>=50?"#E76F51":"#E63946";var st=pct>100?"🔵 Перевып. +"+(done-q.c):pct>=100?"🟢 Выполнен":"🔴 Отстаёт на "+(q.c-done);rows+="<tr><td><b>"+u.name+"</b></td><td>"+u.role+"</td><td>"+(u.branch||"—")+"</td><td>"+(u.region||"—")+"</td><td>"+(u.city||"—")+"</td><td>"+q.l+"</td><td><div style=\"display:flex;align-items:center;gap:8px\"><div style=\"flex:1;height:12px;border-radius:6px;background:#E2E6EB;overflow:hidden\"><div style=\"height:100%;border-radius:6px;width:"+Math.min(pct,200)+"%;background:"+cl+";transition:width .5s\"></div></div><span style=\"font-size:12px;white-space:nowrap\">"+done+"/"+q.c+"</span></div></td><td style=\"font-size:12px;font-weight:600\">"+st+"</td><td><span style=\"font-size:12px;color:var(--g5)\">"+p.l+"</span></td></tr>"}var tbl=wCount>0?"<div class=\"tw\"><table class=\"dt\"><thead><tr><th>ФИО</th><th>Должность</th><th>Филиал</th><th>Регион</th><th>Город</th><th>Норма</th><th>Прогресс</th><th>Статус</th><th>Период</th></tr></thead><tbody>"+rows+"</tbody></table></div>":"<div class=\"nd\"><span class=\"icon\">👥</span><p>Нет зарегистрированных работников.<br>Работники должны зарегистрироваться на странице входа.</p></div>";c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh);margin-bottom:16px\"><h3>👥 График всех работников</h3><div style=\"font-size:12px;color:var(--g5);margin-bottom:10px\">Вы админ — видите данные всех. Проводить ПАБ вам не нужно.</div></div>"+tbl+"<div style=\"background:var(--white);border-radius:var(--rl);padding:16px;box-shadow:var(--sh);margin-top:12px;display:flex;gap:8px;flex-wrap:wrap\"><button class=\"btn bp bs\" onclick=\"swP('DB')\">📊 Дашборд</button><button class=\"btn bo bs\" onclick=\"swP('HS')\">📁 История</button><button class=\"btn bo bs\" onclick=\"downloadWorkerReport()\">👥 Скачать CSV</button></div>";return}var q=getUserQuota(U);if(q.c===0)q={c:1,p:"month",l:"1 раз в месяц"};var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var pct=Math.round(done/q.c*100);var over=pct>100;var cl=over?"#00B4D8":pct>=100?"#2D6A4F":pct>=50?"#E76F51":"#E63946";var barW=Math.min(pct,200);var need=Math.max(0,q.c-done);var extra=done-q.c;c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh);margin-bottom:16px\"><h3>📅 "+p.l+"</h3><div style=\"font-size:12px;color:var(--g5);margin-bottom:10px\">Минимум: <b>"+q.l+"</b> | "+U.role+"</div><div style=\"height:16px;border-radius:8px;background:#E2E6EB;overflow:hidden;margin-bottom:6px\"><div style=\"height:100%;border-radius:8px;width:"+barW+"%;background:"+cl+";transition:width .5s;max-width:200%\"></div></div><div style=\"font-size:12px;font-weight:600\">Проведено: <b>"+done+"</b> (мин: "+q.c+")"+(over?" — <span style=\"color:#00B4D8\">✅ перевыполнено на +"+extra+"!</span>":done>=q.c?" — ✅ план выполнен!":" — осталось: <span style=\"color:#E63946\">"+need+"</span>")+"</div>"+(need>0?"<div style=\"margin-top:10px\"><button class=\"btn bp bs\" onclick=\"sendScheduleReminder()\">✉️ Напомнить</button></div>":"")+"</div><div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\">👤 <b>"+U.name+"</b> — "+U.role+"<br><span style=\"font-size:12px;color:var(--g5)\">"+(U.branch||"—")+" | "+(U.dept||"—")+" | "+(U.region||"—")+" | "+(U.city||"—")+" | "+U.email+"</span></div>"+(done>0?"<div style=\"margin-top:16px;background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\"><h4 style=\"margin-bottom:8px\">📋 Проведённые:</h4>"+getA().filter(function(a){return a.createdBy===U.login}).slice(0,10).map(function(a){return"<div style=\"background:var(--g1);padding:8px 12px;border-radius:var(--r);margin-bottom:6px;font-size:13px\">"+a.date+" — "+a.location+" — <span class=\"badge "+(a.overallSafe?"badge-s":"badge-d")+"\">"+(a.overallSafe?"Безопасно":"Нарушений: "+a.totalViolations)+"</span></div>"}).join("")+"</div>":"")}
function resetF(){
document.getElementById("pn").value="";document.getElementById("pd").value=new Date().toISOString().split("T")[0];document.getElementById("pr").value=U.region||"";document.getElementById("pl").value="";document.getElementById("pw").value="";document.getElementById("pc").value="1";document.getElementById("po").value=U.name;document.getElementById("por").value="";setO("safe");editId=null;
CATS.forEach(function(cat){cat.items.forEach(function(_,i){var cb=document.getElementById("cb-"+cat.id+"-"+i);if(cb)cb.checked=false});updateCT(cat.id)});
document.getElementById("d0").checked=false;document.getElementById("d1").checked=false;document.getElementById("d2").checked=false;document.getElementById("d3").checked=false;
}
function rDB(){var c=document.getElementById("dbc");if(!c)return;var audits=getA();var all=allU();var total=audits.length,allSafe=audits.filter(function(a){return a.overallSafe}).length,wd=audits.filter(function(a){return !a.overallSafe}).length,tv=audits.reduce(function(s,a){return s+(a.totalViolations||0)},0);var ul=[];for(var k in all)if(k!=="admin")ul.push({login:k,role:all[k].role});var ot=0,bh=0,ov=0;ul.forEach(function(u){var q=getUserQuota(u);if(!q.p)return;var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;if(done>q.c)ov++;else if(done>=q.c)ot++;else bh++});var sp=total>0?(allSafe/total*100):50,dp=total>0?(wd/total*100):50;c.innerHTML=(isA()?"<div class=\"fb\"><button class=\"btn bp bs\" onclick=\"downloadFullCSV()\">📥 CSV данные</button><button class=\"btn bo bs\" onclick=\"downloadWorkerReport()\">👥 CSV работники</button><button class=\"btn bo bs\" onclick=\"downloadSummaryHTML()\">📊 HTML отчёт</button><span style=\"color:var(--g2);margin:0 4px\">|</span><button class=\"btn bd bs\" onclick=\"clearAllAudits()\">🗑️ Очистить всё</button><button class=\"btn bo bs\" onclick=\"clearAuditsByDate()\">📅 Очистить период</button><button class=\"btn bo bs\" onclick=\"showAllUsers()\">👥 Пользователи</button></div>":"")+"<div class=\"sg\"><div class=\"sc\"><div class=\"sl\">Всего аудитов</div><div class=\"sv\">"+total+"</div></div><div class=\"sc gr\"><div class=\"sl\">Безопасно</div><div class=\"sv\">"+allSafe+"</div></div><div class=\"sc rd\"><div class=\"sl\">С нарушениями</div><div class=\"sv\">"+wd+"</div></div><div class=\"sc bl\"><div class=\"sl\">Нарушений</div><div class=\"sv\">"+tv+"</div></div><div class=\"sc bl\"><div class=\"sl\">Перевыполняют</div><div class=\"sv\">"+ov+"</div></div><div class=\"sc gr\"><div class=\"sl\">Выполняют</div><div class=\"sv\">"+ot+"</div></div><div class=\"sc rd\"><div class=\"sl\">Отстают</div><div class=\"sv\">"+bh+"</div></div></div><div class=\"cc\" style=\"margin-bottom:16px\"><h3>🟢🔴 Соотношение</h3><div class=\"rb\"><div class=\"rs\" style=\"width:"+sp+"%\"></div><div class=\"ru\" style=\"width:"+dp+"%\"></div></div><div class=\"rl2\"><span>Безопасные: "+allSafe+"</span><span>С нарушениями: "+wd+"</span></div></div><div class=\"cg\"><div class=\"cc\"><h3>📂 По категориям</h3><canvas id=\"ch1\"></canvas></div><div class=\"cc\"><h3>📅 По датам</h3><canvas id=\"ch2\"></canvas></div><div class=\"cc\"><h3>🔝 Топ-10</h3><canvas id=\"ch3\"></canvas></div></div>";setTimeout(function(){for(var ck in charts)try{charts[ck].destroy()}catch(e){}charts={};var ctx1=document.getElementById("ch1");if(ctx1)charts.cat=new Chart(ctx1,{type:"bar",data:{labels:CATS.map(function(c){return c.title.split(". ")[1]}),datasets:[{label:"Нарушений",data:CATS.map(function(cat){return audits.reduce(function(s,a){var c=a.categories&&a.categories[cat.id];return s+(c?c.items.length:0)},0)}),backgroundColor:"#E63946",borderRadius:6}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var dates={};audits.forEach(function(a){if(!dates[a.date])dates[a.date]=0;dates[a.date]+=(a.totalViolations||0)});var sd=Object.keys(dates).sort();var ctx2=document.getElementById("ch2");if(ctx2)charts.tl=new Chart(ctx2,{type:"line",data:{labels:sd,datasets:[{label:"Нарушений",data:sd.map(function(d){return dates[d]}),borderColor:"#E63946",backgroundColor:"rgba(230,57,70,0.08)",fill:true,tension:0.3,pointRadius:5}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var ic={};audits.forEach(function(a){if(a.categories){Object.values(a.categories).forEach(function(cat){if(cat.items)cat.items.forEach(function(it){ic[it.item]=(ic[it.item]||0)+1})})}});var ti=Object.entries(ic).sort(function(a,b){return b[1]-a[1]}).slice(0,10);var ctx3=document.getElementById("ch3");if(ctx3)charts.top=new Chart(ctx3,{type:"bar",data:{labels:ti.map(function(i){return i[0].length>30?i[0].slice(0,30)+"...":i[0]}),datasets:[{label:"Раз",data:ti.map(function(i){return i[1]}),backgroundColor:["#E63946","#E76F51","#F4A261","#E9C46A","#2A9D8F","#264653","#00B4D8","#0077B6","#023E8A","#6C757D"],borderRadius:4}]},options:{indexAxis:"y",responsive:true,plugins:{legend:{display:false}},scales:{x:{beginAtZero:true,ticks:{stepSize:1}}}}})},300)}
function exportCSV(){var a=getA();if(a.length===0){alert("Нет данных");return}var all=allU(),h="Бланк №;Дата;Место;Наблюдатель;Должность;Филиал;Регион;Город;Статус;Нарушений",rs=a.map(function(x){var u=all[x.createdBy]||{};return(x.number||"")+";"+x.date+";"+x.location+";"+x.observer+";"+(x.observerRole||"")+";"+(u.branch||"")+";"+(u.region||"")+";"+(u.city||"")+";"+(x.overallSafe?"Безопасно":"Нарушения")+";"+(x.totalViolations||0)}),csv="\uFEFF"+h+"\n"+rs.join("\n"),bl=new Blob([csv],{type:"text/csv"}),ur=URL.createObjectURL(bl),dl=document.createElement("a");dl.href=ur;dl.download="pab.csv";dl.click();URL.revokeObjectURL(ur)}
function editA(id){if(!isA()){alert("Только админ");return}alert("Редактирование: аудит #"+id)}
function delA(id){if(!isA()){alert("Только админ");return}if(!confirm("Удалить?"))return;saveA(getA().filter(function(a){return a.id!==id}));rHS()}
function downloadFullCSV(){var a=getA();if(a.length===0){alert("Нет данных");return}var all=allU(),h="Бланк №;Дата;Место;Наблюдатель;Филиал;Регион;Статус;Нарушений",rs=a.map(function(x){var u=all[x.createdBy]||{};return(x.number||"")+";"+x.date+";"+x.location+";"+x.observer+";"+(u.branch||"")+";"+(u.region||"")+";"+(x.overallSafe?"Безопасно":"Нарушения")+";"+(x.totalViolations||0)}),csv="\uFEFF"+h+"\n"+rs.join("\n"),bl=new Blob([csv],{type:"text/csv"}),ur=URL.createObjectURL(bl),dl=document.createElement("a");dl.href=ur;dl.download="pab-full.csv";dl.click();URL.revokeObjectURL(ur)}
function showAllUsers(){if(!isA())return;var all=allU(),h="<h2>👥 Пользователи</h2><table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:#0F1218;color:#fff\"><th>Логин</th><th>ФИО</th><th>Должность</th><th>Филиал</th><th>Регион</th><th>Город</th></tr>";for(var k in all){var u=all[k];h+="<tr><td>"+k+(k==="admin"?" ⭐":"")+"</td><td>"+u.name+"</td><td>"+u.role+"</td><td>"+(u.branch||"—")+"</td><td>"+(u.region||"—")+"</td><td>"+(u.city||"—")+"</td></tr>"}h+="</table>";var w=window.open("","_blank","width=800,height=500");w.document.write("<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Пользователи</title><style>body{font:14px/1.5 Arial;max-width:800px;margin:20px auto;padding:20px}</style></head><body>"+h+"</body></html>");w.document.close()}
function rVL(){var c=document.getElementById("vlc");if(!c)return;var audits=getA();var today=new Date().toISOString().split("T")[0];var allV=[];audits.forEach(function(a){if(!a.violations)return;a.violations.forEach(function(v){var dd=v.date||"",done=v.done&&v.done.trim();var st="pending";if(done)st="done";else if(dd&&dd<today)st="overdue";allV.push({nc:v.nc,executor:v.executor,type:v.type,measure:v.measure,responsible:v.responsible,date:dd,done:v.done||"",status:st,auditDate:a.date,auditNumber:a.number||"—"})})});c.innerHTML="<div class=\"sg\"><div class=\"sc\"><div class=\"sl\">Всего</div><div class=\"sv\">"+allV.length+"</div></div><div class=\"sc gr\"><div class=\"sl\">Устранено</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="done"}).length+"</div></div><div class=\"sc rd\"><div class=\"sl\">Просрочено</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="overdue"}).length+"</div></div><div class=\"sc or\"><div class=\"sl\">В работе</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="pending"}).length+"</div></div></div><div class=\"tw\"><table class=\"dt\"><thead><tr><th></th><th>Несоответствие</th><th>Аудит</th><th>Исполнитель</th><th>Вид</th><th>Меры</th><th>Ответственный</th><th>Срок</th><th>Завершение</th><th>Статус</th></tr></thead><tbody>"+allV.map(function(v,i){var sc=v.status==="done"?"badge-s":v.status==="overdue"?"badge-d":"badge-w";var sl=v.status==="done"?"Устранено":v.status==="overdue"?"Просрочено":"В работе";return"<tr><td>"+(i+1)+"</td><td style=\"max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\""+esc(v.nc)+"\">"+v.nc+"</td><td>"+v.auditDate+"</td><td>"+v.executor+"</td><td>"+v.type+"</td><td style=\"max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\">"+(v.measure||"—")+"</td><td>"+v.responsible+"</td><td>"+(v.date||"—")+"</td><td>"+(v.done||"—")+"</td><td><span class=\"badge "+sc+"\">"+sl+"</span></td></tr>"}).join("")+"</tbody></table></div>"}
function rHT(){var audits=getA();var fs=document.getElementById("hfs"),fd=document.getElementById("hfd"),fl=document.getElementById("hfl");if(fs&&fs.value==="safe")audits=audits.filter(function(a){return a.overallSafe});if(fs&&fs.value==="danger")audits=audits.filter(function(a){return !a.overallSafe});if(fd&&fd.value)audits=audits.filter(function(a){return a.date===fd.value});if(fl&&fl.value)audits=audits.filter(function(a){var v=fl.value.toLowerCase();return a.location.toLowerCase().indexOf(v)>=0});var tb=document.getElementById("hbd");if(!tb)return;tb.innerHTML=audits.length===0?"<tr><td colspan=\"8\" style=\"text-align:center;padding:30px;color:var(--g5)\">Нет записей</td></tr>":audits.map(function(a){var ab=isA()?"<a class=\"vl\" onclick=\"editA("+a.id+")\">✏️</a> <button class=\"btn bd bs\" onclick=\"delA("+a.id+")\">🗑️</button>":"<span style=\"color:var(--g5);font-size:11px\">чтение</span>";return"<tr><td>"+(a.number||"—")+"</td><td>"+a.date+"</td><td>"+(a.timeStart||"—")+" — "+(a.timeEnd||"—")+"</td><td>"+a.location+"</td><td>"+a.observer+"</td><td><span class=\"badge "+(a.overallSafe?"badge-s":"badge-d")+"\">"+(a.overallSafe?"Безопасно":"Нарушения")+"</span></td><td>"+(a.totalViolations||0)+"</td><td>"+ab+"</td></tr>"}).join("")}
function exportCSV(){var audits=getA();if(audits.length===0){alert("Нет данных");return}var all=allU();var h="Бланк №;Дата;Время;Место;Наблюдатель;Должность;Филиал;Регион;Область;Город;Статус;Нарушений";var rows=audits.map(function(a){var u=all[a.createdBy]||{};return(a.number||"")+";"+a.date+";"+(a.timeStart||"")+"-"+(a.timeEnd||"")+";\""+a.location+"\";\""+a.observer+"\";\""+(a.observerRole||"")+"\";\""+(u.branch||"")+"\";\""+(u.region||"")+"\";\""+(u.oblast||"")+"\";\""+(u.city||"")+"\";"+(a.overallSafe?"Безопасно":"Нарушения")+";"+(a.totalViolations||0)});var csv="\uFEFF"+h+"\n"+rows.join("\n");var blob=new Blob([csv],{type:"text/csv"});var url=URL.createObjectURL(blob);var dl=document.createElement("a");dl.href=url;dl.download="pab.csv";dl.click();URL.revokeObjectURL(url)}
function editA(id){if(!isA()){alert("Только администратор");return}var a=getA().find(function(x){return x.id===id});if(!a)return;editId=id;swP("NA");setTimeout(function(){document.getElementById("pn").value=a.number||"";document.getElementById("pd").value=a.date||"";document.getElementById("ps").value=a.timeStart||"";document.getElementById("pe").value=a.timeEnd||"";document.getElementById("pl").value=a.location||"";document.getElementById("pr").value=a.region||"";document.getElementById("pw").value=a.workType||"";document.getElementById("pc").value=a.workerCount||1;document.getElementById("po").value=a.observer||"";document.getElementById("por").value=a.observerRole||"";document.getElementById("psv").value=a.supervisor||"";document.getElementById("psr").value=a.supervisorRole||"";document.getElementById("pem").value=a.email||"";document.getElementById("pdoc").value=a.docs||"";setO(a.overallSafe?"safe":"danger");CATS.forEach(function(cat){var cd=a.categories&&a.categories[cat.id];var it=cd?cd.items:[];it.forEach(function(i){var idx=cat.items.indexOf(i.item);if(idx>=0){var cb=document.getElementById("cb-"+cat.id+"-"+idx);if(cb){cb.checked=true;cb.parentElement.classList.add("ck")}if(i.other){var o=document.getElementById("other-"+cat.id);if(o){o.value=i.other;o.style.display="block";o.classList.add("vs")}}}});document.getElementById("ascb-"+cat.id).checked=it.length===0;document.getElementById("as-"+cat.id).classList.toggle("ac2",it.length===0);updateCatTotal(cat.id)});document.getElementById("vr").innerHTML="";if(a.violations&&a.violations.length>0){vrc=a.violations.length;document.getElementById("vr").innerHTML=a.violations.map(function(v,i){return mkV(i+1,v)}).join("")}else{vrc=1;document.getElementById("vr").innerHTML=mkV(1)}setDL(a.dialogue||[])},200)}
function delA(id){if(!isA()){alert("Только администратор");return}if(!confirm("Удалить?"))return;saveA(getA().filter(function(a){return a.id!==id}));rHT()}
function downloadFullCSV(){var audits=getA();if(audits.length===0){alert("Нет данных");return}var all=allU();var h="Бланк №;Дата;Время;Место;Тип;Наблюдатель;Должность;Руководитель;Филиал;Подразделение;Регион;Область;Город;Статус;Нарушений";var rows=audits.map(function(a){var u=all[a.createdBy]||{};return(a.number||"")+";"+a.date+";"+(a.timeStart||"")+"-"+(a.timeEnd||"")+";\""+a.location+"\";\""+(a.workType||"")+"\";\""+a.observer+"\";\""+(a.observerRole||"")+"\";\""+(a.supervisor||"")+"\";\""+(u.branch||"")+"\";\""+(u.dept||"")+"\";\""+(u.region||"")+"\";\""+(u.oblast||"")+"\";\""+(u.city||"")+"\";"+(a.overallSafe?"Безопасно":"Нарушения")+";"+(a.totalViolations||0)});var csv="\uFEFF"+h+"\n"+rows.join("\n");var blob=new Blob([csv],{type:"text/csv"});var url=URL.createObjectURL(blob);var dl=document.createElement("a");dl.href=url;dl.download="pab-full.csv";dl.click();URL.revokeObjectURL(url)}
function downloadWorkerReport(){var audits=getA();var all=allU();var ul=[];for(var k in all)if(k!=="admin")ul.push({login:k,name:all[k].name,role:all[k].role,branch:all[k].branch||"",dept:all[k].dept||"",region:all[k].region||"",oblast:all[k].oblast||"",city:all[k].city||"",email:all[k].email||""});if(ul.length===0){alert("Нет работников");return}var h="Логин;ФИО;Должность;Филиал;Подразделение;Регион;Область;Город;Email;График;Период;Выполнено;Нужно;Статус";var rows=ul.map(function(u){var q=getUserQuota(u);if(!q.p)return u.login+";\""+u.name+"\";\""+u.role+"\";\""+u.branch+"\";\""+u.dept+"\";\""+u.region+"\";\""+u.oblast+"\";\""+u.city+"\";\""+u.email+"\";Без графика;;;0;—";var p=gp(q.p);var done=audits.filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;var st=done>=q.c?"Выполнен":"Отстаёт ("+(q.c-done)+")";return u.login+";\""+u.name+"\";\""+u.role+"\";\""+u.branch+"\";\""+u.dept+"\";\""+u.region+"\";\""+u.oblast+"\";\""+u.city+"\";\""+u.email+"\";\""+q.l+"\";\""+p.l+"\";"+done+";"+q.c+";\""+st+"\""});var csv="\uFEFF"+h+"\n"+rows.join("\n");var blob=new Blob([csv],{type:"text/csv"});var url=URL.createObjectURL(blob);var dl=document.createElement("a");dl.href=url;dl.download="pab-workers.csv";dl.click();URL.revokeObjectURL(url)}
function downloadSummaryHTML(){var audits=getA();var all=allU();var ul=[];for(var k in all)if(k!=="admin")ul.push({login:k,name:all[k].name,role:all[k].role,branch:all[k].branch||"",dept:all[k].dept||"",region:all[k].region||"",city:all[k].city||""});var total=audits.length,allSafe=audits.filter(function(a){return a.overallSafe}).length,wd=audits.filter(function(a){return !a.overallSafe}).length,tv=audits.reduce(function(s,a){return s+(a.totalViolations||0)},0);var ot=0,bh=0;ul.forEach(function(u){var q=getUserQuota(u);if(!q.p)return;var p=gp(q.p);var done=audits.filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;if(done>=q.c)ot++;else bh++});var wr=ul.map(function(u){var q=getUserQuota(u);if(!q.p)return"<tr><td>"+u.name+"</td><td>"+u.role+"</td><td>"+u.branch+"</td><td>"+u.dept+"</td><td>"+u.region+"</td><td>"+u.city+"</td><td>Без графика</td><td></td></tr>";var p=gp(q.p);var done=audits.filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;var c=done>=q.c?"green":"red";return"<tr><td>"+u.name+"</td><td>"+u.role+"</td><td>"+u.branch+"</td><td>"+u.dept+"</td><td>"+u.region+"</td><td>"+u.city+"</td><td style=\"color:"+c+"\">"+done+"/"+q.c+" ("+q.l+")</td><td>"+p.l+"</td></tr>"}).join("");var h="<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Отчёт ПАБ</title><style>body{font:14px/1.5 Arial;max-width:1000px;margin:30px auto;padding:20px}h1{font-size:24px;border-bottom:3px solid #00B4D8}h2{font-size:18px;margin-top:30px;color:#00B4D8}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px;margin:16px 0}.card{background:#F2F4F7;padding:16px;border-radius:10px;text-align:center}.val{font-size:28px;font-weight:800}.g{color:#2D6A4F}.r{color:#E63946}table{width:100%;border-collapse:collapse;margin:12px 0;font-size:13px}th{background:#0F1218;color:#fff;padding:10px 12px}td{padding:8px 12px;border-bottom:1px solid #E2E6EB}@media print{button{display:none}}</style></head><body><button onclick=\"window.print()\" style=\"padding:10px 24px;font-size:15px;margin-bottom:16px\">🖨️ Печать</button><h1>📊 Сводный отчёт ПАБ</h1><p>Сформирован: "+new Date().toLocaleString("ru")+"</p><div class=\"cards\"><div class=\"card\"><div>Всего аудитов</div><div class=\"val\">"+total+"</div></div><div class=\"card\"><div>Безопасно</div><div class=\"val g\">"+allSafe+"</div></div><div class=\"card\"><div>С нарушениями</div><div class=\"val r\">"+wd+"</div></div><div class=\"card\"><div>Нарушений</div><div class=\"val r\">"+tv+"</div></div><div class=\"card\"><div>Выполняют график</div><div class=\"val g\">"+ot+"</div></div><div class=\"card\"><div>Отстают</div><div class=\"val r\">"+bh+"</div></div></div><h2>👥 График</h2><table><tr><th>ФИО</th><th>Должность</th><th>Филиал</th><th>Подразделение</th><th>Регион</th><th>Город</th><th>Прогресс</th><th>Период</th></tr>"+wr+"</table></body></html>";var w=window.open("","_blank","width=1000,height=800");w.document.write(h);w.document.close()}
function clearAllAudits(){if(!isA())return;if(!confirm("Удалить ВСЕ аудиты?"))return;if(!confirm("Точно?"))return;localStorage.removeItem("pab_audits");alert("Удалено")}
function clearAuditsByDate(){if(!isA())return;var from=prompt("С даты (ГГГГ-ММ-ДД):","");if(!from)return;var to=prompt("По дату (ГГГГ-ММ-ДД):","");var audits=getA();var before=audits.length;audits=audits.filter(function(a){if(a.date<from)return true;if(to&&a.date>to)return true;return false});if(before===audits.length){alert("Нет аудитов за период");return}if(!confirm("Удалить "+(before-audits.length)+"?"))return;saveA(audits);alert("Удалено "+(before-audits.length))}
function showAllUsers(){if(!isA())return;var all=allU();var h="<h2>👥 Пользователи</h2><table style=\"width:100%;border-collapse:collapse;font-size:13px\"><tr style=\"background:#0F1218;color:#fff\"><th>Логин</th><th>ФИО</th><th>Должность</th><th>Филиал</th><th>Подразделение</th><th>Регион</th><th>Область</th><th>Город</th><th>Email</th><th>График</th></tr>";for(var k in all){var u=all[k],q=getUserQuota(u);h+="<tr style=\"border-bottom:1px solid #E2E6EB\"><td>"+k+(k==="admin"?" ⭐":"")+"</td><td>"+u.name+"</td><td>"+u.role+"</td><td>"+(u.branch||"—")+"</td><td>"+(u.dept||"—")+"</td><td>"+(u.region||"—")+"</td><td>"+(u.oblast||"—")+"</td><td>"+(u.city||"—")+"</td><td>"+(u.email||"—")+"</td><td>"+q.l+"</td></tr>"}h+="</table>";var w=window.open("","_blank","width=1000,height=600");w.document.write("<!DOCTYPE html><html><head><meta charset=\"utf-8\"><title>Пользователи</title><style>body{font:14px/1.5 Arial;max-width:1100px;margin:30px auto;padding:20px}@media print{button{display:none}}</style></head><body><button onclick=\"window.print()\">🖨️ Печать</button>"+h+"</body></html>");w.document.close()}
document.getElementById("pd").value=new Date().toISOString().split("T")[0];
document.getElementById("po").value=U.name;document.getElementById("por").value=U.role||"";
document.getElementById("pem").value=U.email||"";document.getElementById("pr").value=U.region||"";
rHT();checkSA();
rHS();
</script>
</body>
</html>