График = минимум, перевыполнение >100%, дашборд с перевыполнением
This commit is contained in:
parent
231995df76
commit
64ce8be89d
4
app.html
4
app.html
@ -150,9 +150,9 @@ function printConfirm(){if(!lastSubmitted)return;var e=lastSubmitted;var w=windo
|
||||
|
||||
function checkSA(){if(!U||isA()){document.getElementById("sa").classList.remove("sh","dg");return}var q=getUserQuota(U);if(!q.p)return;var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var need=Math.max(0,q.c-done);var sa=document.getElementById("sa"),at=document.getElementById("sat");sa.classList.remove("sh","dg");if(need>0){at.textContent="⚠️ Отставание ("+p.l+"): "+done+" из "+q.c+". Осталось: "+need;sa.classList.add("sh");if(need>=q.c)sa.classList.add("dg")}}
|
||||
function sendScheduleReminder(){if(!U)return;var q=getUserQuota(U);var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var need=Math.max(0,q.c-done);var to=U.email||"";if(!to||to.indexOf("@")<0){alert("Нет email");return}location.href="mailto:"+encodeURIComponent(to)+"?subject="+encodeURIComponent("График ПАБ — "+p.l)+"&body="+encodeURIComponent("График: "+q.l+"\nПериод: "+p.l+"\nВыполнено: "+done+" из "+q.c+(need>0?"\nОтставание: "+need:"\nГрафик выполнен!"))}
|
||||
function rMS(){var c=document.getElementById("msc");if(!c)return;document.getElementById("sa").classList.remove("sh","dg");var q=getUserQuota(U);if(q.c===0){c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\"><h3>📅 Без графика</h3><p style=\"color:var(--g5);font-size:13px\">Для должности «"+U.role+"» график не установлен.</p></div>";return}var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var pct=Math.min(100,Math.round(done/q.c*100));var cl=pct>=100?"#2D6A4F":pct>=50?"#E76F51":"#E63946";var need=Math.max(0,q.c-done);c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh);margin-bottom:16px\"><h3>📅 "+p.l+"</h3><div style=\"font-size:12px;color:var(--g5);margin-bottom:10px\">Норматив: <b>"+q.l+"</b> | "+U.role+"</div><div style=\"height:16px;border-radius:8px;background:#E2E6EB;overflow:hidden;margin-bottom:6px\"><div style=\"height:100%;border-radius:8px;width:"+pct+"%;background:"+cl+";transition:width .5s\"></div></div><div style=\"font-size:12px;font-weight:600\">Выполнено: <b>"+done+"</b> из <b>"+q.c+"</b> ("+pct+"%) "+(need>0?"— осталось: <span style=\"color:#E63946\">"+need+"</span>":"— ✅ выполнено!")+"</div>"+(need>0?"<div style=\"margin-top:10px\"><button class=\"btn bp bs\" onclick=\"sendScheduleReminder()\">✉️ Напомнить</button></div>":"")+"</div><div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\">👤 <b>"+U.name+"</b> — "+U.role+"<br><span style=\"font-size:12px;color:var(--g5)\">"+(U.branch||"—")+" | "+(U.dept||"—")+" | "+(U.region||"—")+" | "+(U.city||"—")+" | "+U.email+"</span></div>"+(done>0?"<div style=\"margin-top:16px;background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\"><h4 style=\"margin-bottom:8px\">📋 Проведённые:</h4>"+getA().filter(function(a){return a.createdBy===U.login}).slice(0,10).map(function(a){return"<div style=\"background:var(--g1);padding:8px 12px;border-radius:var(--r);margin-bottom:6px;font-size:13px\">"+a.date+" — "+a.location+" — <span class=\"badge "+(a.overallSafe?"badge-s":"badge-d")+"\">"+(a.overallSafe?"Безопасно":"Нарушений: "+a.totalViolations)+"</span></div>"}).join("")+"</div>":"")}
|
||||
function rMS(){var c=document.getElementById("msc");if(!c)return;document.getElementById("sa").classList.remove("sh","dg");var q=getUserQuota(U);if(q.c===0){c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\"><h3>📅 Без графика</h3><p style=\"color:var(--g5);font-size:13px\">Для должности «"+U.role+"» график не установлен. Вы можете проводить ПАБ в любом количестве.</p></div>";return}var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===U.login&&new Date(a.date)>=p.s}).length;var pct=Math.round(done/q.c*100);var over=pct>100;var cl=over?"#00B4D8":pct>=100?"#2D6A4F":pct>=50?"#E76F51":"#E63946";var barW=Math.min(pct,200);var need=Math.max(0,q.c-done);var extra=done-q.c;c.innerHTML="<div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh);margin-bottom:16px\"><h3>📅 "+p.l+"</h3><div style=\"font-size:12px;color:var(--g5);margin-bottom:10px\">Минимум: <b>"+q.l+"</b> | "+U.role+"</div><div style=\"height:16px;border-radius:8px;background:#E2E6EB;overflow:hidden;margin-bottom:6px\"><div style=\"height:100%;border-radius:8px;width:"+barW+"%;background:"+cl+";transition:width .5s;max-width:200%\"></div></div><div style=\"font-size:12px;font-weight:600\">Проведено: <b>"+done+"</b> (мин: "+q.c+")"+(over?" — <span style=\"color:#00B4D8\">✅ перевыполнено на +"+extra+"!</span>":done>=q.c?" — ✅ план выполнен!":" — осталось: <span style=\"color:#E63946\">"+need+"</span>")+"</div>"+(need>0?"<div style=\"margin-top:10px\"><button class=\"btn bp bs\" onclick=\"sendScheduleReminder()\">✉️ Напомнить</button></div>":"")+"</div><div style=\"background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\">👤 <b>"+U.name+"</b> — "+U.role+"<br><span style=\"font-size:12px;color:var(--g5)\">"+(U.branch||"—")+" | "+(U.dept||"—")+" | "+(U.region||"—")+" | "+(U.city||"—")+" | "+U.email+"</span></div>"+(done>0?"<div style=\"margin-top:16px;background:var(--white);border-radius:var(--rl);padding:20px;box-shadow:var(--sh)\"><h4 style=\"margin-bottom:8px\">📋 Проведённые:</h4>"+getA().filter(function(a){return a.createdBy===U.login}).slice(0,10).map(function(a){return"<div style=\"background:var(--g1);padding:8px 12px;border-radius:var(--r);margin-bottom:6px;font-size:13px\">"+a.date+" — "+a.location+" — <span class=\"badge "+(a.overallSafe?"badge-s":"badge-d")+"\">"+(a.overallSafe?"Безопасно":"Нарушений: "+a.totalViolations)+"</span></div>"}).join("")+"</div>":"")}
|
||||
|
||||
function rDB(){var c=document.getElementById("dbc");if(!c)return;var audits=getA();var all=allU();var total=audits.length,allSafe=audits.filter(function(a){return a.overallSafe}).length,wd=audits.filter(function(a){return !a.overallSafe}).length,tv=audits.reduce(function(s,a){return s+(a.totalViolations||0)},0);var ul=[];for(var k in all)if(k!=="admin")ul.push({login:k,role:all[k].role});var ot=0,bh=0;ul.forEach(function(u){var q=getUserQuota(u);if(!q.p)return;var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;if(done>=q.c)ot++;else bh++});var sp=total>0?(allSafe/total*100):50,dp=total>0?(wd/total*100):50;c.innerHTML=(isA()?"<div class=\"fb\"><button class=\"btn bp bs\" onclick=\"downloadFullCSV()\">📥 CSV данные</button><button class=\"btn bo bs\" onclick=\"downloadWorkerReport()\">👥 CSV работники</button><button class=\"btn bo bs\" onclick=\"downloadSummaryHTML()\">📊 HTML отчёт</button><span style=\"color:var(--g2);margin:0 4px\">|</span><button class=\"btn bd bs\" onclick=\"clearAllAudits()\">🗑️ Очистить всё</button><button class=\"btn bo bs\" onclick=\"clearAuditsByDate()\">📅 Очистить период</button><button class=\"btn bo bs\" onclick=\"showAllUsers()\">👥 Пользователи</button></div>":"")+"<div class=\"sg\"><div class=\"sc\"><div class=\"sl\">Всего аудитов</div><div class=\"sv\">"+total+"</div></div><div class=\"sc gr\"><div class=\"sl\">Безопасно</div><div class=\"sv\">"+allSafe+"</div></div><div class=\"sc rd\"><div class=\"sl\">С нарушениями</div><div class=\"sv\">"+wd+"</div></div><div class=\"sc bl\"><div class=\"sl\">Нарушений</div><div class=\"sv\">"+tv+"</div></div><div class=\"sc or\"><div class=\"sl\">Выполняют график</div><div class=\"sv\">"+ot+"</div></div><div class=\"sc rd\"><div class=\"sl\">Отстают</div><div class=\"sv\">"+bh+"</div></div></div><div class=\"cc\" style=\"margin-bottom:16px\"><h3>🟢🔴 Соотношение</h3><div class=\"rb\"><div class=\"rs\" style=\"width:"+sp+"%\"></div><div class=\"ru\" style=\"width:"+dp+"%\"></div></div><div class=\"rl2\"><span>Безопасные: "+allSafe+"</span><span>С нарушениями: "+wd+"</span></div></div><div class=\"cg\"><div class=\"cc\"><h3>📂 По категориям</h3><canvas id=\"ch1\"></canvas></div><div class=\"cc\"><h3>📅 По датам</h3><canvas id=\"ch2\"></canvas></div><div class=\"cc\"><h3>🔝 Топ-10</h3><canvas id=\"ch3\"></canvas></div></div>";setTimeout(function(){for(var ck in charts)try{charts[ck].destroy()}catch(e){}charts={};var ctx1=document.getElementById("ch1");if(ctx1)charts.cat=new Chart(ctx1,{type:"bar",data:{labels:CATS.map(function(c){return c.title.split(". ")[1]}),datasets:[{label:"Нарушений",data:CATS.map(function(cat){return audits.reduce(function(s,a){var c=a.categories&&a.categories[cat.id];return s+(c?c.items.length:0)},0)}),backgroundColor:"#E63946",borderRadius:6}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var dates={};audits.forEach(function(a){if(!dates[a.date])dates[a.date]=0;dates[a.date]+=(a.totalViolations||0)});var sd=Object.keys(dates).sort();var ctx2=document.getElementById("ch2");if(ctx2)charts.tl=new Chart(ctx2,{type:"line",data:{labels:sd,datasets:[{label:"Нарушений",data:sd.map(function(d){return dates[d]}),borderColor:"#E63946",backgroundColor:"rgba(230,57,70,0.08)",fill:true,tension:0.3,pointRadius:5}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var ic={};audits.forEach(function(a){if(a.categories){Object.values(a.categories).forEach(function(cat){if(cat.items)cat.items.forEach(function(it){ic[it.item]=(ic[it.item]||0)+1})})}});var ti=Object.entries(ic).sort(function(a,b){return b[1]-a[1]}).slice(0,10);var ctx3=document.getElementById("ch3");if(ctx3)charts.top=new Chart(ctx3,{type:"bar",data:{labels:ti.map(function(i){return i[0].length>30?i[0].slice(0,30)+"...":i[0]}),datasets:[{label:"Раз",data:ti.map(function(i){return i[1]}),backgroundColor:["#E63946","#E76F51","#F4A261","#E9C46A","#2A9D8F","#264653","#00B4D8","#0077B6","#023E8A","#6C757D"],borderRadius:4}]},options:{indexAxis:"y",responsive:true,plugins:{legend:{display:false}},scales:{x:{beginAtZero:true,ticks:{stepSize:1}}}}})},300)}
|
||||
function rDB(){var c=document.getElementById("dbc");if(!c)return;var audits=getA();var all=allU();var total=audits.length,allSafe=audits.filter(function(a){return a.overallSafe}).length,wd=audits.filter(function(a){return !a.overallSafe}).length,tv=audits.reduce(function(s,a){return s+(a.totalViolations||0)},0);var ul=[];for(var k in all)if(k!=="admin")ul.push({login:k,role:all[k].role});var ot=0,bh=0,ov=0;ul.forEach(function(u){var q=getUserQuota(u);if(!q.p)return;var p=gp(q.p);var done=getA().filter(function(a){return a.createdBy===u.login&&new Date(a.date)>=p.s}).length;if(done>q.c)ov++;else if(done>=q.c)ot++;else bh++});var sp=total>0?(allSafe/total*100):50,dp=total>0?(wd/total*100):50;c.innerHTML=(isA()?"<div class=\"fb\"><button class=\"btn bp bs\" onclick=\"downloadFullCSV()\">📥 CSV данные</button><button class=\"btn bo bs\" onclick=\"downloadWorkerReport()\">👥 CSV работники</button><button class=\"btn bo bs\" onclick=\"downloadSummaryHTML()\">📊 HTML отчёт</button><span style=\"color:var(--g2);margin:0 4px\">|</span><button class=\"btn bd bs\" onclick=\"clearAllAudits()\">🗑️ Очистить всё</button><button class=\"btn bo bs\" onclick=\"clearAuditsByDate()\">📅 Очистить период</button><button class=\"btn bo bs\" onclick=\"showAllUsers()\">👥 Пользователи</button></div>":"")+"<div class=\"sg\"><div class=\"sc\"><div class=\"sl\">Всего аудитов</div><div class=\"sv\">"+total+"</div></div><div class=\"sc gr\"><div class=\"sl\">Безопасно</div><div class=\"sv\">"+allSafe+"</div></div><div class=\"sc rd\"><div class=\"sl\">С нарушениями</div><div class=\"sv\">"+wd+"</div></div><div class=\"sc bl\"><div class=\"sl\">Нарушений</div><div class=\"sv\">"+tv+"</div></div><div class=\"sc bl\"><div class=\"sl\">Перевыполняют</div><div class=\"sv\">"+ov+"</div></div><div class=\"sc gr\"><div class=\"sl\">Выполняют</div><div class=\"sv\">"+ot+"</div></div><div class=\"sc rd\"><div class=\"sl\">Отстают</div><div class=\"sv\">"+bh+"</div></div></div><div class=\"cc\" style=\"margin-bottom:16px\"><h3>🟢🔴 Соотношение</h3><div class=\"rb\"><div class=\"rs\" style=\"width:"+sp+"%\"></div><div class=\"ru\" style=\"width:"+dp+"%\"></div></div><div class=\"rl2\"><span>Безопасные: "+allSafe+"</span><span>С нарушениями: "+wd+"</span></div></div><div class=\"cg\"><div class=\"cc\"><h3>📂 По категориям</h3><canvas id=\"ch1\"></canvas></div><div class=\"cc\"><h3>📅 По датам</h3><canvas id=\"ch2\"></canvas></div><div class=\"cc\"><h3>🔝 Топ-10</h3><canvas id=\"ch3\"></canvas></div></div>";setTimeout(function(){for(var ck in charts)try{charts[ck].destroy()}catch(e){}charts={};var ctx1=document.getElementById("ch1");if(ctx1)charts.cat=new Chart(ctx1,{type:"bar",data:{labels:CATS.map(function(c){return c.title.split(". ")[1]}),datasets:[{label:"Нарушений",data:CATS.map(function(cat){return audits.reduce(function(s,a){var c=a.categories&&a.categories[cat.id];return s+(c?c.items.length:0)},0)}),backgroundColor:"#E63946",borderRadius:6}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var dates={};audits.forEach(function(a){if(!dates[a.date])dates[a.date]=0;dates[a.date]+=(a.totalViolations||0)});var sd=Object.keys(dates).sort();var ctx2=document.getElementById("ch2");if(ctx2)charts.tl=new Chart(ctx2,{type:"line",data:{labels:sd,datasets:[{label:"Нарушений",data:sd.map(function(d){return dates[d]}),borderColor:"#E63946",backgroundColor:"rgba(230,57,70,0.08)",fill:true,tension:0.3,pointRadius:5}]},options:{responsive:true,plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{stepSize:1}}}}});var ic={};audits.forEach(function(a){if(a.categories){Object.values(a.categories).forEach(function(cat){if(cat.items)cat.items.forEach(function(it){ic[it.item]=(ic[it.item]||0)+1})})}});var ti=Object.entries(ic).sort(function(a,b){return b[1]-a[1]}).slice(0,10);var ctx3=document.getElementById("ch3");if(ctx3)charts.top=new Chart(ctx3,{type:"bar",data:{labels:ti.map(function(i){return i[0].length>30?i[0].slice(0,30)+"...":i[0]}),datasets:[{label:"Раз",data:ti.map(function(i){return i[1]}),backgroundColor:["#E63946","#E76F51","#F4A261","#E9C46A","#2A9D8F","#264653","#00B4D8","#0077B6","#023E8A","#6C757D"],borderRadius:4}]},options:{indexAxis:"y",responsive:true,plugins:{legend:{display:false}},scales:{x:{beginAtZero:true,ticks:{stepSize:1}}}}})},300)}
|
||||
|
||||
function rVL(){var c=document.getElementById("vlc");if(!c)return;var audits=getA();var today=new Date().toISOString().split("T")[0];var allV=[];audits.forEach(function(a){if(!a.violations)return;a.violations.forEach(function(v){var dd=v.date||"",done=v.done&&v.done.trim();var st="pending";if(done)st="done";else if(dd&&dd<today)st="overdue";allV.push({nc:v.nc,executor:v.executor,type:v.type,measure:v.measure,responsible:v.responsible,date:dd,done:v.done||"",status:st,auditDate:a.date,auditNumber:a.number||"—"})})});c.innerHTML="<div class=\"sg\"><div class=\"sc\"><div class=\"sl\">Всего</div><div class=\"sv\">"+allV.length+"</div></div><div class=\"sc gr\"><div class=\"sl\">Устранено</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="done"}).length+"</div></div><div class=\"sc rd\"><div class=\"sl\">Просрочено</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="overdue"}).length+"</div></div><div class=\"sc or\"><div class=\"sl\">В работе</div><div class=\"sv\">"+allV.filter(function(v){return v.status==="pending"}).length+"</div></div></div><div class=\"tw\"><table class=\"dt\"><thead><tr><th>№</th><th>Несоответствие</th><th>Аудит</th><th>Исполнитель</th><th>Вид</th><th>Меры</th><th>Ответственный</th><th>Срок</th><th>Завершение</th><th>Статус</th></tr></thead><tbody>"+allV.map(function(v,i){var sc=v.status==="done"?"badge-s":v.status==="overdue"?"badge-d":"badge-w";var sl=v.status==="done"?"Устранено":v.status==="overdue"?"Просрочено":"В работе";return"<tr><td>"+(i+1)+"</td><td style=\"max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\" title=\""+esc(v.nc)+"\">"+v.nc+"</td><td>"+v.auditDate+"</td><td>"+v.executor+"</td><td>"+v.type+"</td><td style=\"max-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap\">"+(v.measure||"—")+"</td><td>"+v.responsible+"</td><td>"+(v.date||"—")+"</td><td>"+(v.done||"—")+"</td><td><span class=\"badge "+sc+"\">"+sl+"</span></td></tr>"}).join("")+"</tbody></table></div>"}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user