1349 lines
60 KiB
PHP
1349 lines
60 KiB
PHP
<?php include('../include/headscript.php'); ?>
|
|
<?php include("../class/company.php");
|
|
include('parsedatachart.php');
|
|
?>
|
|
<!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'); ?>
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
|
|
<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">
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@10/dist/sweetalert2.min.css">
|
|
<script src="../assets/js/jquery.min.js"></script>
|
|
<link rel="stylesheet" href="../assets/plugins/select2/select2.min.css">
|
|
<script src="../assets/plugins/select2/select2.min.js"></script>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/4.2.6/gridstack.min.css" />
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/4.2.6/gridstack-h5.min.js"></script>
|
|
|
|
|
|
<style>
|
|
#activeFilters {
|
|
display: flex;
|
|
font-size: 16px;
|
|
flex-direction: row;
|
|
background: 0;
|
|
}
|
|
|
|
|
|
.badge {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
|
|
.width-100 {
|
|
width: 100%;
|
|
}
|
|
|
|
.flex_center {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.mg_none {
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.hidden {
|
|
display: none !important;
|
|
}
|
|
|
|
.table-custom tr {
|
|
height: 40px;
|
|
line-height: 40px;
|
|
}
|
|
|
|
#ajax_preloader {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: transparent;
|
|
z-index: 9999999;
|
|
}
|
|
|
|
.table-custom td,
|
|
.table-custom th {
|
|
padding: 4px 8px;
|
|
}
|
|
|
|
.table-custom .btn {
|
|
padding: 2px 15px;
|
|
line-height: 1.7;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.form-row {
|
|
display: flex;
|
|
align-items: center;
|
|
/* Questo allinea verticalmente gli elementi nella riga */
|
|
gap: 10px;
|
|
/* Questo crea una piccola distanza tra gli elementi nella riga */
|
|
}
|
|
|
|
.table-custom .form-control,
|
|
.table-custom .form-select {
|
|
height: 25px;
|
|
/* Puoi modificare questo valore per adattarlo al tuo design */
|
|
padding: 2px 6px;
|
|
/* riduce la dimensione del padding */
|
|
font-size: 14px;
|
|
/* riduce la dimensione del font */
|
|
}
|
|
|
|
.table-custom .form-control-sm.analysis-input {
|
|
height: 25px;
|
|
/* Questo modifica la dimensione degli input con classe 'form-control-sm' e 'analysis-input' */
|
|
padding: 2px 6px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.padding_none {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
.select2-container--open {
|
|
z-index: 9999;
|
|
}
|
|
|
|
.card {
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
|
|
transition: transform 0.2s ease-in-out;
|
|
}
|
|
|
|
.card:hover {
|
|
transform: translateY(-3px);
|
|
}
|
|
|
|
.card-body {
|
|
padding: 20px;
|
|
}
|
|
|
|
.card h2 {
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.card h5 {
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.card {
|
|
min-height: 150px;
|
|
/* Imposta un'altezza minima per le card */
|
|
}
|
|
|
|
.percentage {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin-top: 5px;
|
|
margin-left: 10px;
|
|
}
|
|
|
|
.bg-light {
|
|
background-color: #f8f9fa !important;
|
|
}
|
|
|
|
.border-primary {
|
|
border: 2px solid #007bff !important;
|
|
}
|
|
|
|
.border-info {
|
|
border: 2px solid #17a2b8 !important;
|
|
}
|
|
|
|
.border-danger {
|
|
border: 2px solid #dc3545 !important;
|
|
}
|
|
|
|
.border-success {
|
|
border: 2px solid #28a745 !important;
|
|
}
|
|
|
|
.border-warning {
|
|
border: 2px solid #ffc107 !important;
|
|
}
|
|
|
|
.row {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.col-md-2 {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
.col-md-2 {
|
|
flex: 0 0 100%;
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
|
|
.filters-applied {
|
|
display: inline-block;
|
|
color: white;
|
|
border-radius: 5px;
|
|
padding: 5px 10px;
|
|
font-weight: bold;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.chart-container {
|
|
width: 100%;
|
|
margin: 20px;
|
|
}
|
|
|
|
.chart-box {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
</style>
|
|
|
|
</head>
|
|
|
|
|
|
<body class="fixed-left">
|
|
|
|
<!-- Loader -->
|
|
<div id="preloader">
|
|
<div id="status">
|
|
<div class="spinner"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- sidebar filter style -->
|
|
<style>
|
|
.filter-sidebar {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
width: 300px;
|
|
height: 100%;
|
|
background: #f8f9fa;
|
|
box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
|
|
padding: 20px;
|
|
display: none;
|
|
z-index: 999;
|
|
}
|
|
|
|
.active-filters {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
body {
|
|
transition: margin-right 0.3s;
|
|
/* Smooth transition */
|
|
}
|
|
|
|
#main-content {
|
|
transition: margin-right 0.3s;
|
|
/* Smooth transition */
|
|
}
|
|
|
|
.collapsed {
|
|
margin-right: 300px;
|
|
/* Hide the sidebar */
|
|
}
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Begin page -->
|
|
<div id="wrapper">
|
|
|
|
<?php include('../include/navigationbar.php'); ?>
|
|
|
|
<!-- Start right Content here -->
|
|
|
|
<div class="content-page">
|
|
<!-- Start content -->
|
|
<div class="content">
|
|
|
|
<?php include('../include/topbar.php'); ?>
|
|
|
|
<div class="page-content-wrapper " id="main-content">
|
|
|
|
<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">Importify</li>
|
|
</ol>
|
|
</div>
|
|
<h4 class="page-title">Importify</h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end page title end breadcrumb -->
|
|
|
|
<button id="toggleFilters" class="btn btn-primary">Toggle Filters</button>
|
|
|
|
<!-- Right Sidebar -->
|
|
<div class="filter-sidebar" id="filterSidebar">
|
|
<?php
|
|
|
|
// 'refNumbers' => $refNumbers,
|
|
// 'productsSeasons' => $productsSeasons,
|
|
// 'ageRange' => $ageRange,
|
|
// 'labName' => $labName,
|
|
// 'tesType' => $tesType,
|
|
// 'numberLabs' => $numberLabs,
|
|
|
|
?>
|
|
<div class="form-group">
|
|
<label for="productsRefnumber">Product Ref Number</label>
|
|
<select id="productsRefnumber" class="form-control select2" multiple>
|
|
|
|
<?php foreach ($refNumbers as $refNumber): ?>
|
|
<option value="<?php echo $refNumber['refNumber']; ?>"><?php echo $refNumber['refNumber']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="productsSeason">Product Season</label>
|
|
<select id="productsSeason" class="form-control select2" multiple>
|
|
<?php foreach ($productsSeasons as $productSeason): ?>
|
|
<option value="<?php echo $productSeason['season']; ?>"><?php echo $productSeason['season']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="ageRange">Age Range</label>
|
|
<select id="ageRange" class="form-control select2" multiple>
|
|
<?php foreach ($ageRange as $age): ?>
|
|
<option value="<?php echo $age['ageRange']; ?>"><?php echo $age['ageRange']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="reportsLabName">Lab Name</label>
|
|
<select id="reportsLabName" class="form-control select2" multiple>
|
|
<?php foreach ($labName as $lab): ?>
|
|
<option value="<?php echo $lab['labName']; ?>"><?php echo $lab['labName']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="reportsTestType">Tes Type</label>
|
|
<select id="reportsTestType" class="form-control select2" multiple>
|
|
<?php foreach ($tesType as $test): ?>
|
|
<option value="<?php echo $test['tesType']; ?>"><?php echo $test['tesType']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="reportsNumberLab">Report Number</label>
|
|
<select id="reportsNumberLab" class="form-control select2" multiple>
|
|
<?php foreach ($numberLabs as $number): ?>
|
|
<option value="<?php echo $number['reportNumber']; ?>"><?php echo $number['reportNumber']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scripts -->
|
|
<script>
|
|
$(document).ready(function() {
|
|
$('.select2').select2({
|
|
placeholder: "Select options",
|
|
allowClear: true
|
|
});
|
|
|
|
$('#toggleFilters').on('click', function() {
|
|
$('#filterSidebar').toggle();
|
|
$('#main-content').toggleClass('collapsed');
|
|
});
|
|
|
|
$('.select2').on('change', function() {
|
|
updateActiveFilters();
|
|
});
|
|
|
|
$('#startDate, #endDate').on('change', function() {
|
|
updateActiveFilters();
|
|
});
|
|
|
|
function updateActiveFilters() {
|
|
let activeFilters = [];
|
|
$('.select2').each(function() {
|
|
const selectedValues = $(this).val();
|
|
if (selectedValues) {
|
|
// activeFilters with values
|
|
// activeFilters.push(`${$(this).prev('label').text()}: ${selectedValues.join(', ')}`);
|
|
// activefilters without values
|
|
activeFilters.push($(this).prev('label').text());
|
|
}
|
|
});
|
|
$('#startDate, #endDate').each(function() {
|
|
const selectedValue = $(this).val();
|
|
if (selectedValue) {
|
|
activeFilters.push($(this).prev('label').text());
|
|
}
|
|
})
|
|
|
|
$('#activeFilters').html(activeFilters.map(f => `<span class="badge badge-info mr-1">${f} <button class="close" onclick="removeFilter('${f}')">×</button></span>`).join(''));
|
|
|
|
}
|
|
});
|
|
|
|
function removeFilter(filter) {
|
|
const label = filter.split(':')[0];
|
|
const select = $('label').filter(function() {
|
|
return $(this).text().trim() === label;
|
|
}).next('select');
|
|
|
|
const dateInput = $('label').filter(function() {
|
|
return $(this).text().trim() === label;
|
|
}).next('input')
|
|
|
|
// Clear the select2 field
|
|
if (select.length) {
|
|
select.val(null).trigger('change');
|
|
}
|
|
// Clear the date field
|
|
if (dateInput.length) {
|
|
dateInput.val(null).trigger('change');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
|
|
<div class="row">
|
|
<div class="col-xl-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="header-title pb-3 mt-0">Importify: <?php echo $dashboard; ?></h5>
|
|
|
|
<!-- Filter Section -->
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<label for="startDate">Start Date</label>
|
|
<input type="date" id="startDate" class="form-control" placeholder="Start Date">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="endDate">End Date</label>
|
|
<input type="date" id="endDate" class="form-control" placeholder="End Date">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label for="supplierFilter">Supplier</label>
|
|
<select id="supplierFilter" class="form-control select2" multiple>
|
|
<?php foreach ($productBySupplier as $supplier): ?>
|
|
<option value="<?php echo $supplier['supplier']; ?>"><?php echo $supplier['supplier']; ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<!-- Active Filters Display -->
|
|
<div id="activeFiltersDiv" class="mt-3" style="background-color:white;">
|
|
<h6>Active Filters:</h6>
|
|
<div id="activeFilters" class="filters-applied badge badge-info p-2" style="font-size: 16px;"></div>
|
|
<button id="clearFilters" class="btn btn-sm btn-warning ml-3">Clear Filters</button>
|
|
</div>
|
|
|
|
|
|
<hr>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end row -->
|
|
|
|
<div class="chart-container" id="charts">
|
|
|
|
<div class="row chart-box" id="chart1" data-id="1">
|
|
<div class="col-xl-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
|
|
|
|
<!-- cards -->
|
|
<div class="row justify-content-between">
|
|
<div class="col-md-2 col-sm-6">
|
|
<div class="card text-center bg-light border-primary">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Products</h5>
|
|
<h2 id="totalProducts">0</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2 col-sm-6">
|
|
<div class="card text-center bg-light border-info">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Reports</h5>
|
|
<h2 id="totalReports">0</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2 col-sm-6">
|
|
<div class="card text-center bg-light border-danger">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Failed Reports</h5>
|
|
<div class="d-flex justify-content-center align-items-baseline">
|
|
<h2 id="failedReports">0</h2>
|
|
<span class="percentage text-danger" id="failedReportsPercent" style="margin-left: 10px;">(0%)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2 col-sm-6">
|
|
<div class="card text-center bg-light border-success">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Total Tests</h5>
|
|
<h2 id="totalTests">0</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2 col-sm-6">
|
|
<div class="card text-center bg-light border-warning">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Failed Tests</h5>
|
|
<div class="d-flex justify-content-center align-items-baseline">
|
|
<h2 id="failedTests">0</h2>
|
|
<span class="percentage text-danger" id="failedTestsPercent" style="margin-left: 10px;">(0%)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- end row -->
|
|
|
|
<div class="row chart-box" id="chart2" data-id="2">
|
|
<div class="col-md-4"> <!-- Colonna per il primo grafico (Pie Chart) -->
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title" id="reports_overview">Reports Overview</h5>
|
|
<div id="reportPieChart"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-8"> <!-- Colonna per il secondo grafico -->
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Worst Analysis</h5>
|
|
<div id="worsttenanalysis"></div> <!-- Questo è lo spazio per il secondo grafico -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row chart-box" id="chart3" data-id="3">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Worst Suppliers by Failed Report Percentage</h5>
|
|
<div id="worstSuppliersChart"></div> <!-- Il grafico verrà inserito qui -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row chart-box" id="chart4" data-id="4">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Number of Products by Supplier</h5>
|
|
<div id="productBySupplierChart"></div> <!-- Lo spazio per il grafico -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row chart-box" id="chart5" data-id="5">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Analysis Distribution</h5>
|
|
<div id="analysisDistributionChart"></div> <!-- Il grafico verrà inserito qui -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row chart-box" id="chart6" data-id="6">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Analytes with Most Failures</h5>
|
|
<div id="analytesFailChart"></div> <!-- Lo spazio per il grafico -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row chart-box" id="chart7" data-id="7">
|
|
<div class="col-md-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title" id="dynamicChartTitle">Rating Distribution by Group</h5>
|
|
|
|
<!-- Inserisci il dropdown direttamente all'interno della card -->
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<label for="groupingField">Group by:</label>
|
|
<select id="groupingField" class="form-control">
|
|
<option value="products_season">Product Season</option>
|
|
<option value="agerange">Age Range</option>
|
|
<option value="namesupplier">Name Supplier</option>
|
|
<!-- Aggiungi altri campi se necessario -->
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Area per il grafico -->
|
|
<br>
|
|
<h6 class="mt-4">Report Rating Distribution</h6> <!-- Titolo per il primo grafico -->
|
|
<div id="horizontalBarChart"></div>
|
|
|
|
<h6 class="mt-4">Analysis Rating Distribution</h6> <!-- Titolo per il secondo grafico -->
|
|
<div id="horizontalBarAnalysisChart"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
</div><!-- container -->
|
|
|
|
</div> <!-- Page content Wrapper -->
|
|
|
|
</div> <!-- content -->
|
|
|
|
<?php include('../include/footer.php'); ?>
|
|
|
|
</div>
|
|
<!-- End Right content here -->
|
|
|
|
</div>
|
|
<!-- END wrapper -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
|
|
<script>
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
const chartContainer = document.getElementById('charts');
|
|
const sortable = new Sortable(chartContainer, {
|
|
animation: 150,
|
|
onEnd: function() {
|
|
saveChartOrder(); // Save chart order after dragging
|
|
}
|
|
});
|
|
|
|
// Function to save chart order to localStorage
|
|
function saveChartOrder() {
|
|
const order = Array.from(chartContainer.children).map(chart => chart.dataset.id);
|
|
localStorage.setItem('chartOrder', JSON.stringify(order));
|
|
|
|
// lets save it for the user
|
|
$.ajax({
|
|
url: 'chartorder.php',
|
|
method: 'POST',
|
|
data: {
|
|
method: 'save',
|
|
order: order
|
|
},
|
|
success: function(response) {
|
|
|
|
},
|
|
error: function() {
|
|
alert('Error saving chart order.');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Function to restore chart order from localStorage
|
|
function loadChartOrder() {
|
|
|
|
// Load the saved order from localStorage
|
|
|
|
const savedOrder = JSON.parse(localStorage.getItem('chartOrder'));
|
|
if (savedOrder) {
|
|
savedOrder.forEach(id => {
|
|
const chart = document.querySelector(`[data-id='${id}']`);
|
|
chartContainer.appendChild(chart); // Append charts in saved order
|
|
});
|
|
}
|
|
|
|
// Load the saved order from the database
|
|
$.ajax({
|
|
url: 'chartorder.php',
|
|
method: 'POST',
|
|
data: {
|
|
method: 'load'
|
|
},
|
|
success: function(response) {
|
|
|
|
const order = JSON.parse(response);
|
|
order.forEach(id => {
|
|
const chart = document.querySelector(`[data-id='${id}']`);
|
|
chartContainer.appendChild(chart); // Append charts in saved order
|
|
});
|
|
},
|
|
});
|
|
}
|
|
|
|
// Load the saved chart order when the page loads
|
|
loadChartOrder();
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Funzione per aggiornare i dati con AJAX
|
|
function updateData() {
|
|
var startDate = $('#startDate').val();
|
|
var endDate = $('#endDate').val();
|
|
var supplier = $('#supplierFilter').val();
|
|
var productsRefnumber = $('#productsRefnumber').val();
|
|
var productsSeason = $('#productsSeason').val();
|
|
var ageRange = $('#ageRange').val();
|
|
var reportsLabName = $('#reportsLabName').val();
|
|
var reportsTestType = $('#reportsTestType').val();
|
|
var reportsNumberLab = $('#reportsNumberLab').val();
|
|
var groupingField = $('#groupingField').val();
|
|
|
|
// Aggiorna il titolo dinamicamente in base alla selezione del dropdown
|
|
var groupingText = $('#groupingField option:selected').text(); // Ottieni il testo dell'opzione selezionata
|
|
$('#dynamicChartTitle').text(`Rating Distribution by Group: ${groupingText}`); // Aggiorna il titolo
|
|
|
|
|
|
|
|
$.ajax({
|
|
url: 'parsedatachart.php',
|
|
method: 'POST',
|
|
data: {
|
|
startDate: startDate,
|
|
endDate: endDate,
|
|
supplier: supplier,
|
|
productsRefnumber: productsRefnumber,
|
|
productsSeason: productsSeason,
|
|
ageRange: ageRange,
|
|
reportsLabName: reportsLabName,
|
|
reportsTestType: reportsTestType,
|
|
reportsNumberLab: reportsNumberLab,
|
|
groupingField: groupingField
|
|
},
|
|
success: function(response) {
|
|
if (!response) {
|
|
alert('No data found.');
|
|
data = {};
|
|
return;
|
|
} else {
|
|
var data = JSON.parse(response);
|
|
}
|
|
|
|
// Aggiorna le cards con i nuovi dati
|
|
$('#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) + '%)');
|
|
|
|
// Aggiorna il grafico della distribuzione delle analisi
|
|
if (data.analysisDistribution && data.analysisDistribution.length > 0) {
|
|
// Ordina i dati per numero di test e prendi solo i primi 15
|
|
var sortedData = data.analysisDistribution.sort(function(a, b) {
|
|
return b.totalTests - a.totalTests;
|
|
}).slice(0, 15); // Prendi solo le prime 15 analisi
|
|
|
|
var analysisLabels = sortedData.map(function(item) {
|
|
return item.analysisName;
|
|
});
|
|
var analysisCounts = sortedData.map(function(item) {
|
|
return parseInt(item.totalTests, 10); // Converte il conteggio dei test in numeri interi
|
|
});
|
|
|
|
}
|
|
|
|
// remove pie chart and create a new one
|
|
$('#reportPieChart').html('');
|
|
|
|
var intFailReports = parseInt(data.failReportsPie);
|
|
var intPassReports = parseInt(data.passReportsPie);
|
|
var intOtherReports = parseInt(data.otherReportsPie);
|
|
|
|
// Data for pie chart (Reports: Fail, Pass, Others)
|
|
var options = {
|
|
series: [intFailReports, intPassReports, intOtherReports],
|
|
chart: {
|
|
width: '100%', // Mantieni la larghezza al 100% all'interno della colonna Bootstrap
|
|
type: 'pie',
|
|
},
|
|
labels: ['Fail', 'Pass', 'Others'],
|
|
colors: ['#FF4D4D', '#28A745', '#FFA500'], // Red for Fail, Green for Pass, Orange for Others
|
|
responsive: [{
|
|
breakpoint: 480,
|
|
options: {
|
|
chart: {
|
|
width: 250 // Riduci la larghezza sui dispositivi mobili
|
|
},
|
|
legend: {
|
|
position: 'bottom'
|
|
}
|
|
}
|
|
}],
|
|
legend: {
|
|
position: 'bottom', // Posiziona la legenda sotto il grafico
|
|
offsetY: 0,
|
|
height: 50, // Altezza della legenda
|
|
}
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#reportPieChart"), options);
|
|
chart.render();
|
|
|
|
// remove bar chart and create a new one
|
|
$('#worsttenanalysis').html('');
|
|
|
|
// Data for the bar chart
|
|
var analysisNames = data.topFailingAnalysis.map(function(item) {
|
|
return item.name;
|
|
});
|
|
var failCounts = data.topFailingAnalysis.map(function(item) {
|
|
return parseInt(item.failCount, 10);
|
|
});
|
|
|
|
var options = {
|
|
series: [{
|
|
data: failCounts
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 350
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
dataLabels: {
|
|
position: 'center' // Posiziona i nomi delle analisi al centro delle barre
|
|
}
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true,
|
|
style: {
|
|
colors: ['#fff'], // Colore del testo all'interno delle barre (bianco)
|
|
fontSize: '12px'
|
|
},
|
|
formatter: function(val, opt) {
|
|
return analysisNames[opt.dataPointIndex]; // Mostra il nome dell'analisi dentro la barra
|
|
}
|
|
},
|
|
xaxis: {
|
|
categories: failCounts, // Visualizza solo i numeri sull'asse X
|
|
title: {
|
|
text: 'Number of Failures'
|
|
}
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
show: false // Nascondiamo le etichette dell'asse Y
|
|
},
|
|
title: {
|
|
text: 'Analysis'
|
|
}
|
|
},
|
|
colors: ['#FF4D4D'], // Rosso per i Fail
|
|
responsive: [{
|
|
breakpoint: 480,
|
|
options: {
|
|
chart: {
|
|
height: 300
|
|
},
|
|
xaxis: {
|
|
labels: {
|
|
show: true
|
|
}
|
|
}
|
|
}
|
|
}],
|
|
title: {
|
|
text: 'Top 10 Analyses with the Most Failures',
|
|
align: 'center'
|
|
}
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#worsttenanalysis"), options);
|
|
chart.render();
|
|
|
|
// Genera il nuovo grafico a barre orizzontali
|
|
$('#horizontalBarChart').html('');
|
|
var horizontalBarData = data.horizontalBarData;
|
|
var categories = horizontalBarData.map(item => item.groupingValue);
|
|
var passData = horizontalBarData.map(item => item.passCount);
|
|
var failData = horizontalBarData.map(item => item.failCount);
|
|
var otherData = horizontalBarData.map(item => item.otherCount);
|
|
|
|
var options = {
|
|
series: [{
|
|
name: 'Pass',
|
|
data: passData
|
|
},
|
|
{
|
|
name: 'Fail',
|
|
data: failData
|
|
},
|
|
{
|
|
name: 'Others',
|
|
data: otherData
|
|
}
|
|
],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 400,
|
|
stacked: true,
|
|
horizontal: true
|
|
},
|
|
xaxis: {
|
|
categories: categories
|
|
},
|
|
colors: ['#28A745', '#FF4D4D', '#FFA500'],
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
dataLabels: {
|
|
enabled: false
|
|
}
|
|
}
|
|
},
|
|
legend: {
|
|
position: 'top'
|
|
},
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#horizontalBarChart"), options);
|
|
chart.render();
|
|
|
|
// Dati per il grafico delle analisi
|
|
var horizontalBarAnalysisData = data.horizontalBarAnalysisData;
|
|
var categoriesAnalysis = horizontalBarAnalysisData.map(item => item.groupingValue);
|
|
var passDataAnalysis = horizontalBarAnalysisData.map(item => item.passCount);
|
|
var failDataAnalysis = horizontalBarAnalysisData.map(item => item.failCount);
|
|
var otherDataAnalysis = horizontalBarAnalysisData.map(item => item.otherCount);
|
|
|
|
// Crea o aggiorna il grafico delle analisi
|
|
$('#horizontalBarAnalysisChart').html('');
|
|
var optionsAnalysis = {
|
|
series: [{
|
|
name: 'Pass',
|
|
data: passDataAnalysis
|
|
},
|
|
{
|
|
name: 'Fail',
|
|
data: failDataAnalysis
|
|
},
|
|
{
|
|
name: 'Others',
|
|
data: otherDataAnalysis
|
|
}
|
|
],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 400,
|
|
stacked: true,
|
|
horizontal: true
|
|
},
|
|
xaxis: {
|
|
categories: categoriesAnalysis
|
|
},
|
|
colors: ['#28A745', '#FF4D4D', '#FFA500'],
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
dataLabels: {
|
|
enabled: false
|
|
}
|
|
}
|
|
},
|
|
legend: {
|
|
position: 'top'
|
|
},
|
|
};
|
|
var chartAnalysis = new ApexCharts(document.querySelector("#horizontalBarAnalysisChart"), optionsAnalysis);
|
|
chartAnalysis.render();
|
|
|
|
// remove bar chart and create a new one
|
|
$('#worstSuppliersChart').html('');
|
|
|
|
// Data for the bar chart of worst suppliers
|
|
var supplierNames = data.worstSuppliers.map(function(item) {
|
|
return item.supplier;
|
|
});
|
|
var failPercentages = data.worstSuppliers.map(function(item) {
|
|
return parseFloat(item.failPercentage);
|
|
});
|
|
var totalReportsForSupplier = data.worstSuppliers.map(function(item) {
|
|
return parseInt(item.totalReports, 10);
|
|
});
|
|
var failedReportsForSupplier = data.worstSuppliers.map(function(item) {
|
|
return parseInt(item.failedReports, 10);
|
|
});
|
|
|
|
var options = {
|
|
series: [{
|
|
data: failPercentages
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 400
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
dataLabels: {
|
|
position: 'center' // Etichette al centro delle barre
|
|
}
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true,
|
|
style: {
|
|
colors: ['#fff'], // Colore del testo all'interno delle barre
|
|
fontSize: '12px'
|
|
},
|
|
formatter: function(val, opt) {
|
|
// Aggiungi nome del fornitore, percentuale, numero di fail e numero totale di report
|
|
var totalReports = totalReportsForSupplier[opt.dataPointIndex]; // Numero totale di report
|
|
var failedReports = failedReportsForSupplier[opt.dataPointIndex]; // Numero di report falliti
|
|
return supplierNames[opt.dataPointIndex] + ' (' + val.toFixed(2) + '%) (Fail: ' + failedReports + ' - Total: ' + totalReports + ')';
|
|
}
|
|
},
|
|
xaxis: {
|
|
categories: supplierNames, // Visualizza i nomi dei fornitori
|
|
title: {
|
|
text: 'Failure Percentage (%)'
|
|
}
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
show: false // Nascondiamo le etichette dell'asse Y
|
|
},
|
|
title: {
|
|
text: 'Suppliers'
|
|
}
|
|
},
|
|
colors: ['#3368FF'], // Colore blu chiaro per le barre
|
|
title: {
|
|
text: 'Top 10 Suppliers with the Highest Failed Reports Percentage',
|
|
align: 'center'
|
|
}
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#worstSuppliersChart"), options);
|
|
chart.render();
|
|
|
|
// remove bar chart and create a new one
|
|
$('#productBySupplierChart').html('');
|
|
|
|
// Prepara i dati per il grafico
|
|
var supplierNames = data.productBySupplier.map(function(item) {
|
|
return item.supplier;
|
|
});
|
|
var totalProducts = data.productBySupplier.map(function(item) {
|
|
return parseInt(item.totalProducts, 10);
|
|
});
|
|
|
|
var options = {
|
|
series: [{
|
|
name: 'Total Products',
|
|
data: totalProducts
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 400
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: false, // Imposta il grafico a barre verticali
|
|
columnWidth: '50%',
|
|
dataLabels: {
|
|
position: 'top', // Etichette nella parte superiore delle barre
|
|
}
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true,
|
|
offsetY: -20,
|
|
style: {
|
|
fontSize: '12px',
|
|
colors: ['#000']
|
|
}
|
|
},
|
|
xaxis: {
|
|
categories: supplierNames,
|
|
title: {
|
|
text: 'Suppliers'
|
|
}
|
|
},
|
|
yaxis: {
|
|
title: {
|
|
text: 'Number of Products'
|
|
}
|
|
},
|
|
colors: ['#3368FF'],
|
|
title: {
|
|
text: 'Number of Products by Supplier',
|
|
align: 'center'
|
|
}
|
|
};
|
|
|
|
var chart = new ApexCharts(document.querySelector("#productBySupplierChart"), options);
|
|
chart.render();
|
|
|
|
// remove bar chart and create a new one
|
|
$('#analysisDistributionChart').html(''); // Resetta il contenuto del div
|
|
|
|
|
|
var analysisNames = data.analysisDistribution.map(function(item) {
|
|
return item.analysisName;
|
|
});
|
|
var totalTests = data.analysisDistribution.map(function(item) {
|
|
return parseInt(item.totalTests, 10);
|
|
});
|
|
|
|
var analysisBarChartOptions = {
|
|
series: [{
|
|
name: 'Total Tests',
|
|
data: totalTests
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 500
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
columnWidth: '100%',
|
|
endingShape: 'rounded'
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true
|
|
},
|
|
stroke: {
|
|
show: true,
|
|
width: 2,
|
|
colors: ['transparent']
|
|
},
|
|
xaxis: {
|
|
categories: analysisNames,
|
|
title: {
|
|
text: 'Number of Tests'
|
|
}
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
show: true,
|
|
maxWidth: 700,
|
|
style: {
|
|
fontSize: '12px',
|
|
colors: ['#000']
|
|
}
|
|
},
|
|
title: {
|
|
text: 'Analysis Name'
|
|
}
|
|
},
|
|
fill: {
|
|
opacity: 1,
|
|
colors: ['#004d00']
|
|
},
|
|
tooltip: {
|
|
y: {
|
|
formatter: function(val) {
|
|
return val + " tests";
|
|
}
|
|
}
|
|
},
|
|
title: {
|
|
text: 'Analysis Distribution',
|
|
align: 'center'
|
|
},
|
|
grid: {
|
|
padding: {
|
|
left: 10
|
|
}
|
|
}
|
|
};
|
|
|
|
var analysisBarChart = new ApexCharts(document.querySelector("#analysisDistributionChart"), analysisBarChartOptions);
|
|
analysisBarChart.render();
|
|
|
|
// remove bar chart and create a new one
|
|
$('#analytesFailChart').html('');
|
|
var analyteNames = data.failedAnalytes.map(function(item) {
|
|
return item.AnalyteName;
|
|
});
|
|
var failCounts = data.failedAnalytes.map(function(item) {
|
|
return parseInt(item.FailCount, 10);
|
|
});
|
|
|
|
var options = {
|
|
series: [{
|
|
data: failCounts
|
|
}],
|
|
chart: {
|
|
type: 'bar',
|
|
height: 400
|
|
},
|
|
plotOptions: {
|
|
bar: {
|
|
horizontal: true,
|
|
dataLabels: {
|
|
position: 'center' // Etichette al centro delle barre
|
|
}
|
|
}
|
|
},
|
|
dataLabels: {
|
|
enabled: true,
|
|
style: {
|
|
colors: ['#fff'], // Colore del testo all'interno delle barre
|
|
fontSize: '12px'
|
|
},
|
|
formatter: function(val, opt) {
|
|
return analyteNames[opt.dataPointIndex]; // Mostra il nome dell'analita dentro la barra
|
|
}
|
|
},
|
|
xaxis: {
|
|
categories: failCounts, // Visualizza solo i numeri sull'asse X
|
|
title: {
|
|
text: 'Number of Failures'
|
|
}
|
|
},
|
|
yaxis: {
|
|
labels: {
|
|
show: false // Nascondiamo le etichette dell'asse Y
|
|
},
|
|
title: {
|
|
text: 'Analytes'
|
|
}
|
|
},
|
|
colors: ['#ffa515'], // Rosso per i Fail
|
|
title: {
|
|
text: 'Top 10 Analytes with the Most Failures',
|
|
align: 'center'
|
|
}
|
|
};
|
|
var chart = new ApexCharts(document.querySelector("#analytesFailChart"), options);
|
|
chart.render();
|
|
},
|
|
error: function() {
|
|
alert('Error retrieving data.');
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Eventi per applicare i filtri e il cambio di raggruppamento
|
|
$('#startDate, #endDate, #supplierFilter, #productsRefnumber, #productsSeason, #ageRange, #reportsLabName, #reportsTestType, #reportsNumberLab, #groupingField').on('change', function() {
|
|
updateData();
|
|
});
|
|
|
|
// Clear filters
|
|
$('#clearFilters').on('click', function() {
|
|
$('#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');
|
|
updateData();
|
|
// $('#activeFilters').hide();
|
|
});
|
|
|
|
// Chiamata iniziale per caricare i dati alla prima visualizzazione della pagina
|
|
updateData();
|
|
});
|
|
</script>
|
|
|
|
|
|
<script>
|
|
document.getElementById('totalProducts').innerText = <?php echo $totalProducts; ?>;
|
|
document.getElementById('totalReports').innerText = <?php echo $totalReports; ?>;
|
|
document.getElementById('failedReports').innerText = <?php echo $failedReports; ?>;
|
|
document.getElementById('failedReportsPercent').innerText = "(<?php echo number_format($failedReportsPercent, 2); ?>%)";
|
|
document.getElementById('totalTests').innerText = <?php echo $totalTests; ?>;
|
|
document.getElementById('failedTests').innerText = <?php echo $failedTests; ?>;
|
|
document.getElementById('failedTestsPercent').innerText = "(<?php echo number_format($failedTestsPercent, 2); ?>%)";
|
|
</script>
|
|
<script>
|
|
// for multiple select
|
|
$(document).ready(function() {
|
|
$('.select2').select2({
|
|
placeholder: "Select options",
|
|
allowClear: true,
|
|
width: '100%'
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<!-- plugin JS -->
|
|
<script src="../assets/js/popper.min.js"></script>
|
|
<script src="../assets/js/bootstrap.min.js"></script>
|
|
<script src="../assets/js/modernizr.min.js"></script>
|
|
<script src="../assets/js/detect.js"></script>
|
|
<script src="../assets/js/fastclick.js"></script>
|
|
<script src="../assets/js/jquery.slimscroll.js"></script>
|
|
<script src="../assets/js/jquery.blockUI.js"></script>
|
|
<script src="../assets/js/waves.js"></script>
|
|
<script src="../assets/js/jquery.nicescroll.js"></script>
|
|
<script src="../assets/js/jquery.scrollTo.min.js"></script>
|
|
<script src="../assets/js/common_helper.js"></script>
|
|
|
|
<script src="../assets/plugins/chart.js/chart.min.js"></script>
|
|
<script src="../assets/pages/dashboard.js"></script>
|
|
|
|
<!-- App js -->
|
|
<script src="../assets/js/app.js"></script>
|
|
<script src="../assets/plugins/alertify/js/alertify.js"></script>
|
|
|
|
|
|
</body>
|
|
|
|
</html>
|