update entra id
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderAnalysisDistributionChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a torta
|
||||
const analysisDistribution = chartData || [];
|
||||
const labels = analysisDistribution.map((item) => item.analysisName);
|
||||
const series = analysisDistribution.map((item) => {
|
||||
const value = parseInt(item.totalTests);
|
||||
return isNaN(value) || value < 0 ? 0 : value;
|
||||
});
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = series.some((value) => value > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a torta
|
||||
const options = {
|
||||
series: series,
|
||||
chart: {
|
||||
type: "pie",
|
||||
height: 350,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: labels,
|
||||
colors: [
|
||||
"#FF4560",
|
||||
"#008FFB",
|
||||
"#00E396",
|
||||
"#FEB019",
|
||||
"#FF66FF",
|
||||
"#775DD0",
|
||||
"#546E7A",
|
||||
"#26A69A",
|
||||
"#D81B60",
|
||||
"#F06292",
|
||||
"#4FC3F7",
|
||||
"#AED581",
|
||||
"#FF8A65",
|
||||
"#A1887F",
|
||||
"#E0E0E0",
|
||||
"#90A4AE",
|
||||
"#FFCA28",
|
||||
"#78909C",
|
||||
"#D4E157",
|
||||
"#F4FF81",
|
||||
],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 200,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " tests";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Forza un aggiornamento del grafico dopo un breve ritardo
|
||||
setTimeout(() => {
|
||||
chart.updateOptions({});
|
||||
}, 100);
|
||||
|
||||
// Genera la tabella usando la funzione esistente
|
||||
const tableHTML = generatePieTable(labels, series);
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
export function renderAnalytesFailChart(
|
||||
analytesData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(analytesData) || analytesData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = analytesData.map((item) => item.AnalyteName || "Unknown");
|
||||
const data = analytesData.map((item) => parseInt(item.FailCount, 10) || 0);
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = analytesData.some((item) => item.FailCount > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failures to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Failures",
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 400,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: labels,
|
||||
title: {
|
||||
text: "Number of Failures",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Analyte",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " failures";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Analyte</th>
|
||||
<th>Failures</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${analytesData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.AnalyteName || "Unknown"}</td>
|
||||
<td>${parseInt(item.FailCount, 10) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderBarChart(data, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dati per il grafico a barre (usa gli stessi dati del grafico a torta)
|
||||
const intFailReports = parseInt(data.failReportsPie) || 0;
|
||||
const intPassReports = parseInt(data.passReportsPie) || 0;
|
||||
const intOtherReports = parseInt(data.otherReportsPie) || 0;
|
||||
|
||||
const barLabels = ["Fail", "Pass", "Others"];
|
||||
const barSeries = [intFailReports, intPassReports, intOtherReports];
|
||||
|
||||
// Configurazione del grafico a barre
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Reports",
|
||||
data: barSeries,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
height: 350,
|
||||
type: "bar",
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: false,
|
||||
columnWidth: "55%",
|
||||
endingShape: "rounded",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
stroke: {
|
||||
show: true,
|
||||
width: 2,
|
||||
colors: ["transparent"],
|
||||
},
|
||||
xaxis: {
|
||||
categories: barLabels,
|
||||
},
|
||||
colors: ["#FF4D4D", "#28A745", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera la tabella e aggiungi un log
|
||||
const tableHTML = generatePieTable(barLabels, barSeries);
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
export function renderHorizontalBarChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a barre orizzontali
|
||||
const horizontalBarData = chartData || [];
|
||||
const categories = horizontalBarData.map((item) => item.groupingValue);
|
||||
const passData = horizontalBarData.map((item) => item.passCount);
|
||||
const failData = horizontalBarData.map((item) => item.failCount);
|
||||
const otherData = horizontalBarData.map((item) => item.otherCount);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Pass",
|
||||
data: passData,
|
||||
},
|
||||
{
|
||||
name: "Fail",
|
||||
data: failData,
|
||||
},
|
||||
{
|
||||
name: "Others",
|
||||
data: otherData,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
stacked: true,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: categories,
|
||||
title: {
|
||||
text: "Number of Reports",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Grouping Value",
|
||||
},
|
||||
},
|
||||
colors: ["#28A745", "#FF4D4D", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: "top",
|
||||
horizontalAlign: "left",
|
||||
offsetX: 40,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Grouping Value</th>
|
||||
<th>Pass</th>
|
||||
<th>Fail</th>
|
||||
<th>Others</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${horizontalBarData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.groupingValue}</td>
|
||||
<td>${item.passCount}</td>
|
||||
<td>${item.failCount}</td>
|
||||
<td>${item.otherCount}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
export function renderPhaseBarChart(chartData, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a barre
|
||||
const phaseRatingsData = chartData || [];
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(phaseRatingsData) || phaseRatingsData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available for Phase Rating Distribution.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const phases = phaseRatingsData.map((item) => item.phase || "Unknown");
|
||||
const passData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.passCount) || 0,
|
||||
);
|
||||
const failData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.failCount) || 0,
|
||||
);
|
||||
const otherData = phaseRatingsData.map(
|
||||
(item) => parseInt(item.otherCount) || 0,
|
||||
);
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData =
|
||||
passData.some((value) => value > 0) ||
|
||||
failData.some((value) => value > 0) ||
|
||||
otherData.some((value) => value > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No ratings to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No ratings to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Pass",
|
||||
data: passData,
|
||||
},
|
||||
{
|
||||
name: "Fail",
|
||||
data: failData,
|
||||
},
|
||||
{
|
||||
name: "Others",
|
||||
data: otherData,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
stacked: true,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: phases,
|
||||
title: {
|
||||
text: "Number of Reports",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Phase",
|
||||
},
|
||||
},
|
||||
colors: ["#28A745", "#FF4D4D", "#FFA500"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " reports";
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
position: "top",
|
||||
horizontalAlign: "left",
|
||||
offsetX: 40,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Phase</th>
|
||||
<th>Pass</th>
|
||||
<th>Fail</th>
|
||||
<th>Others</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${phaseRatingsData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.phase || "Unknown"}</td>
|
||||
<td>${parseInt(item.passCount) || 0}</td>
|
||||
<td>${parseInt(item.failCount) || 0}</td>
|
||||
<td>${parseInt(item.otherCount) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
tableContainer.style.display = "block"; // Forza la visibilità
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderPhasePieChart(chartData, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico a torta
|
||||
const phaseData = chartData || [];
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(phaseData) || phaseData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available for Products Distribution by Phase.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No data available.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = phaseData.map((item) => item.phase || "Unknown");
|
||||
const series = phaseData.map((item) => {
|
||||
const count = parseInt(item.totalProducts, 10);
|
||||
return isNaN(count) ? 0 : count;
|
||||
});
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = series.some((value) => value > 0);
|
||||
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No valid data to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a torta
|
||||
const options = {
|
||||
series: series,
|
||||
chart: {
|
||||
type: "pie",
|
||||
height: 350,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: labels,
|
||||
colors: [
|
||||
"#FF4560",
|
||||
"#008FFB",
|
||||
"#00E396",
|
||||
"#FEB019",
|
||||
"#FF66FF",
|
||||
"#775DD0",
|
||||
],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 200,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " products";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Forza un aggiornamento del grafico dopo un breve ritardo
|
||||
setTimeout(() => {
|
||||
chart.updateOptions({});
|
||||
}, 100);
|
||||
|
||||
// Genera la tabella usando la funzione esistente
|
||||
const tableHTML = generatePieTable(labels, series);
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
tableContainer.style.display = "block"; // Forza la visibilità
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { generatePieTable } from "../utils/tableGenerator.js";
|
||||
|
||||
export function renderPieChart(data, containerId, tableContainerId) {
|
||||
// Pulizia del contenitore
|
||||
document.querySelector(`#${containerId}`).innerHTML = "";
|
||||
|
||||
// Dati per il grafico a torta
|
||||
const intFailReports = parseInt(data.failReportsPie);
|
||||
const intPassReports = parseInt(data.passReportsPie);
|
||||
const intOtherReports = parseInt(data.otherReportsPie);
|
||||
|
||||
const pieLabels = ["Fail", "Pass", "Others"];
|
||||
const pieSeries = [intFailReports, intPassReports, intOtherReports];
|
||||
|
||||
// Configurazione del grafico
|
||||
const options = {
|
||||
series: pieSeries,
|
||||
chart: {
|
||||
width: "100%",
|
||||
type: "pie",
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: pieLabels,
|
||||
colors: ["#FF4D4D", "#28A745", "#FFA500"],
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 480,
|
||||
options: {
|
||||
chart: {
|
||||
width: 250,
|
||||
},
|
||||
legend: {
|
||||
position: "bottom",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
legend: {
|
||||
position: "bottom",
|
||||
offsetY: 0,
|
||||
height: 50,
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(
|
||||
document.querySelector(`#${containerId}`),
|
||||
options,
|
||||
);
|
||||
chart.render();
|
||||
|
||||
// Genera la tabella
|
||||
document.querySelector(`#${tableContainerId}`).innerHTML = generatePieTable(
|
||||
pieLabels,
|
||||
pieSeries,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
export function renderProductBySupplierChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico
|
||||
const productBySupplier = chartData || [];
|
||||
const suppliers = productBySupplier.map((item) => item.supplier);
|
||||
const totalProducts = productBySupplier.map((item) => item.totalProducts);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Total Products",
|
||||
data: totalProducts,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
},
|
||||
xaxis: {
|
||||
categories: suppliers,
|
||||
title: {
|
||||
text: "Number of Products",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Supplier",
|
||||
},
|
||||
},
|
||||
colors: ["#007BFF"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " products";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Supplier</th>
|
||||
<th>Total Products</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${productBySupplier
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.supplier}</td>
|
||||
<td>${item.totalProducts}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
export function renderWorstSuppliersChart(
|
||||
chartData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Estrai i dati per il grafico
|
||||
const worstSuppliers = chartData || [];
|
||||
const suppliers = worstSuppliers.map((item) => item.supplier);
|
||||
const failPercentages = worstSuppliers.map((item) => item.failPercentage);
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Fail Percentage",
|
||||
data: failPercentages,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 600,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: true,
|
||||
formatter: function (val) {
|
||||
return val.toFixed(2) + "%";
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
categories: suppliers,
|
||||
title: {
|
||||
text: "Fail Percentage (%)",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Supplier",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val.toFixed(2) + "%";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Supplier</th>
|
||||
<th>Fail Percentage</th>
|
||||
<th>Total Reports</th>
|
||||
<th>Failed Reports</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${worstSuppliers
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.supplier}</td>
|
||||
<td>${item.failPercentage.toFixed(2)}%</td>
|
||||
<td>${item.totalReports}</td>
|
||||
<td>${item.failedReports}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
export function renderWorstTenAnalysisChart(
|
||||
analysisData,
|
||||
containerId,
|
||||
tableContainerId,
|
||||
) {
|
||||
// Pulizia del contenitore del grafico
|
||||
const chartContainer = document.querySelector(`#${containerId}`);
|
||||
if (chartContainer) {
|
||||
chartContainer.innerHTML = "";
|
||||
} else {
|
||||
console.error(`Contenitore del grafico non trovato: #${containerId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validazione dei dati
|
||||
if (!Array.isArray(analysisData) || analysisData.length === 0) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = analysisData.map((item) => item.name || "Unknown");
|
||||
const data = analysisData.map((item) => parseInt(item.failCount, 10) || 0);
|
||||
|
||||
console.log("Dati per il grafico Worst Analysis:", { labels, data });
|
||||
|
||||
// Verifica se ci sono dati validi da visualizzare
|
||||
const hasValidData = analysisData.some((item) => item.failCount > 0);
|
||||
if (!hasValidData) {
|
||||
chartContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML =
|
||||
'<p class="text-center text-muted">No failed tests to display.</p>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Configurazione del grafico a barre orizzontali
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: "Failed Tests",
|
||||
data: data,
|
||||
},
|
||||
],
|
||||
chart: {
|
||||
type: "bar",
|
||||
height: 400,
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
selection: false,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: true,
|
||||
barHeight: "80%",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
categories: labels,
|
||||
title: {
|
||||
text: "Number of Failed Tests",
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
title: {
|
||||
text: "Analysis",
|
||||
},
|
||||
},
|
||||
colors: ["#FF4D4D"],
|
||||
fill: {
|
||||
opacity: 1,
|
||||
},
|
||||
tooltip: {
|
||||
y: {
|
||||
formatter: function (val) {
|
||||
return val + " failed tests";
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Render del grafico
|
||||
const chart = new ApexCharts(chartContainer, options);
|
||||
chart.render();
|
||||
|
||||
// Genera una tabella per i dati
|
||||
const tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Analysis</th>
|
||||
<th>Failed Tests</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${analysisData
|
||||
.map(
|
||||
(item) => `
|
||||
<tr>
|
||||
<td>${item.name || "Unknown"}</td>
|
||||
<td>${parseInt(item.failCount, 10) || 0}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// Riprova a trovare il contenitore della tabella con un ritardo
|
||||
const renderTable = () => {
|
||||
const tableContainer = document.querySelector(`#${tableContainerId}`);
|
||||
if (tableContainer) {
|
||||
tableContainer.innerHTML = tableHTML;
|
||||
} else {
|
||||
console.error(
|
||||
`Contenitore della tabella non trovato: #${tableContainerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Prova immediatamente e riprova dopo un breve ritardo
|
||||
renderTable();
|
||||
setTimeout(renderTable, 100);
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
import { fetchData } from "./utils/ajaxUtils.js";
|
||||
import { renderPieChart } from "./charts/pieChart.js";
|
||||
import { renderBarChart } from "./charts/barChart.js";
|
||||
import { renderHorizontalBarChart } from "./charts/horizontalBarChart.js";
|
||||
import { renderWorstSuppliersChart } from "./charts/worstSuppliersChart.js";
|
||||
import { renderProductBySupplierChart } from "./charts/productBySupplierChart.js";
|
||||
import { renderAnalysisDistributionChart } from "./charts/analysisDistributionChart.js";
|
||||
import { renderWorstTenAnalysisChart } from "./charts/worsttenanalysis.js";
|
||||
import { renderAnalytesFailChart } from "./charts/analytesFailChart.js";
|
||||
import { renderPhasePieChart } from "./charts/phasePieChart.js";
|
||||
import { renderPhaseBarChart } from "./charts/phaseBarChart.js";
|
||||
|
||||
$(document).ready(function () {
|
||||
function getFilters() {
|
||||
return {
|
||||
startDate: $("#startDate").val(),
|
||||
endDate: $("#endDate").val(),
|
||||
supplier: $("#supplierFilter").val(),
|
||||
productsRefnumber: $("#productsRefnumber").val(),
|
||||
productsSeason: $("#productsSeason").val(),
|
||||
ageRange: $("#ageRange").val(),
|
||||
reportsLabName: $("#reportsLabName").val(),
|
||||
reportsTestType: $("#reportsTestType").val(),
|
||||
reportsNumberLab: $("#reportsNumberLab").val(),
|
||||
groupingField: $("#groupingField").val(),
|
||||
};
|
||||
}
|
||||
|
||||
function updateCharts() {
|
||||
const filters = getFilters();
|
||||
|
||||
// Aggiorna il titolo dinamicamente
|
||||
const groupingText = $("#groupingField option:selected").text();
|
||||
$("#dynamicChartTitle").text(
|
||||
`Rating Distribution by Group: ${groupingText}`,
|
||||
);
|
||||
|
||||
fetchData("parsedatachart.php", filters).then((data) => {
|
||||
if (data) {
|
||||
console.log("Dati ricevuti dal backend:", data); // Aggiungi log qui
|
||||
console.log("topFailingAnalysis:", data.topFailingAnalysis);
|
||||
console.log("failedAnalytes:", data.failedAnalytes);
|
||||
|
||||
// Aggiorna le card
|
||||
$("#totalProducts").text(data.totalProducts);
|
||||
$("#totalReports").text(data.totalReports);
|
||||
$("#failedReports").text(data.failedReports);
|
||||
$("#failedReportsPercent").text(
|
||||
`(${data.failedReportsPercent.toFixed(2)}%)`,
|
||||
);
|
||||
$("#totalTests").text(data.totalTests);
|
||||
$("#failedTests").text(data.failedTests);
|
||||
$("#failedTestsPercent").text(
|
||||
`(${data.failedTestsPercent.toFixed(2)}%)`,
|
||||
);
|
||||
|
||||
// Renderizza i grafici
|
||||
renderPieChart(data, "reportPieChart", "tableChart2");
|
||||
renderBarChart(data, "reportBarChart", "tableChart3");
|
||||
renderHorizontalBarChart(
|
||||
data.horizontalBarData,
|
||||
"horizontalBarChart",
|
||||
"tableHorizontalBarChart",
|
||||
);
|
||||
renderHorizontalBarChart(
|
||||
data.horizontalBarAnalysisData,
|
||||
"horizontalBarAnalysisChart",
|
||||
"tableHorizontalBarAnalysisChart",
|
||||
);
|
||||
renderWorstSuppliersChart(
|
||||
data.worstSuppliers,
|
||||
"worstSuppliersChart",
|
||||
"tableChartWorstSuppliers",
|
||||
);
|
||||
renderProductBySupplierChart(
|
||||
data.productBySupplier,
|
||||
"productBySupplierChart",
|
||||
"tableChartProductsBySupplier",
|
||||
);
|
||||
renderAnalysisDistributionChart(
|
||||
data.analysisDistribution,
|
||||
"analysisDistributionChart",
|
||||
"tableChartAnalysisDistribution",
|
||||
);
|
||||
renderWorstTenAnalysisChart(
|
||||
data.topFailingAnalysis,
|
||||
"worsttenanalysis",
|
||||
"tableChartWorst",
|
||||
);
|
||||
renderAnalytesFailChart(
|
||||
data.failedAnalytes,
|
||||
"analytesFailChart",
|
||||
"tableChartAnalytesFail",
|
||||
);
|
||||
renderPhasePieChart(
|
||||
data.phaseData,
|
||||
"phasePieChart",
|
||||
"tableChartPhasePie",
|
||||
);
|
||||
renderPhaseBarChart(
|
||||
data.phaseRatingsData,
|
||||
"phaseBarChart",
|
||||
"tableChartPhaseBar",
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setupEventListeners() {
|
||||
$(
|
||||
"#startDate, #endDate, #supplierFilter, #productsRefnumber, #productsSeason, #ageRange, #reportsLabName, #reportsTestType, #reportsNumberLab, #groupingField",
|
||||
).on("change", updateCharts);
|
||||
$("#clearFilters").on("click", () => {
|
||||
$("#startDate").val("");
|
||||
$("#endDate").val("");
|
||||
$("#supplierFilter").val("").trigger("change");
|
||||
$("#productsRefnumber").val("").trigger("change");
|
||||
$("#productsSeason").val("").trigger("change");
|
||||
$("#ageRange").val("").trigger("change");
|
||||
$("#reportsLabName").val("").trigger("change");
|
||||
$("#reportsTestType").val("").trigger("change");
|
||||
$("#reportsNumberLab").val("").trigger("change");
|
||||
updateCharts();
|
||||
});
|
||||
|
||||
// Evento per togglare la tabella con delegazione
|
||||
$(document).on("click", ".toggle-table", function () {
|
||||
const target = $(this).data("target");
|
||||
console.log("Toggle table clicked, target:", target);
|
||||
setTimeout(() => {
|
||||
$(target).toggleClass("hidden");
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
setupEventListeners();
|
||||
updateCharts(); // Caricamento iniziale
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
export function fetchData(url, filters) {
|
||||
return $.ajax({
|
||||
url: url,
|
||||
method: "POST",
|
||||
data: filters,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response) {
|
||||
alert("No data found.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(response);
|
||||
} catch (e) {
|
||||
alert("Invalid data format.");
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
alert("Error retrieving data.");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
export function generatePieTable(labels, series) {
|
||||
let tableHTML = `
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${labels
|
||||
.map(
|
||||
(label, i) => `
|
||||
<tr>
|
||||
<td>${label}</td>
|
||||
<td>${series[i]}</td>
|
||||
</tr>
|
||||
`,
|
||||
)
|
||||
.join("")}
|
||||
</tbody>
|
||||
</table>`;
|
||||
return tableHTML;
|
||||
}
|
||||
Reference in New Issue
Block a user