added charts and fixed analysis component

This commit is contained in:
2024-11-22 11:57:39 +01:00
parent 18735127bb
commit 22c95fa063
12 changed files with 1355 additions and 556 deletions
+360
View File
@@ -0,0 +1,360 @@
<?php include('../include/headscript.php'); ?>
<?php include("../class/company.php");
// Connessione al database
$conn = new mysqli($servername, $username, $password, $database);
$limit = isset($_GET['limit']) && is_numeric($_GET['limit']) ? intval($_GET['limit']) : 50;
// Query per ottenere i dati delle sostanze
$query = "
SELECT
cv.idcompoundsvocabulary AS substance_id,
cv.namecompoundsvocabulary AS substance_name,
COUNT(CASE WHEN rp.result_AnalytsRating IN ('PASS', 'P', 'Complies') THEN 1 END) AS pass_count,
COUNT(CASE WHEN rp.result_AnalytsRating IN ('FAIL', 'F', 'Doesn\'t Comply') THEN 1 END) AS fail_count
FROM result_project rp
LEFT JOIN analysis_project ap ON rp.idanalysis_project = ap.idAnalysis_Project
LEFT JOIN compundsvocabulary cv ON rp.result_AnalytsName = cv.idcompoundsvocabulary
WHERE cv.preferred = 'Y'
GROUP BY cv.idcompoundsvocabulary, cv.namecompoundsvocabulary
ORDER BY
COUNT(CASE WHEN rp.result_AnalytsRating IN ('PASS', 'P', 'Complies') THEN 1 END) +
COUNT(CASE WHEN rp.result_AnalytsRating IN ('FAIL', 'F', 'Doesn\'t Comply') THEN 1 END) DESC
LIMIT 200;
";
$result = $conn->query($query);
$tableData = []; // Array per la tabella
while ($row = $result->fetch_assoc()) {
$substances[] = $row['substance_name'];
$passCounts[] = $row['pass_count'];
$failCounts[] = $row['fail_count'];
$substanceIds[] = $row['substance_id']; // Aggiungi l'ID della sostanza
// Aggiungi dati al $tableData per la tabella
$tableData[] = [
'id' => $row['substance_id'],
'name' => $row['substance_name'],
'pass_count' => $row['pass_count'],
'fail_count' => $row['fail_count'],
'total' => $row['pass_count'] + $row['fail_count']
];
}
$queryDetectable = "
SELECT
cv.idcompoundsvocabulary AS substance_id,
cv.namecompoundsvocabulary AS substance_name,
cv.cascompoundvocabulary AS cas_number,
COUNT(*) AS total_results,
COUNT(CASE WHEN rp.result_Value NOT LIKE '<%' THEN 1 END) AS detectable_count,
ROUND((COUNT(CASE WHEN rp.result_Value NOT LIKE '<%' THEN 1 END) / COUNT(*)) * 100, 2) AS detectable_percentage
FROM result_project rp
LEFT JOIN analysis_project ap ON rp.idanalysis_project = ap.idAnalysis_Project
LEFT JOIN compundsvocabulary cv ON rp.result_AnalytsName = cv.idcompoundsvocabulary
WHERE cv.preferred = 'Y' AND cv.component_type = 'CH'
GROUP BY cv.idcompoundsvocabulary, cv.namecompoundsvocabulary, cv.cascompoundvocabulary
ORDER BY total_results DESC;
";
$resultDetectable = $conn->query($queryDetectable);
$detectableData = []; // Array per la nuova tabella
while ($row = $resultDetectable->fetch_assoc()) {
$detectableData[] = [
'id' => $row['substance_id'],
'name' => $row['substance_name'],
'cas_number' => $row['cas_number'], // Aggiunge il CAS number
'total_results' => $row['total_results'],
'detectable_count' => $row['detectable_count'],
'detectable_percentage' => $row['detectable_percentage']
];
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<?php include('../include/seo.php'); ?>
<link rel="shortcut icon" href="../assets/images/favicon.ico">
<link href="../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="../assets/css/icons.css" rel="stylesheet" type="text/css">
<link href="../assets/css/style.css" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/boxicons@2.0.7/css/boxicons.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css" rel="stylesheet">
<script src="../assets/js/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
</head>
<body class="fixed-left">
<div id="wrapper">
<?php include('../include/navigationbar.php'); ?>
<div class="content-page">
<div class="content">
<?php include('../include/topbar.php'); ?>
<div class="page-content-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-sm-12">
<div class="page-title-box">
<div class="btn-group float-right">
<ol class="breadcrumb hide-phone p-0 m-0">
<li class="breadcrumb-item"><a href="#">Reportify</a></li>
<li class="breadcrumb-item active">Substance Statistics</li>
</ol>
</div>
<h4 class="page-title">Substance Statistics</h4>
</div>
</div>
</div>
<form method="GET" action="">
<label for="limit">Show:</label>
<select id="limit" name="limit" onchange="this.form.submit()">
<option value="10" <?php echo isset($_GET['limit']) && $_GET['limit'] == 10 ? 'selected' : ''; ?>>10</option>
<option value="50" <?php echo isset($_GET['limit']) && $_GET['limit'] == 50 ? 'selected' : ''; ?>>50</option>
<option value="100" <?php echo isset($_GET['limit']) && $_GET['limit'] == 100 ? 'selected' : ''; ?>>100</option>
<option value="200" <?php echo isset($_GET['limit']) && $_GET['limit'] == 200 ? 'selected' : ''; ?>>200</option>
<option value="500" <?php echo isset($_GET['limit']) && $_GET['limit'] == 500 ? 'selected' : ''; ?>>500</option>
</select>
records
</form>
<!-- Grafico delle sostanze -->
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Substances by Rating</h5>
<div id="substance-chart"></div>
</div>
</div>
</div>
</div>
<!-- Tabella delle sostanze -->
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Substances Data</h5>
<table id="substances-table" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Substance Name</th>
<th>Pass Count</th>
<th>Fail Count</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<?php foreach ($tableData as $data) : ?>
<tr>
<td>
<a href="substance-detail.php?id=<?php echo $data['id']; ?>" style="text-decoration:none;color:#007bff;">
<?php echo htmlspecialchars($data['name']); ?>
</a>
</td>
<td><?php echo $data['pass_count']; ?></td>
<td><?php echo $data['fail_count']; ?></td>
<td><?php echo $data['total']; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Tabella dei risultati totali e dei valori detectable -->
<!-- Tabella dei risultati totali e dei valori detectable -->
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Chemical Substance Result Summary</h5>
<table id="detectable-table" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Substance Name</th>
<th>CAS Number</th>
<th>Total Results</th>
<th>Detectable Count</th>
<th>Detectable %</th>
</tr>
</thead>
<tbody>
<?php foreach ($detectableData as $data) : ?>
<tr>
<td>
<a href="substance-detail.php?id=<?php echo $data['id']; ?>" style="text-decoration:none;color:#007bff;">
<?php echo htmlspecialchars($data['name']); ?>
</a>
</td>
<td><?php echo htmlspecialchars($data['cas_number']); ?></td>
<td><?php echo $data['total_results']; ?></td>
<td><?php echo $data['detectable_count']; ?></td>
<td><?php echo $data['detectable_percentage']; ?>%</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('../include/footer.php'); ?>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
// Recupera il numero di categorie (sostanze)
const numberOfCategories = <?php echo count($substances); ?>;
// Calcola dinamicamente l'altezza del grafico
const chartHeight = Math.min(Math.max(numberOfCategories * 40, 400), 5000);
// 40px per categoria, altezza minima 400px, altezza massima 5000px
const options = {
series: [{
name: 'PASS',
data: <?php echo json_encode($passCounts); ?>
},
{
name: 'FAIL',
data: <?php echo json_encode($failCounts); ?>
}
],
chart: {
type: 'bar',
height: chartHeight, // Altezza dinamica basata sul numero di categorie
stacked: true,
horizontal: true
},
plotOptions: {
bar: {
horizontal: true,
barHeight: '80%' // Barre più alte
}
},
xaxis: {
categories: <?php echo json_encode($substances); ?>,
labels: {
style: {
fontSize: '12px',
fontWeight: 'normal'
}
},
title: {
text: 'Number of Ratings',
style: {
fontSize: '16px',
fontWeight: 'bold'
}
}
},
yaxis: {
labels: {
style: {
fontSize: '12px',
fontWeight: 'normal',
lineHeight: '2.0'
},
maxWidth: 400 // Larghezza massima per i nomi delle sostanze
},
title: {
text: 'Substances',
style: {
fontSize: '16px',
fontWeight: 'bold'
}
}
},
colors: ['#28a745', '#dc3545'], // Colori delle barre
title: {
text: 'Substances by Rating',
align: 'center',
style: {
fontSize: '20px',
fontWeight: 'bold'
}
},
legend: {
position: 'bottom',
labels: {
style: {
fontSize: '14px',
fontWeight: 'normal'
}
}
}
};
const chart = new ApexCharts(document.querySelector("#substance-chart"), options);
chart.render();
// DataTables initialization
$('#substances-table').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
],
order: [
[3, 'desc']
], // Ordina per colonna totale
pageLength: 50
});
});
</script>
<script>
$(document).ready(function() {
$('#detectable-table').DataTable({
dom: 'Bfrtip',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
],
order: [
[2, 'desc']
], // Ordina per numero totale di risultati
pageLength: 50
});
});
</script>
</body>
</html>
+73 -3
View File
@@ -489,15 +489,21 @@ while ($row = $analysisDistributionResult->fetch_assoc()) {
// fecth analytes with most fails
$failedAnalytesQuery = "
SELECT c.namecompoundsvocabulary AS AnalyteName, COUNT(*) AS FailCount
SELECT
c.namecompoundsvocabulary AS AnalyteName,
COUNT(*) AS FailCount
FROM result_project rp
LEFT JOIN compundsvocabulary c ON rp.result_AnalytsName = c.idcompoundsvocabulary
WHERE LOWER(rp.result_AnalytsRating) IN ('f', 'fail', 'doesn\'t comply')
LEFT JOIN reports r ON rp.idreports = r.idreports
LEFT JOIN products p ON r.idproducts = p.idproducts
$filters
AND LOWER(rp.result_AnalytsRating) IN ('f', 'fail', 'doesn\'t comply')
GROUP BY c.namecompoundsvocabulary
ORDER BY FailCount DESC
LIMIT 10;
";
$resultFailedAnalytes = mysqli_query($repnew, $failedAnalytesQuery) or die("Error in Selecting " . mysqli_error($repnew));
// Verifica se ci sono risultati
@@ -510,6 +516,68 @@ while ($row = mysqli_fetch_assoc($resultFailedAnalytes)) {
];
}
// New Query: phasequery
$phaseQuery = "
SELECT
p.products_phase AS phase,
COUNT(*) AS totalProducts
FROM products p
LEFT JOIN reports r ON p.idproducts = r.idproducts
$filters
AND p.products_phase IS NOT NULL
GROUP BY p.products_phase
ORDER BY totalProducts DESC
";
$phaseQueryResult = $conn->query($phaseQuery);
// Process the results
$phaseData = [];
while ($row = $phaseQueryResult->fetch_assoc()) {
$phaseData[] = [
'phase' => $row['phase'],
'totalProducts' => $row['totalProducts']
];
}
// New Query: Phase ratings distribution
$phaseRatingsQuery = "
SELECT
p.products_phase AS phase,
SUM(CASE
WHEN UPPER(r.reportsRating) IN ('PASS', 'P', 'COMPLY') THEN 1
ELSE 0
END) AS passCount,
SUM(CASE
WHEN UPPER(r.reportsRating) IN ('FAIL', 'F', 'DOESN\'T COMPLY') THEN 1
ELSE 0
END) AS failCount,
SUM(CASE
WHEN UPPER(r.reportsRating) NOT IN ('PASS', 'P', 'COMPLY', 'FAIL', 'F', 'DOESN\'T COMPLY') THEN 1
ELSE 0
END) AS otherCount
FROM products p
LEFT JOIN reports r ON p.idproducts = r.idproducts
$filters
AND p.products_phase IS NOT NULL
GROUP BY p.products_phase
ORDER BY p.products_phase ASC
";
$phaseRatingsResult = $conn->query($phaseRatingsQuery);
// Process the results
$phaseRatingsData = [];
while ($row = $phaseRatingsResult->fetch_assoc()) {
$phaseRatingsData[] = [
'phase' => $row['phase'],
'passCount' => (int)$row['passCount'],
'failCount' => (int)$row['failCount'],
'otherCount' => (int)$row['otherCount']
];
}
// Ora controlliamo se è una richiesta AJAX
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// Rispondi ai dati aggiornati tramite AJAX
@@ -537,7 +605,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
'failedAnalytes' => $failedAnalytes,
'analysisDistribution' => $analysisDistribution, // Distribuzione delle analisi per il grafico a torta
'horizontalBarData' => $horizontalBarData, // Dati per il grafico a barre orizzontali
'horizontalBarAnalysisData' => $horizontalBarAnalysisData // Nuovi dati per le analisi
'phaseData' => $phaseData,
'horizontalBarAnalysisData' => $horizontalBarAnalysisData,
'phaseRatingsData' => $phaseRatingsData // Nuovi dati per il grafico delle fasi
]);
exit; // Ferma l'esecuzione del resto dello script dopo aver risposto all'AJAX
}
+159
View File
@@ -641,6 +641,27 @@ include('parsedatachart.php');
</div>
</div>
<div class="row mt-4">
<!-- Colonna Sinistra per il Grafico a Torta -->
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Products Distribution by Phase</h5>
<div id="phasePieChart"></div>
</div>
</div>
</div>
<!-- Colonna Destra (Vuota o per futuri contenuti) -->
<div class="col-md-6">
<div class="card">
<div class="card-body">
<h5 class="card-title">Phase Rating Distribution</h5>
<div id="phaseBarChart"></div> <!-- Contenitore per il grafico -->
</div>
</div>
</div>
</div>
</div>
@@ -1273,6 +1294,144 @@ include('parsedatachart.php');
alert('Error retrieving data.');
}
});
function renderPhasePieChart(phaseData) {
const labels = phaseData.map(item => item.phase);
const values = phaseData.map(item => parseInt(item.totalProducts, 10));
const options = {
series: values,
chart: {
type: 'pie',
height: 350
},
labels: labels,
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 300
},
legend: {
position: 'bottom'
}
}
}],
colors: ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#C9CB8D'], // Custom Colors
legend: {
position: 'bottom'
}
};
const chart = new ApexCharts(document.querySelector("#phasePieChart"), options);
chart.render();
}
// Funzione per il grafico a barre (Phase Ratings)
function renderPhaseBarChart(phaseRatingsData) {
const labels = phaseRatingsData.map(item => item.phase); // Etichette per le fasi
const passCounts = phaseRatingsData.map(item => parseInt(item.passCount, 10));
const failCounts = phaseRatingsData.map(item => parseInt(item.failCount, 10));
const otherCounts = phaseRatingsData.map(item => parseInt(item.otherCount, 10));
const options = {
series: [{
name: 'Pass',
data: passCounts
},
{
name: 'Fail',
data: failCounts
},
{
name: 'Other',
data: otherCounts
}
],
chart: {
type: 'bar',
height: 400,
stacked: true, // Barre impilate
horizontal: true
},
xaxis: {
categories: labels, // Fasi come categorie
title: {
text: 'Ratings Count' // Titolo per l'asse X
}
},
colors: ['#28A745', '#FF4D4D', '#FFA500'], // Colori per Pass, Fail e Other
plotOptions: {
bar: {
horizontal: true,
dataLabels: {
enabled: false // Disabilitiamo le etichette per ogni barra
}
}
},
legend: {
position: 'top', // Posizioniamo la leggenda sopra il grafico
},
tooltip: {
y: {
formatter: val => `${val} reports` // Tooltip personalizzato
}
}
};
$('#phaseBarChart').html(''); // Reset grafico esistente
const chart = new ApexCharts(document.querySelector("#phaseBarChart"), options);
chart.render();
}
// Chiama questa funzione dopo aver recuperato i dati tramite AJAX
$(document).ready(function() {
updateData(); // Aggiorna i dati iniziali
});
function updateData() {
$.ajax({
url: 'parsedatachart.php', // Endpoint per ottenere i dati
method: 'POST',
data: {
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(),
},
success: function(response) {
const data = JSON.parse(response);
// Aggiorna il grafico della distribuzione per fase
if (data.phaseData && data.phaseData.length > 0) {
renderPhasePieChart(data.phaseData);
} else {
console.log('No phase data available.');
}
// Aggiorna il grafico delle valutazioni per fase (Bar Chart)
if (data.phaseRatingsData && data.phaseRatingsData.length > 0) {
renderPhaseBarChart(data.phaseRatingsData);
} else {
console.log('No phase ratings data available for Bar Chart.');
$('#phaseBarChart').html('<p>No data available</p>');
}
},
error: function() {
console.log('Error retrieving data.');
}
});
}
}
@@ -0,0 +1,301 @@
<?php include('../include/headscript.php'); ?>
<?php include("../class/company.php");
// Connessione al database
$conn = new mysqli($servername, $username, $password, $database);
// Recupera l'ID della sostanza dalla query string
$substance_id = isset($_GET['id']) && is_numeric($_GET['id']) ? intval($_GET['id']) : 0;
// Query per ottenere i dettagli della sostanza
$query = "
SELECT cv.namecompoundsvocabulary AS substance_name
FROM compundsvocabulary cv
WHERE cv.idcompoundsvocabulary = ?";
$stmt = $conn->prepare($query);
$stmt->bind_param("i", $substance_id);
$stmt->execute();
$result = $stmt->get_result();
$substance = $result->fetch_assoc();
// Query per ottenere i valori della sostanza
$queryValues = "
SELECT
rp.result_Value,
rp.result_UnitofMeasure,
r.reportDateIn,
r.reportsNumberLab,
p.products_refnumber,
p.products_description,
r.idreports
FROM result_project rp
LEFT JOIN compundsvocabulary cv ON rp.result_AnalytsName = cv.idcompoundsvocabulary
LEFT JOIN reports r ON rp.idreports = r.idreports
LEFT JOIN products p ON r.idproducts = p.idproducts
WHERE cv.idcompoundsvocabulary = ?
AND (rp.result_Value REGEXP '^[0-9]+([,][0-9]+)?$' OR rp.result_Value LIKE '<%')
ORDER BY r.reportDateIn ASC;
";
$stmtValues = $conn->prepare($queryValues);
$stmtValues->bind_param("i", $substance_id);
$stmtValues->execute();
$resultValues = $stmtValues->get_result();
$values = [];
while ($row = $resultValues->fetch_assoc()) {
$values[] = $row;
}
// Query per calcolare la percentuale di valori detected
$queryDetectablePercentage = "
SELECT
ROUND(
(COUNT(CASE WHEN rp.result_Value NOT LIKE '<%' THEN 1 END) / COUNT(*)) * 100, 2
) AS detectable_percentage
FROM result_project rp
LEFT JOIN compundsvocabulary cv ON rp.result_AnalytsName = cv.idcompoundsvocabulary
WHERE cv.idcompoundsvocabulary = ? AND cv.component_type = 'CH';
";
$stmtDetectablePercentage = $conn->prepare($queryDetectablePercentage);
$stmtDetectablePercentage->bind_param("i", $substance_id);
$stmtDetectablePercentage->execute();
$resultDetectablePercentage = $stmtDetectablePercentage->get_result();
$detectableData = $resultDetectablePercentage->fetch_assoc();
$detectablePercentage = $detectableData['detectable_percentage'] ?? 0;
// Determina la classe del badge in base alla percentuale
$badgeClass = '';
if ($detectablePercentage < 3) {
$badgeClass = 'bg-success'; // Verde
} elseif ($detectablePercentage >= 3 && $detectablePercentage < 10) {
$badgeClass = 'bg-info'; // Azzurro
} elseif ($detectablePercentage >= 10 && $detectablePercentage < 30) {
$badgeClass = 'bg-warning'; // Arancio
} else {
$badgeClass = 'bg-danger'; // Rosso
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
<?php include('../include/seo.php'); ?>
<link rel="shortcut icon" href="../assets/images/favicon.ico">
<link href="../assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="../assets/css/icons.css" rel="stylesheet" type="text/css">
<link href="../assets/css/style.css" rel="stylesheet" type="text/css">
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/buttons/2.3.6/css/buttons.dataTables.min.css" rel="stylesheet">
<script src="../assets/js/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/dataTables.buttons.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.3/jszip.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/2.3.6/js/buttons.print.min.js"></script>
</head>
<body class="fixed-left">
<div id="wrapper">
<?php include('../include/navigationbar.php'); ?>
<div class="content-page">
<div class="content">
<?php include('../include/topbar.php'); ?>
<div class="page-content-wrapper">
<div class="container-fluid">
<br>
<div class="row">
<div class="col-md-12">
<div class="card shadow">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center">
<div>
<h1 class="mb-1 text-primary">
<i class="fas fa-flask"></i>
<?php echo htmlspecialchars($substance['substance_name']); ?>
<span class="badge <?php echo $badgeClass; ?> px-3 py-2">
<?php echo $detectablePercentage; ?>% Detected
</span>
</h1>
<p class="text-muted mb-0">Comprehensive analysis and details</p>
</div>
<div class="text-end">
<span class="badge bg-success px-3 py-2">
ID: <?php echo $substance_id; ?>
</span>
<span class="badge bg-info px-3 py-2">
Last Updated: <?php echo date('d M Y'); ?>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Grafico -->
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Distribution of Values</h5>
<div id="value-chart"></div>
</div>
</div>
</div>
</div>
<!-- Tabella -->
<div class="row mt-4">
<div class="col-md-12">
<div class="card">
<div class="card-body">
<h5 class="card-title">Values Table</h5>
<table id="values-table" class="display nowrap" style="width:100%">
<thead>
<tr>
<th>Date</th>
<th>Report Number</th>
<th>Product Ref</th>
<th>Value</th>
<th>Unit</th>
</tr>
</thead>
<tbody>
<?php foreach ($values as $value): ?>
<tr>
<td><?php echo htmlspecialchars($value['reportDateIn']); ?></td>
<td>
<a href="../products/reportdetails.php?idreports=<?php echo $value['idreports']; ?>" style="text-decoration:none;color:#007bff;">
<?php echo htmlspecialchars($value['reportsNumberLab']); ?>
</a>
</td>
<td><?php echo htmlspecialchars($value['products_refnumber']); ?></td>
<td>
<?php
$rawValue = str_replace(',', '.', $value['result_Value']);
if (str_starts_with($rawValue, '<')) {
echo '<span style="color: gray;">' . htmlspecialchars($rawValue) . '</span>';
} else {
echo '<span style="color: green;">' . htmlspecialchars($rawValue) . '</span>';
}
?>
</td>
<td><?php echo htmlspecialchars($value['result_UnitofMeasure']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php include('../include/footer.php'); ?>
</div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function() {
const values = <?php echo json_encode(array_values(array_filter($values, function ($row) {
$rawValue = str_replace(',', '.', $row['result_Value']);
return is_numeric($rawValue) || str_starts_with($rawValue, '<');
}))); ?>;
const dataPoints = values.map((val) => ({
x: val.reportDateIn,
y: parseFloat(val.result_Value.replace(',', '.')) || null,
}));
// Configura il grafico scatter
const options = {
series: [{
name: 'Value',
data: dataPoints,
}, ],
chart: {
type: 'scatter',
height: 500,
},
xaxis: {
type: 'datetime',
title: {
text: 'Date',
},
labels: {
datetimeFormatter: {
year: 'yyyy',
month: 'MMM yyyy',
day: 'dd MMM',
},
},
},
yaxis: {
title: {
text: 'Value',
},
},
markers: {
size: 5,
},
};
const chart = new ApexCharts(document.querySelector("#value-chart"), options);
chart.render();
// Configurazione DataTables
$('#values-table').DataTable({
pageLength: 100,
dom: 'Bfrtip',
buttons: ['copy', 'csv', 'excel', 'pdf', 'print'],
order: [
[0, 'asc']
], // Ordina per data in modo crescente
columnDefs: [{
targets: 0, // Colonna delle date
render: function(data, type, row) {
if (type === 'display' || type === 'filter') {
return new Date(data).toLocaleDateString();
}
return data; // Mantiene il formato originale per l'ordinamento
},
}, ],
});
});
</script>
</body>
</html>