samruk-ai-agent/index.html

334 lines
47 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>";
h+="<div class='fr' style='margin-bottom:16px'><button class='btn btn-sm' onclick='dAnCSV()'>📥 Скачать CSV (все)</button><button class='btn btn-sm btn-ghost' onclick='dAnHTML()'>📄 Скачать HTML (все)</button></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>"}
function dAnCSV(){var all=ev||[],csv="\uFEFF№;Филиал;Мероприятие;Подпункты;Раздел;Статус;Прогресс;Срок;Осталось;Факт;Описание\n";all.forEach(function(e){var rep="";var d=getMD(e.id,-1);for(var k in d)if(d.hasOwnProperty(k)&&d[k]&&d[k].report)rep+=d[k].report.replace(/"/g,'""')+"; ";csv+=e.id+";"+br[e.b]+";\""+e.t.replace(/"/g,'""')+"\";"+(e.sub?e.sub.length:"—")+";"+sec[e.sec]+";"+st[e.s]+";"+e.p+"%;"+e.due+";"+daysLeft(e).replace(/<[^>]*>/g,"")+";"+(e.done||"—")+";\""+rep+"\"\n"});var a=document.createElement("a");a.href=URL.createObjectURL(new Blob([csv]));a.download="analitika.csv";a.click()}
function dAnHTML(){var all=ev||[];var h="<!DOCTYPE html><html><head><meta charset='utf-8'><title>Аналитика ПБ</title><style>body{font:13px/1.5 Arial;max-width:1100px;margin:0 auto;padding:24px}h1{color:#0B1A2E}h2{color:#00B4D8;margin-top:24px}table{width:100%;border-collapse:collapse;margin-bottom:16px}th,td{padding:8px 12px;text-align:left;font-size:12px;border:1px solid #ddd}th{background:#0B1A2E;color:#fff;font-weight:600}.g{color:#10B981}.a{color:#F59E0B}.r{color:#EF4444}.w{color:#64748B}.done td{background:#f0fff4}.late td{background:#fff5f5}</style></head><body><h1>📊 Аналитика ПБ — все мероприятия</h1><p>Сформирован: "+new Date().toLocaleDateString()+"</p><table><tr><th>№</th><th>Мероприятие</th><th>Подпункты</th><th>Филиал</th><th>Раздел</th><th>Статус</th><th>Срок</th><th>Осталось</th><th>Факт</th></tr>";
all.forEach(function(e){var cl=e.s==="done"?"done":e.s==="late"?"late":"";h+="<tr class='"+cl+"'><td>"+e.id+"</td><td>"+esc(e.t)+"</td><td>"+(e.sub?e.sub.length:"—")+"</td><td>"+esc(br[e.b])+"</td><td>"+sec[e.sec]+"</td><td><b class='"+{done:"g",warn:"a",late:"r",wait:"w"}[e.s]+"'>"+st[e.s]+"</b></td><td>"+e.due+"</td><td>"+daysLeft(e).replace(/<[^>]*>/g,"")+"</td><td>"+(e.done||"—")+"</td></tr>"});
h+="</table></body></html>";
try{var a=document.createElement("a");a.href=URL.createObjectURL(new Blob(["\uFEFF"+h],{type:"text/html"}));a.download="analitika.html";a.click()}catch(e){alert("Слишком большой")}}
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"}),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)}}
var qq=q.toLowerCase();
if(qq.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> "+br[e.b]+" | срок "+e.due+"<br>"});return r}
if(qq.indexOf("текущ")>=0||qq.indexOf("месяц")>=0){var dtm=all.filter(function(e){if(e.s==="done"||e.s==="late")return false;var p=e.due.split(".");return p.length===3&&parseInt(p[1])===(now.getMonth()+1)});return dtm.length?"<b>К завершению в этом месяце ("+dtm.length+"):</b><br>"+dtm.map(function(e){return"• №"+e.id+" — "+esc(e.t.slice(0,60))+"... ("+e.due+")"}).join("<br>"):"В этом месяце срочных мероприятий нет."}
if(qq.indexOf("риск")>=0||qq.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+="• <b>№"+x.e.id+"</b> — "+x.risk.p+"% ("+x.risk.l+") — "+esc(x.e.t.slice(0,50))+"...<br>"});return r}
if(qq.indexOf("рейтинг")>=0||qq.indexOf("филиал")>=0||qq.indexOf("сравн")>=0){var bsd=bs(),r="<b>Рейтинг филиалов:</b><br>";bsd.forEach(function(b,i){r+=(i+1)+". "+b.name+" — "+b.pct+"% ("+b.done+"/"+b.total+(b.late?", просрочено:"+b.late:"")+")<br>"});return r}
if(qq.indexOf("сводка")>=0||qq.indexOf("ежедн")>=0||qq.indexOf("утр")>=0){return"<b>Сводка на "+new Date().toLocaleDateString()+"</b><br>• План: "+dp+"% ("+done.length+"/"+all.length+")<br>• Просрочено: "+late.length+"<br>• В процессе: "+warn.length+"<br>• Не начато: "+(all.length-done.length-late.length-warn.length)+"<br><br><b>→ Рекомендации:</b><br>"+(late.length?"• Эскалировать просрочки<br>":"")+"• Проверить подтверждающие документы<br>• Запросить отчёты у отстающих";}
if(qq.indexOf("советник")>=0||qq.indexOf("директор")>=0){var bsd=bs(),w3=bsd.slice(-3).map(function(b){return b.name+" ("+b.pct+"%)"}).join(", ");return"<b>👔 Советник директора по ПБ:</b><br><br><b>Выводы:</b><br>• План: "+dp+"%. "+(dp>=70?"Темп хороший.":dp>=40?"Темп средний.":"Критично!")+"<br>• Просрочено: "+late.length+"<br><br><b>Риски:</b> "+w3+"<br><br><b>Решения:</b><br>1. Совещание с отстающими филиалами<br>2. Еженедельный контроль просрочек<br>3. Запросить документы у всех в статусе «В процессе»<br>4. Усилить ИИ-мониторинг<br>5. Доклад Правлению";}
if(qq.indexOf("почему")>=0||qq.indexOf("причин")>=0){return"<b>Причины отставания:</b><br>• Отсутствие текстовых отчётов<br>• Нет подтверждающих файлов<br>• Низкая активность исполнителей<br>• Приближение сроков без обновлений<br><br><b>→ Решение:</b> активизировать загрузку отчётов и документов.";}
if(qq.indexOf("проверк")>=0||qq.indexOf("качеств")>=0||qq.indexOf("подтвержд")>=0){var nf=all.filter(function(e){if(e.s==="done")return false;var d=getMD(e.id,-1),h=false;for(var k in d)if(d.hasOwnProperty(k)&&d[k]&&d[k].files&&d[k].files.length)h=true;return !h});return"<b>Проверка качества:</b><br>• Без файлов: "+nf.length+" мероприятий<br>• Полнота: "+(100-Math.round(nf.length/all.length*100))+"%<br><br><b>→ Рекомендация:</b> запросить недостающие документы.";}
if(qq.indexOf("аудит")>=0)return"<b>🔎 AI-аудитор:</b><br>• "+late.length+" мероприятий с нарушением сроков<br>• Рекомендуется аудит отстающих филиалов<br>• Проверить: обучение, медосмотры, СИЗ, инструктажи";
if(qq.indexOf("360")>=0||qq.indexOf("комплекс")>=0){var bsd=bs();return"<b>ПБ 360°:</b><br>• План: "+dp+"%<br>• Зона риска: "+bsd.filter(function(b){return b.pct<50}).map(function(b){return b.name}).join(", ")+"<br>• Приоритет: устранить просрочки, активизировать отчётность";}
if(qq.indexOf("показател")>=0||qq.indexOf("kpi")>=0){var bsd=bs();return"<b>KPI безопасности:</b><br>• План: "+dp+"%<br>• Лучший: "+bsd[0].name+" ("+bsd[0].pct+"%)<br>• Худший: "+bsd[bsd.length-1].name+" ("+bsd[bsd.length-1].pct+"%)<br>• Просрочено: "+late.length;}
if(qq.indexOf("статус")>=0||qq.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 c=cr(e);return"<b>Пункт №"+e.id+"</b><br>Статус: "+st[e.s]+"<br>Филиал: "+br[e.b]+"<br>Срок: "+e.due+"<br>Риск: "+c.l+" ("+c.p+"%)";}return"Пункт №"+num[0]+" не найден.";}}
if(qq.indexOf("привет")>=0||qq.indexOf("здрав")>=0||qq.indexOf("помощ")>=0)return"👋 Я ИИ-помощник по ПБ АО «Казахтелеком». Спросите: «сводка», «риски», «рейтинг филиалов», «советник», «статус пункта N».";
return"Спросите: <b>сводка</b> · <b>риски</b> · <b>рейтинг филиалов</b> · <b>советник</b> · <b>просроченные</b> · <b>проверка</b> · <b>аудит</b> · <b>360</b> · <b>статус пункта N</b> · <b>причины</b> · <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>