659 lines
20 KiB
PHP
659 lines
20 KiB
PHP
<?php include('include/headscript.php'); ?>
|
|
<?php
|
|
/**
|
|
* Check if current user has a Vanguard permission.
|
|
* Uses Vanguard native method if available, otherwise falls back to DB check.
|
|
*/
|
|
function userCan($permissionName)
|
|
{
|
|
global $kindofrole;
|
|
|
|
$user = Auth::user();
|
|
|
|
// Vanguard / Laravel-style methods, depending on installed version/customization.
|
|
if (method_exists($user, 'hasPermission')) {
|
|
return $user->hasPermission($permissionName);
|
|
}
|
|
|
|
if (method_exists($user, 'hasPermissionTo')) {
|
|
return $user->hasPermissionTo($permissionName);
|
|
}
|
|
|
|
if (method_exists($user, 'can')) {
|
|
return $user->can($permissionName);
|
|
}
|
|
|
|
// Fallback: direct DB check using existing Vanguard tables.
|
|
static $permissions = null;
|
|
|
|
if ($permissions === null) {
|
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
|
|
|
$stmt = $pdo->prepare("
|
|
SELECT p.name
|
|
FROM auth_permissions p
|
|
INNER JOIN auth_permission_role pr ON pr.permission_id = p.id
|
|
WHERE pr.role_id = ?
|
|
");
|
|
$stmt->execute([(int)$kindofrole]);
|
|
|
|
$permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
}
|
|
|
|
return in_array($permissionName, $permissions, true);
|
|
}
|
|
|
|
/**
|
|
* Filter visible buttons.
|
|
*/
|
|
function visibleButtons(array $buttons)
|
|
{
|
|
return array_values(array_filter($buttons, function ($button) {
|
|
return empty($button['permission']) || userCan($button['permission']);
|
|
}));
|
|
}
|
|
?>
|
|
<?php
|
|
$dashboardSections = [
|
|
[
|
|
'id' => 'secOperativo',
|
|
'title' => 'Operativo',
|
|
'subtitle' => 'Azioni principali di produzione e attività in scadenza',
|
|
'icon' => '🚀',
|
|
'open' => true,
|
|
'buttons' => [
|
|
[
|
|
'label' => 'Programmazione',
|
|
'icon' => '🗓️',
|
|
'class' => 'btn-programmazione',
|
|
'url' => 'produzione_programmazione_drag.php',
|
|
'permission' => 'production.programming.view',
|
|
],
|
|
[
|
|
'label' => 'Line View',
|
|
'icon' => '⚙️',
|
|
'class' => 'btn-status',
|
|
'url' => 'production_line_view2.php',
|
|
'permission' => 'production.line_view.view',
|
|
],
|
|
[
|
|
'label' => 'Statistiche',
|
|
'icon' => '📈',
|
|
'class' => 'btn-statistiche',
|
|
'url' => 'production_stats.php',
|
|
'permission' => 'production.stats.view',
|
|
],
|
|
[
|
|
'label' => 'Manager',
|
|
'icon' => '👔',
|
|
'class' => 'btn-manager',
|
|
'url' => 'manager_produzione.php',
|
|
'permission' => 'production.manager.view',
|
|
],
|
|
[
|
|
'label' => 'Manager Stats',
|
|
'icon' => '📊',
|
|
'class' => 'btn-manager-stats',
|
|
'url' => 'manager_stats.php',
|
|
'permission' => 'production.manager_stats.view',
|
|
],
|
|
[
|
|
'label' => 'Magazzino',
|
|
'icon' => '📦',
|
|
'class' => 'btn-magazzino',
|
|
'url' => 'warehouse_dashboard.php',
|
|
'permission' => 'warehouse.dashboard.view',
|
|
],
|
|
[
|
|
'label' => 'Scadenziario',
|
|
'icon' => '⏰',
|
|
'class' => 'btn-scadenziario',
|
|
'url' => 'scadenzario/index.php',
|
|
'permission' => 'deadlines.view',
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'id' => 'secAnagrafiche',
|
|
'title' => 'Anagrafiche',
|
|
'subtitle' => 'Dati di base e setup di produzione',
|
|
'icon' => '🗂️',
|
|
'open' => false,
|
|
'buttons' => [
|
|
[
|
|
'label' => 'Mescole',
|
|
'icon' => '⚗️',
|
|
'class' => 'btn-mescole',
|
|
'url' => 'mescole.php',
|
|
'permission' => 'masterdata.mescole.view',
|
|
],
|
|
[
|
|
'label' => 'Elenco Profili',
|
|
'icon' => '🧩',
|
|
'class' => 'btn-matrici',
|
|
'url' => 'matrici.php',
|
|
'permission' => 'masterdata.matrici.view',
|
|
],
|
|
[
|
|
'label' => 'Linee Produzione',
|
|
'icon' => '🏭',
|
|
'class' => 'btn-linee',
|
|
'url' => 'linee.php',
|
|
'permission' => 'masterdata.linee.view',
|
|
],
|
|
[
|
|
'label' => 'Imballaggi',
|
|
'icon' => '📦',
|
|
'class' => 'btn-setup',
|
|
'url' => 'packaging_items.php',
|
|
'permission' => 'masterdata.packaging.view',
|
|
],
|
|
[
|
|
'label' => 'Suppliers',
|
|
'icon' => '🏷️',
|
|
'class' => 'btn-setup',
|
|
'url' => 'suppliers.php',
|
|
'permission' => 'masterdata.suppliers.view',
|
|
],
|
|
[
|
|
'label' => 'Setup',
|
|
'icon' => '⚙️',
|
|
'class' => 'btn-setup',
|
|
'url' => 'lookup_values.php',
|
|
'permission' => 'masterdata.lookup.view',
|
|
],
|
|
[
|
|
'label' => 'Fogli di lavoro',
|
|
'icon' => '🗒️',
|
|
'class' => 'btn-setup',
|
|
'url' => 'worksheets.php',
|
|
'permission' => 'masterdata.worksheets.view',
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'id' => 'secServizi',
|
|
'title' => 'Servizi',
|
|
'subtitle' => 'Status, cause pausa, attrezzature',
|
|
'icon' => '🧰',
|
|
'open' => false,
|
|
'buttons' => [
|
|
[
|
|
'label' => 'Status',
|
|
'icon' => '📋',
|
|
'class' => 'btn-setup',
|
|
'url' => 'production_status.php',
|
|
'permission' => 'services.status.view',
|
|
],
|
|
[
|
|
'label' => 'Cause di Pausa',
|
|
'icon' => '🛑',
|
|
'class' => 'btn-problem',
|
|
'url' => 'production_pause_reasons.php',
|
|
'permission' => 'services.pause_reasons.view',
|
|
],
|
|
[
|
|
'label' => 'Attrezzature',
|
|
'icon' => '🛠️',
|
|
'class' => 'btn-tools',
|
|
'url' => 'production_tools.php',
|
|
'permission' => 'services.tools.view',
|
|
],
|
|
],
|
|
],
|
|
[
|
|
'id' => 'secPersonale',
|
|
'title' => 'Personale',
|
|
'subtitle' => 'Dipendenti, skill',
|
|
'icon' => '👥',
|
|
'open' => false,
|
|
'buttons' => [
|
|
[
|
|
'label' => 'Employees',
|
|
'icon' => '👥',
|
|
'class' => 'btn-employees',
|
|
'url' => 'employees.php',
|
|
'permission' => 'hr.employees.view',
|
|
],
|
|
[
|
|
'label' => 'Departments',
|
|
'icon' => '🏢',
|
|
'class' => 'btn-departments',
|
|
'url' => 'departments.php',
|
|
'permission' => 'hr.departments.view',
|
|
],
|
|
[
|
|
'label' => 'Skills',
|
|
'icon' => '🧠',
|
|
'class' => 'btn-setup',
|
|
'url' => 'skills.php',
|
|
'permission' => 'hr.skills.view',
|
|
],
|
|
],
|
|
],
|
|
];
|
|
?>
|
|
<!doctype html>
|
|
<html lang="it">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="icon" href="assets/images/favicon-32x32.png" type="image/png" />
|
|
<?php include('cssinclude.php'); ?>
|
|
<title>Dashboard Produzione - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
|
|
|
<!-- Bootstrap + jQuery -->
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
|
|
<style>
|
|
body {
|
|
background: linear-gradient(135deg, #f3f6f8, #e8eef3);
|
|
font-family: 'Segoe UI', sans-serif;
|
|
color: #2b3e50;
|
|
}
|
|
|
|
.page-content {
|
|
padding: 1.4rem 1rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
h3.dashboard-title {
|
|
text-align: center;
|
|
font-weight: 800;
|
|
color: #2b3e50;
|
|
margin-bottom: 1.2rem;
|
|
letter-spacing: 0.3px;
|
|
}
|
|
|
|
/* ===== STATISTICHE ===== */
|
|
.stats-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 14px;
|
|
margin-bottom: 16px;
|
|
width: 100%;
|
|
max-width: 980px;
|
|
}
|
|
|
|
.stat-card {
|
|
flex: 1 1 240px;
|
|
background: #fff;
|
|
border-radius: 16px;
|
|
padding: 18px 20px;
|
|
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
|
|
text-align: center;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.13);
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 1.8rem;
|
|
font-weight: 800;
|
|
color: #2b3e50;
|
|
line-height: 1.15;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.98rem;
|
|
font-weight: 600;
|
|
color: #6b7a89;
|
|
}
|
|
|
|
.stat-prod {
|
|
background: linear-gradient(135deg, #cde5ff, #dff0ff);
|
|
}
|
|
|
|
.stat-mese {
|
|
background: linear-gradient(135deg, #d2f7d9, #e7ffea);
|
|
}
|
|
|
|
.stat-scarti {
|
|
background: linear-gradient(135deg, #ffe7cc, #fff3df);
|
|
}
|
|
|
|
/* ===== SEZIONI COLLASSABILI ===== */
|
|
.sections-wrap {
|
|
width: 100%;
|
|
max-width: 980px;
|
|
}
|
|
|
|
.section-card {
|
|
background: #fff;
|
|
border-radius: 16px;
|
|
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
|
|
margin-bottom: 14px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.section-header {
|
|
width: 100%;
|
|
border: 0;
|
|
background: transparent;
|
|
padding: 14px 16px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
text-align: left;
|
|
}
|
|
|
|
.section-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.section-icon {
|
|
font-size: 1.6rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.section-title {
|
|
font-weight: 800;
|
|
font-size: 1.05rem;
|
|
margin: 0;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.section-subtitle {
|
|
font-size: 0.9rem;
|
|
color: #6b7a89;
|
|
margin: 0;
|
|
}
|
|
|
|
.chev {
|
|
font-size: 1.25rem;
|
|
transition: transform 0.18s ease;
|
|
}
|
|
|
|
.section-header[aria-expanded="true"] .chev {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.section-body {
|
|
padding: 14px 16px 16px 16px;
|
|
border-top: 1px solid rgba(0, 0, 0, 0.06);
|
|
}
|
|
|
|
/* ===== BOTTONI ===== */
|
|
.dashboard-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(200px, 1fr));
|
|
gap: 14px 16px;
|
|
width: 100%;
|
|
}
|
|
|
|
.dash-btn {
|
|
width: 100%;
|
|
border: none;
|
|
border-radius: 16px;
|
|
padding: 16px 10px;
|
|
color: #2b3e50;
|
|
font-size: 1.15rem;
|
|
font-weight: 700;
|
|
background: #fff;
|
|
transition: all 0.2s ease;
|
|
box-shadow: 0 5px 12px rgba(0, 0, 0, 0.08);
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 108px;
|
|
}
|
|
|
|
.dash-btn:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.13);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dash-icon {
|
|
font-size: 2.6rem;
|
|
margin-bottom: 6px;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* Pastel colors */
|
|
.btn-programmazione {
|
|
background: linear-gradient(135deg, #7c7afaff, #7c7afaff);
|
|
color: #fff;
|
|
}
|
|
|
|
.btn-status {
|
|
background: linear-gradient(135deg, #61ce5dff, #61ce5dff);
|
|
color: #fff;
|
|
}
|
|
|
|
.btn-scadenziario {
|
|
background: linear-gradient(135deg, #ffb86b, #ffd59a);
|
|
color: #2b3e50;
|
|
}
|
|
|
|
.btn-statistiche {
|
|
background: linear-gradient(135deg, #ffe0a3ff, #fff1c1ff);
|
|
}
|
|
|
|
.btn-manager {
|
|
background: linear-gradient(135deg, #cde5ff, #dff0ff);
|
|
}
|
|
|
|
.btn-manager-stats {
|
|
background: linear-gradient(135deg, #d2f7d9, #e7ffea);
|
|
}
|
|
|
|
.btn-magazzino {
|
|
background: linear-gradient(135deg, #b9e3ffff, #d7f1ffff);
|
|
}
|
|
|
|
.btn-mescole {
|
|
background: linear-gradient(135deg, #ffc853ff, #fdd98bff);
|
|
}
|
|
|
|
.btn-matrici {
|
|
background: linear-gradient(135deg, #ff8585ff, #ff9d9dff);
|
|
}
|
|
|
|
.btn-linee {
|
|
background: linear-gradient(135deg, #b9e3ffff, #d7f1ffff);
|
|
}
|
|
|
|
.btn-problem {
|
|
background-color: #ef4444 !important;
|
|
color: #ffffff !important;
|
|
border-radius: 16px;
|
|
}
|
|
|
|
.btn-problem:hover {
|
|
background-color: #dc2626 !important;
|
|
}
|
|
|
|
.btn-tools {
|
|
background: linear-gradient(135deg, #9f7aea, #b794f4);
|
|
color: #fff;
|
|
}
|
|
|
|
.btn-employees {
|
|
background: linear-gradient(135deg, #a5b4fc, #c7d2fe);
|
|
}
|
|
|
|
.btn-departments {
|
|
background: linear-gradient(135deg, #bfdbfe, #dbeafe);
|
|
color: #1f2d3d;
|
|
}
|
|
|
|
.btn-departments:hover {
|
|
background: linear-gradient(135deg, #93c5fd, #bfdbfe);
|
|
}
|
|
|
|
.btn-setup {
|
|
background: linear-gradient(135deg, #e5e7eb, #f3f4f6);
|
|
}
|
|
|
|
/* Tablet/mobile */
|
|
@media (max-width: 992px) {
|
|
.dashboard-grid {
|
|
grid-template-columns: repeat(2, minmax(180px, 1fr));
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.stats-row {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
.dashboard-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.dash-btn {
|
|
font-size: 1.12rem;
|
|
min-height: 98px;
|
|
}
|
|
|
|
.dash-icon {
|
|
font-size: 2.4rem;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="wrapper toggled">
|
|
<?php include('include/navbar.php'); ?>
|
|
<?php include('include/topbar.php'); ?>
|
|
|
|
<div class="page-wrapper">
|
|
<div class="page-content">
|
|
|
|
<?php
|
|
$pdo = DBHandlerSelect::getInstance()->getConnection();
|
|
include(__DIR__ . '/scadenzario/include/my_deadlines_widget.php');
|
|
?>
|
|
|
|
<h3 class="dashboard-title">Dashboard Produzione</h3>
|
|
|
|
<!-- ===== STATISTICHE PRINCIPALI ===== -->
|
|
<div class="stats-row">
|
|
<?php
|
|
$db = DBHandlerSelect::getInstance();
|
|
$pdo = $db->getConnection();
|
|
|
|
$stmt = $pdo->query("SELECT SUM(kgprod) AS totale_oggi FROM productiondata WHERE DATE(Data) = CURDATE()");
|
|
$totOggi = number_format($stmt->fetchColumn() ?? 0, 2, ',', '.');
|
|
|
|
$stmt = $pdo->query("SELECT SUM(kgprod) AS totale_mese FROM productiondata WHERE MONTH(Data) = MONTH(CURDATE()) AND YEAR(Data) = YEAR(CURDATE())");
|
|
$totMese = number_format($stmt->fetchColumn() ?? 0, 2, ',', '.');
|
|
|
|
$stmt = $pdo->query("SELECT (SUM(scarto)/NULLIF(SUM(kgprod),0))*100 AS perc_scarto FROM productiondata WHERE MONTH(Data) = MONTH(CURDATE()) AND YEAR(Data) = YEAR(CURDATE())");
|
|
$percScarto = number_format($stmt->fetchColumn() ?? 0, 2, ',', '.');
|
|
?>
|
|
|
|
<div class="stat-card stat-prod">
|
|
<div class="stat-value"><?= $totOggi ?> kg</div>
|
|
<div class="stat-label">Produzione odierna</div>
|
|
</div>
|
|
|
|
<div class="stat-card stat-mese">
|
|
<div class="stat-value"><?= $totMese ?> kg</div>
|
|
<div class="stat-label">Produzione mese corrente</div>
|
|
</div>
|
|
|
|
<div class="stat-card stat-scarti">
|
|
<div class="stat-value"><?= $percScarto ?>%</div>
|
|
<div class="stat-label">Scarto medio mensile</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ===== SEZIONI COLLASSABILI ===== -->
|
|
<div class="sections-wrap" id="prodAccordion">
|
|
|
|
<?php
|
|
$hasVisibleSections = false;
|
|
|
|
foreach ($dashboardSections as $section):
|
|
$buttons = visibleButtons($section['buttons']);
|
|
|
|
// If no visible buttons are available, do not show the section.
|
|
if (empty($buttons)) {
|
|
continue;
|
|
}
|
|
|
|
$hasVisibleSections = true;
|
|
|
|
$sectionId = htmlspecialchars($section['id'], ENT_QUOTES, 'UTF-8');
|
|
$isOpen = !empty($section['open']);
|
|
?>
|
|
|
|
<div class="section-card">
|
|
<button type="button"
|
|
class="section-header"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#<?= $sectionId ?>"
|
|
aria-expanded="<?= $isOpen ? 'true' : 'false' ?>"
|
|
aria-controls="<?= $sectionId ?>">
|
|
<div class="section-left">
|
|
<div class="section-icon"><?= htmlspecialchars($section['icon'], ENT_QUOTES, 'UTF-8') ?></div>
|
|
<div style="min-width:0;">
|
|
<p class="section-title"><?= htmlspecialchars($section['title'], ENT_QUOTES, 'UTF-8') ?></p>
|
|
<p class="section-subtitle"><?= htmlspecialchars($section['subtitle'], ENT_QUOTES, 'UTF-8') ?></p>
|
|
</div>
|
|
</div>
|
|
<div class="chev">⌄</div>
|
|
</button>
|
|
|
|
<div id="<?= $sectionId ?>"
|
|
class="collapse <?= $isOpen ? 'show' : '' ?>"
|
|
data-bs-parent="#prodAccordion">
|
|
<div class="section-body">
|
|
<div class="dashboard-grid">
|
|
|
|
<?php foreach ($buttons as $button): ?>
|
|
<button class="dash-btn <?= htmlspecialchars($button['class'], ENT_QUOTES, 'UTF-8') ?>"
|
|
onclick="location.href='<?= htmlspecialchars($button['url'], ENT_QUOTES, 'UTF-8') ?>'">
|
|
<div class="dash-icon"><?= htmlspecialchars($button['icon'], ENT_QUOTES, 'UTF-8') ?></div>
|
|
<div><?= htmlspecialchars($button['label'], ENT_QUOTES, 'UTF-8') ?></div>
|
|
</button>
|
|
<?php endforeach; ?>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php endforeach; ?>
|
|
|
|
<?php if (!$hasVisibleSections): ?>
|
|
<div class="section-card">
|
|
<div class="section-body text-center">
|
|
Nessuna sezione disponibile per il tuo profilo.
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
<!-- /sections-wrap -->
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<?php include('jsinclude.php'); ?>
|
|
<?php include('include/footer.php'); ?>
|
|
</div>
|
|
|
|
</body>
|
|
|
|
</html>
|