samruk-ai-agent/index.html

278 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>План ПБ 2026 — Казахтелеком</title>
<style>
:root{--b:#0B1A2E;--c:#00B4D8;--w:#fff;--g5:#64748B;--g1:#F1F5F9;--g2:#E2E8F0;--gn:#10B981;--rd:#EF4444;--am:#F59E0B}
*{box-sizing:border-box;margin:0;padding:0}
body{font:14px/1.4 Arial,sans-serif;color:var(--b);background:var(--g1)}
input,select,textarea,button{font:inherit;outline:none}
.btn{background:var(--c);color:var(--w);padding:10px 20px;border-radius:8px;font-weight:600;font-size:14px;border:none;cursor:pointer}.btn:hover{opacity:.85}
.btn-sm{padding:6px 14px;font-size:12px}.btn-r{background:var(--rd);color:#fff}.btn-g{background:var(--gn);color:#fff}.btn-gh{background:transparent;color:var(--g5);border:1px solid var(--g2)}
#loginBox{display:flex;align-items:center;justify-content:center;min-height:100vh;background:linear-gradient(135deg,#0B1A2E,#1a3a5c)}
#loginBox>div{background:var(--w);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;margin-bottom:4px}#loginBox .logo span{color:var(--c)}
#loginBox .sub{color:var(--g5);font-size:13px;margin-bottom:32px}
#loginBox input{display:block;width:100%;padding:14px 16px;border:2px solid var(--g2);border-radius:10px;font-size:14px;margin-bottom:16px}
#loginBox input:focus{border-color:var(--c)}
#app{display:none;min-height:100vh}
.sidebar{width:240px;background:var(--b);color:var(--w);position:fixed;top:0;left:0;bottom:0;z-index:10;display:flex;flex-direction:column}
.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(--c)}
.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;border-left:3px solid transparent}
.sidebar nav a:hover,.sidebar nav a.on{color:var(--w);background:rgba(0,180,216,.1);border-left-color:var(--c)}
.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:240px;flex:1;padding:24px 32px}
.topbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}
.topbar h2{font-size:22px;font-weight:700}
.topbar .right{display:flex;align-items:center;gap:16px}
.notif-btn{position:relative;background:var(--w);border:1px solid var(--g2);border-radius:10px;padding:8px 12px;cursor:pointer;font-size:18px}
.notif-btn .cnt{position:absolute;top:-6px;right:-6px;background:var(--rd);color:#fff;border-radius:100px;font-size:10px;padding:2px 6px;font-weight:700}
.notif-drop{position:absolute;top:52px;right:0;width:400px;max-width:90vw;background:var(--w);border:1px solid var(--g2);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(--g1);font-size:13px}.notif-drop .it b{display:block;margin-bottom:3px}.notif-drop .it span{font-size:11px;color:var(--g5)}
.card{background:var(--w);border-radius:14px;padding:24px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04);border:1px solid var(--g1)}
.card h3{font-size:17px;font-weight:700;margin-bottom:12px}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:14px;margin-bottom:20px}
.stat{background:var(--w);border-radius:12px;padding:20px 24px;box-shadow:0 1px 3px rgba(0,0,0,.04);border:1px solid var(--g1);text-align:center}
.stat .n{font-size:30px;font-weight:800}.stat .l{font-size:12px;color:var(--g5);margin-top:4px}
.stat.r .n{color:var(--rd)}.stat.g .n{color:var(--gn)}.stat.a .n{color:var(--am)}.stat.b .n{color:var(--c)}
table{width:100%;border-collapse:collapse}th,td{padding:10px 14px;text-align:left;font-size:13px}
th{font-weight:600;color:var(--g5);font-size:11px;text-transform:uppercase;border-bottom:2px solid var(--g1);background:var(--g1)}
td{border-bottom:1px solid var(--g1)}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(--g1);color:var(--g5)}
.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(--g2);border-radius:8px;font-size:13px;background:var(--w)}.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(--w);border-radius:16px;max-width:720px;width:94vw;max-height:88vh;overflow-y:auto;padding:32px}
.modal .x{float:right;border:none;background:none;font-size:26px;cursor:pointer;color:var(--g5)}
.modal label{display:block;font-size:12px;font-weight:600;color:var(--g5);margin-bottom:4px;margin-top:12px}
.modal input,.modal select,.modal textarea{width:100%;padding:10px 14px;border:1px solid var(--g2);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(--g5)}.meta strong{display:block;color:var(--b);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(--g2);border-radius:100px;font-size:12px;font-weight:600;cursor:pointer}.mt span.on{background:var(--c);color:var(--w);border-color:var(--c)}
.si{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--g1);border-radius:8px;margin-bottom:6px;font-size:13px}.si .n{font-weight:700;color:var(--c);font-size:15px;min-width:20px}
.fl{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--g1);border-radius:8px;margin-bottom:4px;font-size:12px}.fl .nm{font-weight:600;cursor:pointer}.fl .nm:hover{color:var(--c)}.fl .sz{font-size:10px;color:var(--g5)}
.up{border:2px dashed var(--g2);border-radius:10px;padding:14px;margin-top:8px;text-align:center}
.ai-block{background:#E0F7FA;border-radius:8px;padding:12px;margin:12px 0;font-size:13px}
.hi{font-size:11px;color:var(--g5);padding:2px 0}.hi .d{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--c);margin-right:6px;vertical-align:middle}
.ai-chat{border:1px solid var(--g2);border-radius:10px;padding:14px;max-height:320px;overflow-y:auto;margin-bottom:12px}.ai-chat .msg{margin-bottom:8px;padding:10px 14px;border-radius:10px;font-size:13px;max-width:88%}.ai-chat .user{background:var(--c);color:var(--w);margin-left:auto}.ai-chat .bot{background:var(--g1);color:var(--b)}
.ai-input{display:flex;gap:8px}.ai-input input{flex:1;padding:10px 14px;border:1px solid var(--g2);border-radius:8px;font-size:13px}
@media(max-width:768px){.sidebar{width:0;overflow:hidden}.main{margin-left:0;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(--rd);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">
<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-gh 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 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(--gn)">✓</span>';
if(e.s==="late")return'<span style="color:var(--rd);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(--rd);font-weight:700">'+Math.abs(days)+' дн.</span>';
if(days<=7)return'<span style="color:var(--rd);font-weight:600">'+days+' дн.</span>';
if(days<=14)return'<span style="color:var(--am);font-weight:600">'+days+' дн.</span>';
if(days<=30)return'<span style="color:var(--am)">'+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("se5");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("se5",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()+": подпункты "+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(--g5);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:300px'>";
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(--g5)'>("+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(--g1)'><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"}),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>";
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 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(--gn)":b.pct>=40?"var(--am)":"var(--rd)")+";font-weight:700'>"+b.pct+"%</span></td><td>"+(b.late?b.late:"—")+"</td></tr>"});h+="</table></div>";
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(--g5)'>Нет уведомлений</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(--g5)'>Хранилище: "+(b>1048576?(b/1048576).toFixed(1)+" МБ":(b/1024).toFixed(0)+" КБ")+"</p>";
h+="<button class='btn btn-sm btn-g' onclick='exp()'>💾 Сохранить всё</button> <button class='btn btn-sm btn-gh' 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-r' 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]+";"+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 =====
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(--b),#1a3a5c);color:var(--w);border:none'><h3 style='color:var(--c);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>";
h+="<p style='font-size:12px;color:var(--g5)'>Спросите: <b>сводка</b> · <b>риски</b> · <b>рейтинг филиалов</b> · <b>советник</b> · <b>статус пункта N</b> · <b>просроченные</b> · <b>аудит</b></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"}),dp=all.length?Math.round(done.length/all.length*100):0;
function bs(){var r=[];br.forEach(function(b,i){var it=all.filter(function(e){return e.b===i}),d=it.filter(function(e){return e.s==="done"}).length,l=it.filter(function(e){return e.s==="late"}).length;r.push({name:b,done:d,total:it.length,late:l,pct:it.length?Math.round(d/it.length*100):0})});r.sort(function(a,b){return b.pct-a.pct});return r}
function cr(e){if(e.s==="done")return{l:"отсутствует",p:0};if(e.s==="late")return{l:"критический",p:100};var s=0;var p=e.due.split(".");if(p.length===3){var d=new Date(parseInt(p[2]),parseInt(p[1])-1,parseInt(p[0])),days=Math.round((d-now)/86400000);if(days<=7)s+=40;else if(days<=14)s+=25;else if(days<=30)s+=15}if(e.p<20)s+=25;else if(e.p<50)s+=15;var md=getMD(e.id,-1),hr=false;for(var k in md)if(md.hasOwnProperty(k)&&md[k]&&md[k].report)hr=true;if(!hr)s+=20;var l=s>=60?"критический":s>=35?"высокий":s>=15?"средний":"низкий";return{l:l,p:Math.min(s,95)}}
if(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,70))+"...<br>"});return r}
if(q.indexOf("сводка")>=0||q.indexOf("ежедн")>=0)return"<b>Сводка на "+new Date().toLocaleDateString()+"</b><br>• План: "+dp+"%<br>• Просрочено: "+late.length+"<br>• В процессе: "+warn.length+"<br>→ "+(late.length?"Эскалация просрочек":"Ситуация под контролем");
if(q.indexOf("риск")>=0){var risks=[];all.forEach(function(e){if(e.s!=="done"){var c=cr(e);if(c.l!=="низкий")risks.push({e:e,risk:c})}});risks.sort(function(a,b){return b.risk.p-a.risk.p});if(!risks.length)return"Рисков не выявлено.";var r="<b>Риски:</b><br>";risks.slice(0,8).forEach(function(x){r+="• №"+x.e.id+" — "+x.risk.p+"% ("+x.risk.l+")<br>"});return r}
if(q.indexOf("рейтинг")>=0||q.indexOf("филиал")>=0){var bsd=bs(),r="<b>Рейтинг:</b><br>";bsd.forEach(function(b,i){r+=(i+1)+". "+b.name+" — "+b.pct+"%<br>"});return r}
if(q.indexOf("советник")>=0||q.indexOf("директор")>=0){var bsd=bs();return"<b>👔 Советник:</b><br>• План: "+dp+"%<br>• Просрочено: "+late.length+"<br>• Зона риска: "+bsd.slice(-3).map(function(b){return b.name}).join(", ")+"<br><br><b>Решения:</b><br>1. Совещание с отстающими<br>2. Еженедельный контроль<br>3. Запросить документы<br>4. Доклад Правлению";}
if(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)return"<b>Пункт №"+e.id+"</b><br>Статус: "+st[e.s]+"<br>Филиал: "+br[e.b]+"<br>Срок: "+e.due;return"Не найден."}}
if(q.indexOf("привет")>=0)return"👋 Я ИИ-помощник по ПБ. Спросите: сводка, риски, рейтинг, советник, статус пункта N.";
return"Спросите: <b>сводка</b> · <b>риски</b> · <b>рейтинг</b> · <b>советник</b> · <b>просроченные</b> · <b>статус пункта N</b>";
}
// ===== EDIT =====
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><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>";
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(--c)":"")+"'><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(--c);color:var(--w)":"")+"'>"+(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:#E0F7FA;border-radius:10px;border:2px solid var(--c)'>";
h+="<b>"+sb.l+") "+esc(sb.t)+"</b><p style='font-size:11px;color:var(--g5)'>"+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)+" КБ</span><button onclick='rmF2("+e.id+","+cm+","+fi+","+i+")' style='border:none;color:var(--rd);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(--g5)'>PDF, DOC, XLS, JPG, PPT · до 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>";
}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><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)+" КБ</span><button onclick='rmF2("+e.id+","+cm+","+i+",-1)' style='border:none;color:var(--rd);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(--g5)'>PDF, DOC, XLS, JPG, PPT · до 3 МБ</p></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+="<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-gh' 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>