v15: CSV+HTML отчёты с текстами и списками файлов
This commit is contained in:
parent
007676595c
commit
14ca3d5c60
32
index.html
32
index.html
@ -214,21 +214,45 @@ function renderDashboard(){
|
||||
h+='<div class="panel"><h3>📥 Скачать сводный отчёт</h3><div class="report-bar">';
|
||||
h+='<select id="rptFrom">'+months.map(function(m,i){return'<option value="'+i+'">'+M(i)+'</option>'}).join("")+'</select>';
|
||||
h+='<span>—</span><select id="rptTo">'+months.map(function(m,i){return'<option value="'+i+'"'+(i===11?" selected":"")+'>'+M(i)+'</option>'}).join("")+'</select>';
|
||||
h+='<button class="btn btn-sm" onclick="downloadReport()">Скачать CSV</button></div></div>';
|
||||
h+='<button class="btn btn-sm" onclick="downloadReport()">Скачать CSV</button>';
|
||||
h+='<button class="btn btn-sm btn-outline" onclick="downloadHTML()" style="margin-left:8px">Скачать HTML</button></div></div>';
|
||||
|
||||
document.getElementById("tab-dashboard").innerHTML=h;
|
||||
}
|
||||
|
||||
function downloadReport(){
|
||||
var from=parseInt(document.getElementById("rptFrom").value),to=parseInt(document.getElementById("rptTo").value);
|
||||
var my=getMy(),csv="№;Мероприятие;Раздел;Дивизион;Статус;Прогресс;Срок;Факт;Отчёт (текст)\n";
|
||||
var my=getMy(),csv="№;Мероприятие;Раздел;Дивизион;Статус;Прогресс;Срок;Факт;Отчёты по месяцам (текст);Файлы по месяцам (названия)\n";
|
||||
my.forEach(function(e){
|
||||
var rep="";for(var i=from;i<=to;i++){var m=months[i],d=getMD(e.id);if(d[m]&&d[m].report)rep+=M(i)+": "+d[m].report.replace(/"/g,'""')+"; "}
|
||||
csv+=e.id+';"'+e.t.replace(/"/g,'""')+'";'+sections[e.sec]+';'+branches[e.b]+';'+statusMap[e.s]+';'+e.p+'%;'+e.due+';'+(e.done||"—")+';"'+rep+'"\n';
|
||||
var rep="",fls="",d=getMD(e.id);
|
||||
for(var i=from;i<=to;i++){var m=months[i];if(d[m]){if(d[m].report)rep+=M(i)+": "+d[m].report.replace(/"/g,'""')+"; ";if(d[m].files&&d[m].files.length)fls+=M(i)+": "+d[m].files.map(function(f){return f.name}).join(", ")+"; "}}
|
||||
csv+=e.id+';"'+e.t.replace(/"/g,'""')+'";'+sections[e.sec]+';'+branches[e.b]+';'+statusMap[e.s]+';'+e.p+'%;'+e.due+';'+(e.done||"—")+';"'+rep+'";"'+fls+'"\n';
|
||||
});
|
||||
var blob=new Blob(["\uFEFF"+csv],{type:"text/csv;charset=utf-8"}),a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download="otchet_pb_"+M(from)+"-"+M(to)+".csv";a.click()
|
||||
}
|
||||
|
||||
function downloadHTML(){
|
||||
var from=parseInt(document.getElementById("rptFrom").value),to=parseInt(document.getElementById("rptTo").value);
|
||||
var my=getMy(),h='<!DOCTYPE html><html lang="ru"><head><meta charset="utf-8"><title>Сводный отчёт ПБ</title><style>body{font:14px/1.5 Arial,sans-serif;max-width:1100px;margin:0 auto;padding:24px}h1{font-size:22px;margin-bottom:4px}h1 span{color:#00E5FF}h2{font-size:18px;margin:24px 0 8px}.ev{border:1px solid #ddd;border-radius:8px;padding:16px;margin-bottom:16px;page-break-inside:avoid}.ev h3{font-size:15px;margin:0 0 8px}.meta{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:#666;margin-bottom:8px}.meta strong{color:#111}.badge{display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:700}.g{background:#D1FAE5;color:#065F46}.a{background:#FEF3C7;color:#92400E}.r{background:#FEE2E2;color:#991B1B}.w{background:#eee;color:#666}.month{background:#f5f5f5;padding:8px 12px;border-radius:4px;margin:6px 0}.month strong{font-size:12px}.files{font-size:12px;color:#555;margin-top:2px}.files li{list-style:"📄 ";margin-left:20px}@media print{.ev{border-color:#999}}</style></head><body>';
|
||||
h+='<h1><span>ИИ-Агент</span> ПБ — Сводный отчёт</h1><p style="color:#666">Период: '+M(from)+' — '+M(to)+' · Дивизион: '+branches[curUser.branch]+' · Сформирован: '+new Date().toLocaleDateString()+'</p>';
|
||||
my.forEach(function(e){
|
||||
var scls={done:"g",warn:"a",late:"r",wait:"w"}[e.s];
|
||||
h+='<div class="ev"><h3>'+e.id+'. '+esc(e.t)+'</h3>';
|
||||
h+='<div class="meta"><span>Раздел: <strong>'+sections[e.sec]+'</strong></span><span>Дивизион: <strong>'+branches[e.b]+'</strong></span><span>Срок: <strong>'+e.due+'</strong></span><span>Факт: <strong>'+(e.done||"—")+'</strong></span><span>Прогресс: <strong>'+e.p+'%</strong></span><span class="badge '+scls+'">'+statusMap[e.s]+'</span></div>';
|
||||
h+='<div class="meta"><span>Ответственный: <strong>'+esc(e.r)+'</strong></span></div>';
|
||||
var d=getMD(e.id),has=false;
|
||||
for(var i=from;i<=to;i++){var m=months[i];if(d[m]&&(d[m].report||(d[m].files&&d[m].files.length))){
|
||||
has=true;h+='<div class="month"><strong>'+M(i)+'</strong>';
|
||||
if(d[m].report)h+='<p style="font-size:13px;margin:4px 0">'+esc(d[m].report)+'</p>';
|
||||
if(d[m].files&&d[m].files.length)h+='<div class="files"><ul>'+d[m].files.map(function(f){return'<li>'+esc(f.name)+(f.desc?' — '+esc(f.desc):'')+' ('+(f.size/1024).toFixed(0)+' КБ)</li>'}).join("")+'</ul></div>';
|
||||
h+='</div>'}}
|
||||
if(!has)h+='<p style="font-size:12px;color:#999">Нет отчётов за выбранный период</p>';
|
||||
h+='<div style="font-size:11px;color:#666;margin-top:8px">🤖 ИИ: '+esc(e.ai)+'</div></div>';
|
||||
});
|
||||
h+='</body></html>';
|
||||
var blob=new Blob(["\uFEFF"+h],{type:"text/html;charset=utf-8"}),a=document.createElement("a");a.href=URL.createObjectURL(blob);a.download="otchet_pb_"+M(from)+"-"+M(to)+".html";a.click()
|
||||
}
|
||||
|
||||
// ===== MY EVENTS =====
|
||||
function renderMyEvents(){
|
||||
var my=getMy(),h='<div class="panel" style="border-radius:0 0 12px 12px">';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user