<div class="modal fade" id="GenericAiReportModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" style="z-index:9999;">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="GenericAiReportModalLabel">Report</h4>
<div class="pull-right" style="margin-top:-4px;">
<button type="button" class="btn btn-xs btn-default" onclick="aiReportExportCsv()" title="Export CSV">
<i class="fa fa-file-text-o"></i> CSV
</button>
<button type="button" class="btn btn-xs btn-default" onclick="aiReportPrint()" title="Print / Save as PDF">
<i class="fa fa-print"></i> Print / PDF
</button>
</div>
</div>
<div class="modal-body">
<div class="row clearfix">
<div class="col-md-12 " id="GenericAiReportModalBody">
</div>
<div class="col-md-12 " id="GenericAiReportChartBody">
<canvas id="genericAiChart_bar"></canvas>
<canvas id="genericAiChart_pi"></canvas>
<canvas id="genericAiChart_line"></canvas>
</div>
</div>
{# <div class="row clearfix">#}
{# <div class="col-md-12">#}
{# <div class="btn-toolbar pull-right">#}
{# <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>#}
{# </div>#}
{# </div>#}
{# </div>#}
{#</form>#}
</div>
</div>
{#<div class="modal-footer">#}
{#<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>#}
{#</div>#}
</div>
</div>
</div>
<style type="text/css">
#GenericAiReportModal .modal-dialog { width: 80% !important; max-width: 1100px; }
#GenericAiReportModal .modal-header { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
#GenericAiReportModal .modal-header h4 { flex: 1; margin: 0; }
#GenericAiReportModal .modal-body { max-height: 70vh; overflow-y: auto; }
#GenericAiReportModalBody table { width: 100%; font-size: 12px; }
</style>
<script>
var genericAiChart ={
bar : null,
line : null,
pi : null,
}
// ── Report export helpers ─────────────────────────────────────────────────
function aiReportExportCsv() {
var $table = $('#GenericAiReportModalBody table');
if (!$table.length) { alert('No table data to export.'); return; }
var rows = [];
$table.find('tr').each(function () {
var row = [];
$(this).find('th, td').each(function () {
var cell = $(this).text().trim().replace(/"/g, '""');
row.push('"' + cell + '"');
});
if (row.length) rows.push(row.join(','));
});
var title = $('#GenericAiReportModalLabel').text().trim() || 'report';
var blob = new Blob([rows.join('\n')], {type: 'text/csv;charset=utf-8;'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = title.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.csv';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function aiReportPrint() {
var title = $('#GenericAiReportModalLabel').text().trim() || 'Report';
var bodyHtml = $('#GenericAiReportModalBody').html();
var win = window.open('', '_blank', 'width=960,height=720');
win.document.write('<!DOCTYPE html><html><head><meta charset="utf-8"><title>' + title + '</title><style>'
+ 'body{font-family:Arial,sans-serif;font-size:12px;padding:24px;color:#222;}'
+ 'h2{margin:0 0 14px;font-size:16px;}'
+ 'table{border-collapse:collapse;width:100%;}'
+ 'th,td{border:1px solid #ccc;padding:6px 10px;text-align:left;vertical-align:top;}'
+ 'th{background:#f0f4f7;font-weight:bold;}'
+ 'tr:nth-child(even){background:#fafafa;}'
+ 'pre{white-space:pre-wrap;word-break:break-word;}'
+ '@media print{body{padding:0;}@page{margin:15mm;}}'
+ '</style></head><body>'
+ '<h2>' + title + '</h2>'
+ bodyHtml
+ '<script>window.onload=function(){window.print();}<\/script>'
+ '</body></html>');
win.document.close();
}
// ─────────────────────────────────────────────────────────────────────────
function generateGenericAiChart(data,type) {
type=type || 'bar';
data=data || {
labels : [],
x_title : "",
y_title : "",
datasets : [],
};
var ctx = document.getElementById('genericAiChart_'+type).getContext('2d');
var labels = data.labels||[];
if (genericAiChart[type]) {
genericAiChart[type].destroy();
}
genericAiChart[type] = new Chart(ctx, {
type: type,
data: {
labels: labels,
datasets: data.datasets
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
stacked: true,
grid: {
display: false
},
title: {
display: true,
text: data.x_title,
font: {
weight: 'bold'
}
}
},
y: {
beginAtZero: true,
grid: {
display: true
},
title: {
display: true,
text: data.y_title,
font: {
weight: 'bold'
}
}
},
},
plugins: {
legend: {
position: 'top',
labels: {
usePointStyle: false,
boxWidth: 10
}
},
}
}
});
}
</script>