samruk-ai-agent/index.html

321 lines
43 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>План ПБ 2026 — Казахтелеком</title>
<style>
:root{--ink:#0B1A2E;--cyan:#00B4D8;--cyan-l:#E0F7FA;--white:#fff;--gray-50:#F8FAFC;--gray-100:#F1F5F9;--gray-200:#E2E8F0;--gray-500:#64748B;--gray-700:#334155;--green:#10B981;--red:#EF4444;--amber:#F59E0B;--blue:#3B82F6;--sidebar:240px}
*{box-sizing:border-box;margin:0;padding:0}
body{font:14px/1.5 'Segoe UI',system-ui,-apple-system,sans-serif;color:var(--gray-700);background:var(--gray-50);min-height:100vh}
input,select,textarea,button{font:inherit;outline:none}
.btn{background:var(--cyan);color:var(--white);padding:10px 20px;border-radius:8px;font-weight:600;font-size:14px;border:none;cursor:pointer;transition:.15s}.btn:hover{background:#0096B0}
.btn-sm{padding:6px 14px;font-size:12px}.btn-red{background:var(--red);color:#fff}.btn-gn{background:var(--green);color:#fff}
.btn-ghost{background:transparent;color:var(--gray-500);border:1px solid var(--gray-200)}.btn-ghost:hover{background:var(--gray-100)}
#loginBox{display:flex;align-items:center;justify-content:center;min-height:100vh;background:linear-gradient(135deg,#0B1A2E 0%,#1a3a5c 100%)}
#loginBox>div{background:var(--white);border-radius:20px;padding:48px 40px;width:420px;max-width:90vw;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.3)}
#loginBox .logo{font-size:28px;font-weight:800;color:var(--ink);margin-bottom:4px}
#loginBox .logo span{color:var(--cyan)}
#loginBox .sub{color:var(--gray-500);font-size:13px;margin-bottom:32px}
#loginBox input{display:block;width:100%;padding:14px 16px;border:2px solid var(--gray-200);border-radius:10px;font-size:14px;margin-bottom:16px;transition:.15s}
#loginBox input:focus{border-color:var(--cyan)}
#app{display:none;display:flex;min-height:100vh}
.sidebar{width:var(--sidebar);background:var(--ink);color:var(--white);position:fixed;top:0;left:0;bottom:0;display:flex;flex-direction:column;z-index:10}
.sidebar .logo{padding:24px 20px;font-size:18px;font-weight:800;border-bottom:1px solid rgba(255,255,255,.08)}
.sidebar .logo span{color:var(--cyan)}
.sidebar nav{flex:1;padding:12px 0}
.sidebar nav a{display:flex;align-items:center;gap:12px;padding:12px 20px;color:rgba(255,255,255,.6);font-weight:500;font-size:14px;cursor:pointer;text-decoration:none;transition:.15s;border-left:3px solid transparent}
.sidebar nav a:hover,.sidebar nav a.on{color:var(--white);background:rgba(0,180,216,.1);border-left-color:var(--cyan)}
.sidebar .user{padding:20px;border-top:1px solid rgba(255,255,255,.08);font-size:12px;color:rgba(255,255,255,.4)}
.main{margin-left:var(--sidebar);flex:1;padding:24px 32px;max-width:calc(100vw - var(--sidebar))}
.topbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}
.topbar h2{font-size:22px;font-weight:700;color:var(--ink)}
.topbar .right{display:flex;align-items:center;gap:16px}
.notif-btn{position:relative;background:var(--white);border:1px solid var(--gray-200);border-radius:10px;padding:8px 12px;cursor:pointer;font-size:18px}
.notif-btn .cnt{position:absolute;top:-6px;right:-6px;background:var(--red);color:#fff;border-radius:100px;font-size:10px;padding:2px 6px;font-weight:700;min-width:18px;text-align:center}
.notif-drop{position:absolute;top:52px;right:0;width:400px;max-width:90vw;background:var(--white);border:1px solid var(--gray-200);border-radius:14px;box-shadow:0 10px 40px rgba(0,0,0,.12);z-index:300;display:none;max-height:420px;overflow-y:auto}
.notif-drop.on{display:block}.notif-drop .it{padding:14px 18px;border-bottom:1px solid var(--gray-100);font-size:13px}.notif-drop .it b{display:block;margin-bottom:3px}.notif-drop .it span{font-size:11px;color:var(--gray-500)}
.tabs{display:flex;gap:8px;margin-bottom:24px}
.tab{padding:10px 22px;border-radius:10px;border:none;background:var(--white);cursor:pointer;font-size:14px;font-weight:600;color:var(--gray-500);box-shadow:0 1px 3px rgba(0,0,0,.04);transition:.15s}
.tab.on{background:var(--cyan);color:var(--white)}
.pg{display:none}.pg.on{display:block}
.card{background:var(--white);border-radius:14px;padding:24px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04);border:1px solid var(--gray-100)}
.card h3{font-size:17px;font-weight:700;margin-bottom:12px;color:var(--ink)}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px;margin-bottom:20px}
.stat{background:var(--white);border-radius:12px;padding:20px 24px;box-shadow:0 1px 3px rgba(0,0,0,.04);border:1px solid var(--gray-100);text-align:center}
.stat .n{font-size:30px;font-weight:800}.stat .l{font-size:12px;color:var(--gray-500);margin-top:4px}
.stat.r .n{color:var(--red)}.stat.g .n{color:var(--green)}.stat.a .n{color:var(--amber)}.stat.b .n{color:var(--cyan)}
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;border-bottom:2px solid var(--gray-100);background:var(--gray-50)}
td{border-bottom:1px solid var(--gray-100)}
tr.rd td{background:#FEF2F2}tr.am td{background:#FFFBEB}
.badge{display:inline-block;padding:4px 10px;border-radius:100px;font-size:11px;font-weight:600}
.badge.g{background:#D1FAE5;color:#065F46}.badge.a{background:#FEF3C7;color:#92400E}.badge.r{background:#FEE2E2;color:#991B1B}.badge.b{background:#DBEAFE;color:#1E40AF}.badge.w{background:var(--gray-100);color:var(--gray-700)}
.fr{display:flex;gap:10px;margin-bottom:14px;flex-wrap:wrap;align-items:center}
.fr input,.fr select{padding:10px 14px;border:1px solid var(--gray-200);border-radius:8px;font-size:13px;background:var(--white)}.fr input{min-width:220px}
.modal-o{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:99;display:none;align-items:center;justify-content:center}.modal-o.on{display:flex}
.modal{background:var(--white);border-radius:16px;max-width:720px;width:94vw;max-height:88vh;overflow-y:auto;padding:32px;box-shadow:0 20px 60px rgba(0,0,0,.15)}
.modal .x{float:right;border:none;background:none;font-size:26px;cursor:pointer;color:var(--gray-500);line-height:1}
.modal label{display:block;font-size:12px;font-weight:600;color:var(--gray-500);margin-bottom:4px;margin-top:12px}
.modal input,.modal select,.modal textarea{width:100%;padding:10px 14px;border:1px solid var(--gray-200);border-radius:8px;font-size:13px;margin-bottom:6px}
.modal textarea{min-height:64px;resize:vertical}
.meta{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:10px;font-size:12px;color:var(--gray-500)}.meta strong{display:block;color:var(--ink);font-size:14px;margin-top:2px}
.mt{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px}.mt span{padding:6px 14px;border:1px solid var(--gray-200);border-radius:100px;font-size:12px;font-weight:600;cursor:pointer;transition:.15s}.mt span.on{background:var(--cyan);color:var(--white);border-color:var(--cyan)}.mt span:hover{border-color:var(--cyan)}
.si{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--gray-50);border-radius:8px;margin-bottom:6px;font-size:13px}.si .n{font-weight:700;color:var(--cyan);font-size:15px;min-width:20px}
.fl{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--gray-50);border-radius:8px;margin-bottom:4px;font-size:12px}.fl .nm{font-weight:600;cursor:pointer}.fl .nm:hover{color:var(--cyan)}.fl .sz{font-size:10px;color:var(--gray-500)}
.up{border:2px dashed var(--gray-200);border-radius:10px;padding:14px;margin-top:8px;text-align:center}.up p{font-size:13px;color:var(--gray-500);margin-bottom:10px}.up input[type=file]{font-size:12px}
.ai-block{background:var(--cyan-l);border-radius:8px;padding:12px;margin:12px 0;font-size:13px}
.hi{font-size:11px;color:var(--gray-500);padding:2px 0}.hi .d{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--cyan);margin-right:6px;vertical-align:middle}
.chart-bar{display:flex;align-items:flex-end;gap:8px;height:160px;padding:0 4px}
.chart-bar>div{flex:1;border-radius:6px 6px 0 0;min-height:4px;transition:.3s}
.ai-chat{border:1px solid var(--gray-200);border-radius:10px;padding:14px;max-height:320px;overflow-y:auto;margin-bottom:12px;background:var(--white)}
.ai-chat .msg{margin-bottom:8px;padding:10px 14px;border-radius:10px;font-size:13px;max-width:88%;line-height:1.5}
.ai-chat .user{background:var(--cyan);color:var(--white);margin-left:auto}.ai-chat .bot{background:var(--gray-50);color:var(--ink)}
.ai-input{display:flex;gap:8px}.ai-input input{flex:1;padding:10px 14px;border:1px solid var(--gray-200);border-radius:8px;font-size:13px}
@media(max-width:768px){
.sidebar{width:0;overflow:hidden}.sidebar .logo,.sidebar nav,.sidebar .user{display:none}
.main{margin-left:0;max-width:100vw;padding:16px}
.stats{grid-template-columns:1fr 1fr}.meta{grid-template-columns:1fr}
}
</style>
</head>
<body>
<div id="loginBox"><div>
<div class="logo"><span>Qazaq</span>Telecom</div>
<p class="sub">План производственной безопасности 2026</p>
<input id="lem" placeholder="curator@telecom.kz">
<input id="lpw" type="password" placeholder="Пароль">
<p id="lerr" style="color:var(--red);font-size:12px;display:none;margin-bottom:8px">Неверная почта</p>
<button class="btn" style="width:100%;padding:14px" onclick="doLogin()">Войти</button>
</div></div>
<div id="app" style="display:none">
<div class="sidebar">
<div class="logo"><span>Qazaq</span>Telecom</div>
<nav>
<a class="on" data-pg="ev" onclick="switchPg('ev')">📋 Мероприятия</a>
<a data-pg="an" onclick="switchPg('an')">📊 Аналитика</a>
<a data-pg="rp" onclick="switchPg('rp')">📥 Отчётность</a>
<a data-pg="ai" onclick="switchPg('ai')">🤖 ИИ-помощник</a>
</nav>
<div class="user" id="ul"></div>
</div>
<div class="main">
<div class="topbar">
<h2 id="pageTitle">Мероприятия</h2>
<div class="right">
<div style="position:relative"><button class="notif-btn" onclick="toggleN()">🔔<span class="cnt" id="nc">0</span></button><div class="notif-drop" id="nd"></div></div>
<button class="btn btn-ghost btn-sm" onclick="doLogout()">Выйти</button>
</div>
</div>
<div class="pg on" id="pg-ev"></div><div class="pg" id="pg-an"></div><div class="pg" id="pg-rp"></div><div class="pg" id="pg-ai"></div>
</div>
</div>
<div class="modal-o" id="mo"><div class="modal" id="mc"></div></div>
<script>
var sec=["I. Люди. Повышение культуры безопасности","II. Безопасность при эксплуатации оборудования","III. Предупреждение и готовность к ликвидации аварий и ЧС","IV. Информационно-разъяснительная работа","V. Внедрение ИИ и цифровизации"];
var br=["Дирекция ПБ","Дивизион «Сеть»","Корпоративный бизнес","Розничный бизнес","Сервисная фабрика","Телеком Комплект","Корпоративный университет","Управление проектами","Цифровой бизнес"];
var reg=["Центральный","Алматинский","Южный","Северный","Восточный","Западный"];
var st={wait:"Не начато",warn:"В процессе",late:"Просрочено",done:"Исполнено"};
var ms=["2026-01","2026-02","2026-03","2026-04","2026-05","2026-06","2026-07","2026-08","2026-09","2026-10","2026-11","2026-12"];
var mn=["Янв","Фев","Мар","Апр","Май","Июн","Июл","Авг","Сен","Окт","Ноя","Дек"];
var titles={ev:"Мероприятия",an:"Аналитика",rp:"Отчётность",ai:"ИИ-помощник"};
function M(i){var p=ms[i].split("-");return mn[parseInt(p[1])-1]+" "+p[0]}
function esc(s){return s.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
function nl(s){return esc(s).replace(/\n/g,"<br>")}
function sb(s){var m={done:"g",warn:"a",late:"r",wait:"w"};return'<span class="badge '+m[s]+'">'+st[s]+'</span>'}
function daysLeft(e){
if(e.s==="done")return'<span style="color:var(--green)">✓</span>';
if(e.s==="late")return'<span style="color:var(--red);font-weight:700">ПРОСРОЧЕНО</span>';
var p=e.due.split(".");if(p.length!==3)return"";
var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));
var days=Math.round((d-new Date())/86400000);
if(days<0)return'<span style="color:var(--red);font-weight:700">'+Math.abs(days)+' дн.</span>';
if(days<=7)return'<span style="color:var(--red);font-weight:600">'+days+' дн.</span>';
if(days<=14)return'<span style="color:var(--amber);font-weight:600">'+days+' дн.</span>';
if(days<=30)return'<span style="color:var(--amber)">'+days+' дн.</span>';
return days+' дн.';
}
function rowClass(e){if(e.s==="late")return"rd";if(e.s==="done")return"";var p=e.due.split(".");if(p.length!==3)return"";var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));var days=Math.round((d-new Date())/86400000);if(days<=14)return"rd";if(days<=30)return"am";return""}
var U={"curator@telecom.kz":{n:"Куратор ПБ",b:0,r:"cur"},"dpp@telecom.kz":{n:"Директор ДПБ",b:0,r:"br"},"ahmetov@telecom.kz":{n:"Ахметов К.Т.",b:6,r:"br"},"serikov@telecom.kz":{n:"Сериков А.М.",b:1,r:"br"},"nurlanov@telecom.kz":{n:"Нурланов Д.С.",b:8,r:"br"},"aliev@telecom.kz":{n:"Алиев Г.С.",b:4,r:"br"},"tulegenov@telecom.kz":{n:"Тулегенов Е.А.",b:2,r:"br"},"saparov@telecom.kz":{n:"Сапаров А.Д.",b:3,r:"br"},"maratov@telecom.kz":{n:"Маратов Ж.К.",b:5,r:"br"},"iskakov@telecom.kz":{n:"Искаков Р.Н.",b:7,r:"br"}};
var cu=null,ev=null,cm=5,esi=-1,ex={},chatHistory=[];
function getMD(id,si){var k=si>=0?"sf_"+id+"_s"+si:"sf_"+id;var r=localStorage.getItem(k);return r?JSON.parse(r):{}}
function setMD(id,o,si){var k=si>=0?"sf_"+id+"_s"+si:"sf_"+id;localStorage.setItem(k,JSON.stringify(o))}
function gsc(id){var r=localStorage.getItem("ss_"+id);return r?JSON.parse(r):[]}
function ssc(id,a){localStorage.setItem("ss_"+id,JSON.stringify(a))}
function doLogin(){var e=document.getElementById("lem").value.trim().toLowerCase();if(U[e]){cu={em:e,n:U[e].n,b:U[e].b,r:U[e].r};localStorage.setItem("su",JSON.stringify(cu));showApp()}else document.getElementById("lerr").style.display="block"}
function doLogout(){localStorage.removeItem("su");cu=null;document.getElementById("loginBox").style.display="flex";document.getElementById("app").style.display="none"}
function showApp(){document.getElementById("loginBox").style.display="none";document.getElementById("app").style.display="flex";document.getElementById("ul").textContent=cu.n;loadEvents()}
function loadEvents(){var s=localStorage.getItem("se4");if(s){try{ev=JSON.parse(s);renderEv();return}catch(e){}}var x=new XMLHttpRequest();x.open("GET","data.json",true);x.onload=function(){if(x.status===200){try{ev=JSON.parse(x.responseText);saveEv()}catch(e){ev=[]}};renderEv()};x.onerror=function(){ev=[];renderEv()};x.send()}
function saveEv(){localStorage.setItem("se4",JSON.stringify(ev||[]))}
function switchPg(n){
document.querySelectorAll(".sidebar nav a").forEach(function(a){a.classList.remove("on")});
document.querySelector('[data-pg="'+n+'"]').classList.add("on");
document.querySelectorAll(".pg").forEach(function(p){p.classList.remove("on")});
document.getElementById("pg-"+n).classList.add("on");
document.getElementById("pageTitle").textContent=titles[n];
if(n==="ev")renderEv();else if(n==="an")renderAn();else if(n==="rp")renderRp();else if(n==="ai")renderAi();
}
// ===== EVENTS =====
function toggleEx(id){ex[id]=!ex[id];renderEv()}
function ts(id,si,chk){var s=gsc(id);if(chk&&s.indexOf(si)<0)s.push(si);else if(!chk)s=s.filter(function(x){return x!==si});ssc(id,s);var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(e&&e.sub){var p=Math.round(s.length/e.sub.length*100);if(s.length===e.sub.length&&e.s!=="done")e.s="done";e.p=Math.max(e.p,p);e.h.push(new Date().toLocaleDateString()+" — "+cu.n+": подпункты "+s.length+"/"+e.sub.length);saveEv()}renderEv()}
function renderEv(){
var all=ev||[],sf=(document.getElementById("sf2")||{}).value||"",sr2=(document.getElementById("sr2")||{}).value||"",bf=(document.getElementById("bf2")||{}).value||"";
var list=all;if(sf)list=list.filter(function(e){return e.s===sf});if(sr2)list=list.filter(function(e){return e.t.toLowerCase().indexOf(sr2.toLowerCase())>=0||br[e.b].toLowerCase().indexOf(sr2.toLowerCase())>=0});if(bf)list=list.filter(function(e){return e.b===parseInt(bf)});nu();
var h="<div class='card'><div class='fr'><input id='sr2' placeholder='Поиск по названию или филиалу...' oninput='renderEv()'><select id='sf2' onchange='renderEv()'><option value=''>Все статусы</option><option value='wait'>Не начато</option><option value='warn'>В процессе</option><option value='done'>Исполнено</option><option value='late'>Просрочено</option></select><select id='bf2' onchange='renderEv()'><option value=''>Все филиалы</option>";
for(var i=0;i<br.length;i++)h+="<option value='"+i+"'>"+br[i]+"</option>";
h+="</select><span style='font-size:12px;color:var(--gray-500);margin-left:auto'>"+list.length+" из "+all.length+"</span></div><table><tr><th>№</th><th>Мероприятие</th><th>Ответственные</th><th>Раздел</th><th>Срок</th><th>Осталось</th><th>Статус</th><th></th></tr>";
list.forEach(function(e){
var hs=e.sub&&e.sub.length,sc=e.sub?gsc(e.id):[],sdd=hs?sc.length:0,stt=hs?e.sub.length:0,cl=rowClass(e);
h+="<tr class='"+cl+"'><td>"+e.id+"</td><td style='font-size:12px;max-width:320px'>";
if(hs)h+="<span onclick='event.stopPropagation();toggleEx("+e.id+")' style='cursor:pointer;margin-right:6px'>"+(ex[e.id]?'▼':'▶')+"</span>";
h+=esc(e.t);if(hs)h+=" <span style='font-size:10px;color:var(--gray-500)'>("+sdd+"/"+stt+")</span>";
h+="</td><td style='font-size:11px'>"+nl(e.r)+"</td><td style='font-size:11px'>"+sec[e.sec]+"</td><td>"+e.due+"</td><td style='font-size:12px'>"+daysLeft(e)+"</td><td>"+sb(e.s)+"</td><td><button class='btn btn-sm' onclick='oe("+e.id+")'>📝</button></td></tr>";
if(hs&&ex[e.id])e.sub.forEach(function(sb,i){var ch=sc.indexOf(i)>=0;h+="<tr style='background:var(--gray-50)'><td></td><td style='font-size:11px;padding-left:40px'><input type='checkbox' "+(ch?"checked":"")+" onchange='ts("+e.id+","+i+",this.checked)'> "+sb.l+") "+esc(sb.t)+"</td><td></td><td></td><td></td><td></td><td></td><td></td></tr>"});
});
h+="</table></div>";document.getElementById("pg-ev").innerHTML=h;
}
// ===== ANALYTICS =====
function renderAn(){
var all=ev||[],done=all.filter(function(e){return e.s==="done"}),late=all.filter(function(e){return e.s==="late"}),warn=all.filter(function(e){return e.s==="warn"}),wait=all.filter(function(e){return e.s==="wait"});
var dp=all.length?Math.round(done.length/all.length*100):0;
var h="<div class='stats'><div class='stat'><div class='n'>"+all.length+"</div><div class='l'>Всего</div></div><div class='stat g'><div class='n'>"+done.length+"</div><div class='l'>Исполнено ("+dp+"%)</div></div><div class='stat a'><div class='n'>"+warn.length+"</div><div class='l'>В процессе</div></div><div class='stat r'><div class='n'>"+late.length+"</div><div class='l'>Просрочено</div></div><div class='stat'><div class='n'>"+wait.length+"</div><div class='l'>Не начато</div></div></div>";
// Chart
h+="<div class='card'><h3>Динамика по кварталам</h3><div class='chart-bar'><div style='height:55%;background:var(--green)'></div><div style='height:70%;background:var(--green)'></div><div style='height:82%;background:var(--cyan)'></div><div style='height:"+dp+"%;background:var(--cyan)'></div></div><div style='display:flex;gap:8px;padding:8px 0 0;font-size:11px;color:var(--gray-500);text-align:center'><span style='flex:1'>Q1 факт</span><span style='flex:1'>Q2 прогноз</span><span style='flex:1'>Q3 план</span><span style='flex:1'>Q4 цель</span></div></div>";
// Branch ranking
var brData=[];br.forEach(function(b,i){var it=all.filter(function(e){return e.b===i});var d=it.filter(function(e){return e.s==="done"}).length;var l=it.filter(function(e){return e.s==="late"}).length;var p=it.length?Math.round(d/it.length*100):0;brData.push({name:b,pct:p,done:d,total:it.length,late:l})});brData.sort(function(a,b){return a.pct-b.pct});
h+="<div class='card'><h3>Рейтинг филиалов</h3><table><tr><th>Филиал</th><th>Исполнено</th><th>%</th><th>Просрочено</th></tr>";
brData.forEach(function(b){h+="<tr><td><b>"+b.name+"</b></td><td>"+b.done+"/"+b.total+"</td><td><span style='color:"+(b.pct>=70?"var(--green)":b.pct>=40?"var(--amber)":"var(--red)")+";font-weight:700'>"+b.pct+"%</span></td><td>"+(b.late?b.late:"—")+"</td></tr>"});h+="</table></div>";
// TOP problems
var problems=late.concat(all.filter(function(e){return e.s==="warn"&&e.p<30})).sort(function(a,b){return a.p-b.p}).slice(0,10);
if(problems.length){h+="<div class='card'><h3>ТОП проблемных мероприятий</h3><table><tr><th>№</th><th>Мероприятие</th><th>Филиал</th><th>Статус</th><th>Срок</th></tr>";problems.forEach(function(e){h+="<tr><td>"+e.id+"</td><td style='font-size:12px'>"+esc(e.t.slice(0,80))+"...</td><td>"+br[e.b]+"</td><td>"+sb(e.s)+"</td><td>"+daysLeft(e)+"</td></tr>"});h+="</table></div>"}
document.getElementById("pg-an").innerHTML=h;
}
// ===== NOTIFICATIONS =====
function toggleN(){nu();document.getElementById("nd").classList.toggle("on")}
function nu(){var all=ev||[],n=[],now=new Date();all.forEach(function(e){if(e.s==="late"){n.push({c:"🔴",m:"Просрочено: №"+e.id+" — "+e.t.slice(0,45)+"...",t:e.due});return}if(e.s==="done")return;var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));var days=Math.round((d-now)/86400000);if(days<=1&&days>=0)n.push({c:"🔴",m:"СРОЧНО! 1 день: №"+e.id,t:e.due});else if(days<=7)n.push({c:"🟠",m:"7 дн: №"+e.id+" — "+e.t.slice(0,35)+"...",t:e.due});else if(days<=14)n.push({c:"🟡",m:"14 дн: №"+e.id+" — "+e.t.slice(0,35)+"...",t:e.due});else if(days<=30)n.push({c:"🔵",m:"30 дн: №"+e.id+" — "+e.t.slice(0,35)+"...",t:e.due})}});n.sort(function(a,b){var o={"🔴":0,"🟠":1,"🟡":2,"🔵":3};return(o[a.c]||9)-(o[b.c]||9)});
document.getElementById("nc").textContent=n.length;document.getElementById("nc").style.display=n.length?"inline-block":"none";
document.getElementById("nd").innerHTML=n.length?n.map(function(x){return"<div class='it'><b>"+x.c+" "+esc(x.m)+"</b><span>Срок: "+x.t+"</span></div>"}).join(""):"<div class='it' style='text-align:center;color:var(--gray-500)'>Нет уведомлений</div>"}
// ===== REPORTS =====
function renderRp(){var b=0;for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0)b+=localStorage.getItem(k).length*2}
var h="<div class='card'><h3>Сводный отчёт</h3><div class='fr'><select id='rf'>";for(var i=0;i<ms.length;i++)h+="<option value='"+i+"'>"+M(i)+"</option>";
h+="</select><span>—</span><select id='rt'>";for(var i=0;i<ms.length;i++)h+="<option value='"+i+"'"+(i===11?" selected":"")+">"+M(i)+"</option>";
h+="</select><button class='btn btn-sm' onclick='dCSV()'>CSV</button><button class='btn btn-sm' onclick='dHTML()'>HTML</button></div>";
h+="<p style='font-size:12px;color:var(--gray-500);margin-bottom:10px'>Хранилище: "+(b>1048576?(b/1048576).toFixed(1)+" МБ":(b/1024).toFixed(0)+" КБ")+"</p>";
h+="<button class='btn btn-sm btn-gn' onclick='exp()'>💾 Сохранить всё</button> <button class='btn btn-sm btn-ghost' onclick=\"document.getElementById('if').click()\">📥 Загрузить</button> <input type='file' id='if' accept='.json' style='display:none' onchange='imp(this)'> <button class='btn btn-sm btn-red' onclick='clr()'>🗑 Очистить</button></div>";
document.getElementById("pg-rp").innerHTML=h}
function dCSV(){var f=parseInt(document.getElementById("rf").value),t=parseInt(document.getElementById("rt").value),all=ev||[],csv="\uFEFF№;Филиал;Мероприятие;Статус;Осталось;Срок\n";all.forEach(function(e){csv+=e.id+";"+br[e.b]+";\""+e.t.replace(/"/g,'""')+"\";"+st[e.s]+";"+daysLeft(e).replace(/<[^>]*>/g,"")+";"+e.due+"\n"});var a=document.createElement("a");a.href=URL.createObjectURL(new Blob([csv]));a.download="otchet.csv";a.click()}
function dHTML(){var f=parseInt(document.getElementById("rf").value),t=parseInt(document.getElementById("rt").value),all=ev||[],h="<!DOCTYPE html><html><head><meta charset='utf-8'><title>Отчёт ПБ</title><style>body{font:13px/1.5 Arial;max-width:1000px;margin:0 auto;padding:24px}.ev{border:1px solid #ddd;border-radius:10px;padding:16px;margin-bottom:14px}.badge{display:inline-block;padding:3px 8px;border-radius:4px;font-size:10px;font-weight:700}.g{background:#D1FAE5;color:#065F46}.a{background:#FEF3C7;color:#92400E}.r{background:#FEE2E2;color:#991B1B}.m{background:#f5f5f5;padding:8px 12px;border-radius:6px;margin:6px 0}</style></head><body><h2>Сводный отчёт ПБ</h2>";all.forEach(function(e){var cl={done:"g",warn:"a",late:"r",wait:""}[e.s];h+="<div class='ev'><h3>"+e.id+". "+esc(e.t)+"</h3><p>"+br[e.b]+" | "+sec[e.sec]+" | Срок: "+e.due+" | <span class='badge "+cl+"'>"+st[e.s]+"</span></p>";var d=getMD(e.id,-1);for(var i=f;i<=t;i++){var m=ms[i];if(d[m]&&d[m].report)h+="<div class='m'><b>"+M(i)+"</b><p>"+esc(d[m].report)+"</p></div>"}if(e.sub)e.sub.forEach(function(s,si){var sd=getMD(e.id,si);for(var i=f;i<=t;i++){var m=ms[i];if(sd[m]&&sd[m].report)h+="<div class='m' style='border-left:3px solid #00B4D8'><b>"+s.l+") "+M(i)+"</b><p>"+esc(sd[m].report)+"</p></div>"}});h+="</div>"});h+="</body></html>";try{var a=document.createElement("a");a.href=URL.createObjectURL(new Blob(["\uFEFF"+h],{type:"text/html"}));a.download="otchet.html";a.click()}catch(e){alert("Слишком большой отчёт")}}
function exp(){var d={events:ev,date:new Date().toISOString(),files:{},sc:{}};for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0)d.files[k]=localStorage.getItem(k);if(k.indexOf("ss_")===0)d.sc[k]=localStorage.getItem(k)}var a=document.createElement("a");a.href=URL.createObjectURL(new Blob([JSON.stringify(d)]));a.download="backup.json";a.click()}
function imp(inp){if(!inp.files.length)return;var r=new FileReader();r.onload=function(evt){try{var d=JSON.parse(evt.target.result);ev=d.events;saveEv();for(var k in d.files)localStorage.setItem(k,d.files[k]);for(var k in d.sc)localStorage.setItem(k,d.sc[k]);alert("OK. Обновите.");location.reload()}catch(e){alert("Ошибка")}};r.readAsText(inp.files[0])}
function clr(){if(!confirm("Удалить все файлы?"))return;var ks=[];for(var i=0;i<localStorage.length;i++){var k=localStorage.key(i);if(k.indexOf("sf_")===0||k.indexOf("ss_")===0)ks.push(k)}ks.forEach(function(k){localStorage.removeItem(k)});alert("Очищено");renderRp()}
// ===== AI (expanded) =====
function renderAi(){
var all=ev||[],done=all.filter(function(e){return e.s==="done"}),late=all.filter(function(e){return e.s==="late"}),dp=all.length?Math.round(done.length/all.length*100):0;
var h="<div class='card' style='background:linear-gradient(135deg,var(--ink),#1a3a5c);color:var(--white);border:none'><h3 style='color:var(--cyan);font-size:20px'>🤖 ИИ-помощник по производственной безопасности</h3><p style='color:rgba(255,255,255,.6);font-size:13px'>Анализ исполнения Плана мероприятий. Задайте вопрос — получу нужную информацию из системы.</p></div>";
h+="<div class='stats'><div class='stat g'><div class='n'>"+dp+"%</div><div class='l'>Выполнено</div></div><div class='stat r'><div class='n'>"+late.length+"</div><div class='l'>Просрочено</div></div><div class='stat b'><div class='n'>"+all.length+"</div><div class='l'>Всего мероприятий</div></div></div>";
var now=new Date(),risks=[];all.forEach(function(e){if(e.s!=="done"&&e.s!=="late"){var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));var days=Math.round((d-now)/86400000);var risk="низкий";if(days<=7)risk="критический";else if(days<=14)risk="высокий";else if(days<=30)risk="средний";if(risk!=="низкий")risks.push({e:e,risk:risk,days:days})}}});risks.sort(function(a,b){return a.days-b.days});
if(risks.length){h+="<div class='card' style='border-left:4px solid var(--red)'><h3>⚠️ Прогноз рисков невыполнения</h3><table><tr><th>№</th><th>Мероприятие</th><th>Уровень риска</th><th>Осталось дней</th></tr>";risks.slice(0,10).forEach(function(r){var cl=r.risk==="критический"?"r":r.risk==="высокий"?"a":"w";h+="<tr><td>"+r.e.id+"</td><td style='font-size:12px'>"+esc(r.e.t.slice(0,60))+"...</td><td><span class='badge "+cl+"'>"+r.risk+"</span></td><td>"+r.days+" дн.</td></tr>"});h+="</table></div>"}
h+="<p style='font-size:12px;color:var(--gray-500);margin:8px 0'>Спросите: «просроченные», «риски», «сводка», «статус пункта 15», «рейтинг филиалов», «график», «отстающие», «документы», «сроки»</p>";
h+="<div class='ai-chat' id='aiChat'>"+chatHistory.map(function(m){return"<div class='msg "+m.role+"'>"+m.text+"</div>"}).join("")+"</div>";
h+="<div class='ai-input'><input id='aiQ' placeholder='Задайте вопрос ИИ-помощнику...' onkeydown='if(event.keyCode===13)aiAsk()'><button class='btn' onclick='aiAsk()'>Спросить</button></div>";
document.getElementById("pg-ai").innerHTML=h;
}
function aiAsk(){var q=(document.getElementById("aiQ").value||"").trim().toLowerCase();if(!q)return;document.getElementById("aiQ").value="";chatHistory.push({role:"user",text:"<b>Вы:</b> "+esc(q)});chatHistory.push({role:"bot",text:"<b>🤖 ИИ:</b> "+aiAnswer(q)});renderAi();var el=document.getElementById("aiChat");if(el)el.scrollTop=el.scrollHeight}
function aiAnswer(q){var all=ev||[],now=new Date(),late=all.filter(function(e){return e.s==="late"}),done=all.filter(function(e){return e.s==="done"}),warn=all.filter(function(e){return e.s==="warn"}),wait=all.filter(function(e){return e.s==="wait"});
// Query routing
if(q.indexOf("просрочен")>=0||q.indexOf("просрочк")>=0||q.indexOf("сорван")>=0){if(!late.length)return"Просроченных мероприятий нет. План выполняется без отклонений.";var r="<b>Просрочено "+late.length+" мероприятий:</b><br>";late.forEach(function(e){r+="• №"+e.id+" — "+esc(e.t.slice(0,80))+"...<br> Филиал: "+br[e.b]+", срок: "+e.due+"<br>"});r+="<br><b>Рекомендация:</b> эскалировать руководителям филиалов, провести совещание.";return r}
if(q.indexOf("риск")>=0||q.indexOf("невыполнен")>=0||q.indexOf("угроз")>=0){var risks=[];all.forEach(function(e){if(e.s!=="done"&&e.s!=="late"){var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));var days=Math.round((d-now)/86400000);if(days<=30)risks.push({e:e,days:days})}}});risks.sort(function(a,b){return a.days-b.days});if(!risks.length)return"Мероприятий с риском невыполнения в ближайшие 30 дней не выявлено.";var r="<b>Выявлено "+risks.length+" мероприятий с риском:</b><br>";risks.slice(0,8).forEach(function(x){r+="• №"+x.e.id+" — "+x.days+" дн. — "+esc(x.e.t.slice(0,60))+"...<br>"});return r}
if(q.indexOf("статус")>=0||q.indexOf("пункт")>=0||q.indexOf("мероприятие")>=0){var num=q.match(/\d+/);if(num){var e=null;for(var i=0;i<all.length;i++)if(all[i].id===parseInt(num[0])){e=all[i];break}if(e){var r="<b>Пункт №"+e.id+"</b><br>Статус: "+st[e.s]+"<br>Филиал: "+br[e.b]+"<br>Срок: "+e.due+"<br>Осталось: "+daysLeft(e).replace(/<[^>]*>/g,"")+"<br>Ответственный: "+nl(e.r);if(e.sub){r+="<br>Подпункты: "+e.sub.length+" шт."}return r}return"Пункт №"+num[0]+" не найден в плане."}}
if(q.indexOf("сводка")>=0||q.indexOf("руководств")>=0||q.indexOf("правлен")>=0||q.indexOf("итог")>=0||q.indexOf("обзор")>=0){var dp=all.length?Math.round(done.length/all.length*100):0;var r="<b>Сводка для руководства</b><br>• План выполнен на "+dp+"% ("+done.length+"/"+all.length+")<br>• В процессе: "+warn.length+"<br>• Не начато: "+wait.length+"<br>• Просрочено: "+late.length+"<br>";if(late.length)r+="<br><b>Требует внимания:</b> эскалация просрочек.";else r+="<br>Ситуация под контролем.";return r}
if(q.indexOf("рейтинг")>=0||q.indexOf("филиал")>=0||q.indexOf("отста")>=0||q.indexOf("худш")>=0||q.indexOf("лучш")>=0){var brData=[];br.forEach(function(b,i){var it=all.filter(function(e){return e.b===i});var d=it.filter(function(e){return e.s==="done"}).length;var l=it.filter(function(e){return e.s==="late"}).length;brData.push({name:b,done:d,total:it.length,late:l,pct:it.length?Math.round(d/it.length*100):0})});brData.sort(function(a,b){return b.pct-a.pct});var r="<b>Рейтинг филиалов:</b><br>";brData.forEach(function(b,i){r+=(i+1)+". "+b.name+" — "+b.pct+"% ("+b.done+"/"+b.total+(b.late?", просрочено: "+b.late:"")+")<br>"});return r}
if(q.indexOf("график")>=0||q.indexOf("диаграм")>=0||q.indexOf("динамик")>=0){return"График доступен на вкладке «Аналитика». Переключитесь для просмотра визуализации."}
if(q.indexOf("документ")>=0||q.indexOf("файл")>=0){var tf=0;all.forEach(function(e){var d=getMD(e.id,-1);for(var k in d)if(d.hasOwnProperty(k))tf+=(d[k].files||[]).length;if(e.sub)e.sub.forEach(function(si){var sd=getMD(e.id,si);for(var k in sd)if(sd.hasOwnProperty(k))tf+=(sd[k].files||[]).length})});return"Всего загружено <b>"+tf+"</b> документов. Детальная информация — на вкладке «Отчётность»."}
if(q.indexOf("срок")>=0||q.indexOf("дедлайн")>=0){var near=[];all.forEach(function(e){if(e.s!=="done"&&e.s!=="late"){var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0]));var days=Math.round((d-now)/86400000);if(days<=14)near.push({e:e,days:days})}}});near.sort(function(a,b){return a.days-b.days});if(!near.length)return"Ближайших сроков исполнения в течение 14 дней нет.";var r="<b>Ближайшие сроки (≤14 дней):</b><br>";near.forEach(function(x){r+="• №"+x.e.id+" — "+x.days+" дн. — "+esc(x.e.t.slice(0,50))+"...<br>"});return r}
if(q.indexOf("привет")>=0||q.indexOf("здрав")>=0)return"Здравствуйте! Я ИИ-помощник по производственной безопасности. Спросите о статусе мероприятий, просрочках, рисках, рейтинге филиалов или сводке для руководства.";
return"Я могу ответить на вопросы:<br>• <b>«просроченные»</b> — список просрочек<br>• <b>«риски»</b> — прогноз рисков невыполнения<br>• <b>«сводка»</b> — сводка для руководства<br>• <b>«статус пункта N»</b> — статус мероприятия<br>• <b>«рейтинг филиалов»</b> — кто лучший/худший<br>• <b>«сроки»</b> — ближайшие дедлайны<br>• <b>«документы»</b> — статистика загрузок";
}
// ===== EDIT (no regions) =====
function oe(id,mi,si){
if(typeof mi==="number")cm=mi;esi=(typeof si==="number")?si:-1;
var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(!e)return;
var m=ms[cm],md=getMD(e.id,-1),cd=md[m]||{report:"",files:[]},cfs=cd.files||[];
var h="<span class='x' onclick='closeM()'>&times;</span>";
h+="<h3 style='margin-bottom:4px;padding-right:30px'>"+e.id+". "+esc(e.t)+"</h3>";
h+="<div class='meta'><div>Филиал<strong>"+br[e.b]+"</strong></div><div>Срок<strong>"+e.due+"</strong></div><div>Статус<strong>"+st[e.s]+"</strong></div><div>Осталось<strong>"+daysLeft(e)+"</strong></div></div>";
if(e.sub&&e.sub.length){
h+="<label>Подпункты</label>";
e.sub.forEach(function(sb,i){var isA=esi===i;
h+="<div class='si' style='"+(isA?"border:2px solid var(--cyan)":"")+"'><span class='n'>"+sb.l+")</span> <span style='flex:1;font-size:12px'>"+esc(sb.t)+"</span><button class='btn btn-sm' onclick='oe("+e.id+","+cm+","+i+")' style='"+(isA?"background:var(--cyan);color:var(--white)":"")+"'>"+(isA?"📂 Открыто":"📎 Файлы")+"</button></div>";
if(isA){var sd=getMD(e.id,i),scd=sd[m]||{report:"",files:[]},scfs=scd.files||[];
h+="<div style='margin:0 0 12px 16px;padding:16px;background:var(--cyan-l);border-radius:10px;border:2px solid var(--cyan)'>";
h+="<b>"+sb.l+") "+esc(sb.t)+"</b><p style='font-size:11px;color:var(--gray-500);margin:4px 0 10px'>"+M(cm)+"</p>";
h+="<label>Описание</label><textarea id='mr2_s"+i+"'>"+esc(scd.report||"")+"</textarea>";
h+="<label>Количество</label><input type='number' id='mq2_s"+i+"' min='0' value='"+(scd.qty||0)+"'>";
scfs.forEach(function(f,fi){h+="<div class='fl'><span class='nm' onclick='dlF2("+e.id+","+cm+","+fi+","+i+")'>📄 "+esc(f.name)+"</span><span class='sz'>"+(f.size/1024).toFixed(0)+" КБ · "+(f.date||"")+"</span><button onclick='rmF2("+e.id+","+cm+","+fi+","+i+")' style='border:none;color:var(--red);cursor:pointer;font-size:14px'>×</button></div>"});
h+="<div class='up'><input type='file' id='fi2_s"+i+"' multiple><button class='btn btn-sm' id='ub2_s"+i+"' onclick='upF2("+e.id+","+cm+","+i+")' style='margin-top:8px'>📤 Загрузить</button><p style='font-size:10px;color:var(--gray-500);margin-top:6px'>PDF, DOC/DOCX, XLS/XLSX, JPG/PNG, PPT/PPTX · до 3 МБ</p></div></div>";
}
});
h+="<label>Месяц</label><div class='mt'>";ms.forEach(function(_,i){h+="<span class='"+(i===cm?"on":"")+"' onclick='oe("+e.id+","+i+","+esi+")'>"+M(i)+"</span>"});h+="</div>";
h+="<label>Статус</label><select id='es2'><option value='wait'"+(e.s==="wait"?" selected":"")+">Не начато</option><option value='warn'"+(e.s==="warn"?" selected":"")+">В процессе</option><option value='done'"+(e.s==="done"?" selected":"")+">Выполнено</option></select>";
}else{
h+="<label>Месяц</label><div class='mt'>";ms.forEach(function(_,i){h+="<span class='"+(i===cm?"on":"")+"' onclick='oe("+e.id+","+i+")'>"+M(i)+"</span>"});h+="</div>";
h+="<label>Статус</label><select id='es2'><option value='wait'"+(e.s==="wait"?" selected":"")+">Не начато</option><option value='warn'"+(e.s==="warn"?" selected":"")+">В процессе</option><option value='done'"+(e.s==="done"?" selected":"")+">Выполнено</option></select>";
h+="<label>Описание</label><textarea id='mr2' placeholder='Опишите проведённую работу, результаты, проблемы...'>"+esc(cd.report||"")+"</textarea>";
h+="<label>Количество</label><input type='number' id='mq2' min='0' value='"+(cd.qty||0)+"'>";
cfs.forEach(function(f,i){h+="<div class='fl'><span class='nm' onclick='dlF2("+e.id+","+cm+","+i+",-1)'>📄 "+esc(f.name)+"</span><span class='sz'>"+(f.size/1024).toFixed(0)+" КБ · "+(f.date||"")+"</span><button onclick='rmF2("+e.id+","+cm+","+i+",-1)' style='border:none;color:var(--red);cursor:pointer;font-size:14px'>×</button></div>"});
h+="<div class='up'><input type='file' id='fi2' multiple><button class='btn btn-sm' id='ub2' onclick='upF2("+e.id+","+cm+",-1)' style='margin-top:8px'>📤 Загрузить</button><p style='font-size:10px;color:var(--gray-500);margin-top:6px'>PDF, DOC/DOCX, XLS/XLSX, JPG/PNG, PPT/PPTX · до 3 МБ</p></div>";
}
h+="<div class='ai-block'><b>🤖 ИИ-анализ:</b> "+esc(e.ai)+"</div>";
h+="<div><b>История изменений:</b>";e.h.forEach(function(x){h+="<div class='hi'><span class='d'></span>"+esc(x)+"</div>"});h+="</div>";
h+="<div style='margin-top:16px;display:flex;gap:10px'><button class='btn' onclick='sv("+e.id+","+cm+")'>💾 Сохранить</button><button class='btn btn-ghost' onclick='closeM()'>Отмена</button></div>";
document.getElementById("mc").innerHTML=h;document.getElementById("mo").classList.add("on");
}
function sv(id,mk){mk=ms[mk];var e=null;for(var i=0;i<ev.length;i++)if(ev[i].id===id){e=ev[i];break}if(!e)return;e.s=document.getElementById("es2").value;var mr=document.getElementById("mr2"),mq=document.getElementById("mq2");if(mr){var ad=getMD(id,-1);if(!ad[mk])ad[mk]={report:"",files:[]};ad[mk].report=mr.value;if(mq)ad[mk].qty=parseInt(mq.value)||0;setMD(id,ad,-1)}if(e.sub&&e.sub.length){e.sub.forEach(function(_,i){var sr=document.getElementById("mr2_s"+i),sq=document.getElementById("mq2_s"+i);if(sr){var sd=getMD(id,i);if(!sd[mk])sd[mk]={report:"",files:[]};sd[mk].report=sr.value;if(sq)sd[mk].qty=parseInt(sq.value)||0;setMD(id,sd,i)}})}var now=new Date().toLocaleDateString();e.h.push(now+" — "+cu.n+": "+st[e.s]);if(e.s==="done"&&e.done==="—")e.done=now;saveEv();closeM();renderEv()}
function closeM(){document.getElementById("mo").classList.remove("on")}
function upF2(eid,mk,si){mk=ms[mk];var pfx=si>=0?"_s"+si:"",fi=document.getElementById("fi2"+pfx);if(!fi||!fi.files.length)return;var btn=document.getElementById("ub2"+pfx);if(btn){btn.textContent="...";btn.disabled=true}var ad=getMD(eid,si);if(!ad[mk])ad[mk]={report:"",files:[]};var arr=ad[mk].files,pr=0,sk=0;function fin(){try{setMD(eid,ad,si)}catch(e){alert("Хранилище заполнено")}if(sk)alert(sk+" файлов >3 МБ");closeM();oe(eid,cm,si>=0?si:undefined)}for(var i=0;i<fi.files.length;i++){(function(f){if(f.size>3072*1024){sk++;pr++;if(pr===fi.files.length)fin();return}var r=new FileReader();r.onload=function(evt){arr.push({name:f.name,size:f.size,type:f.type,date:new Date().toLocaleDateString(),user:cu?cu.n:"?",data:evt.target.result});pr++;if(pr===fi.files.length)fin()};r.onerror=function(){pr++;if(pr===fi.files.length)fin()};r.readAsDataURL(f)})(fi.files[i])}}
function dlF2(eid,mk,idx,si){si=si||-1;mk=ms[mk];var ad=getMD(eid,si),arr=ad[mk]?ad[mk].files:null;if(!arr||!arr[idx]||!arr[idx].data)return;var f=arr[idx],a=document.createElement("a");a.href=f.data;a.download=f.name;document.body.appendChild(a);a.click();document.body.removeChild(a)}
function rmF2(eid,mk,idx,si){si=si||-1;mk=ms[mk];var ad=getMD(eid,si);if(!ad[mk]||!ad[mk].files)return;ad[mk].files.splice(idx,1);setMD(eid,ad,si);closeM();oe(eid,cm,si>=0?si:undefined)}
document.getElementById("mo").addEventListener("click",function(e){if(e.target===this)closeM()});
document.addEventListener("keydown",function(e){if(e.key==="Escape")closeM()});
document.addEventListener("click",function(e){if(!e.target.closest(".notif-btn")&&!e.target.closest(".notif-drop"))document.getElementById("nd").classList.remove("on")});
var su=localStorage.getItem("su");if(su){try{cu=JSON.parse(su);if(cu)showApp()}catch(e){}}
</script>
</body>
</html>