zibo-dashboard/public/userarea/skill_matrix.php
2026-02-02 17:25:47 +01:00

393 lines
15 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
ini_set('display_errors', 1);
error_reporting(E_ALL);
include('include/headscript.php');
$db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection();
// AJAX salvataggio singolo (ora gestisce anche testo libero)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
header('Content-Type: application/json');
if ($_POST['action'] === 'save_single_skill') {
$employee_id = (int)($_POST['employee_id'] ?? 0);
$skill_id = (int)($_POST['skill_id'] ?? 0);
$level = trim($_POST['level'] ?? '');
try {
$pdo->prepare("DELETE FROM employee_skills WHERE employee_id = ? AND skill_id = ?")
->execute([$employee_id, $skill_id]);
// Salva solo se c'è valore (non vuoto)
if ($level !== '') {
$pdo->prepare("INSERT INTO employee_skills (employee_id, skill_id, level) VALUES (?, ?, ?)")
->execute([$employee_id, $skill_id, $level]);
}
echo json_encode(['success' => true]);
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
exit;
}
echo json_encode(['success' => false, 'message' => 'Azione non valida']);
exit;
}
// DATI
$employees = $pdo->query("
SELECT id, CONCAT(first_name, ' ', last_name) AS nome
FROM employees
ORDER BY id
")->fetchAll(PDO::FETCH_ASSOC);
$skills = $pdo->query("
SELECT
s.id,
s.name AS nome_completo,
COALESCE(s.abbreviato, SUBSTRING(s.name, 1, 12)) AS acronimo,
pl.line_number,
pl.name AS linea
FROM skills s
LEFT JOIN production_lines pl ON s.production_line_id = pl.id
ORDER BY s.ordinamento ASC, COALESCE(pl.line_number, 999), s.id
")->fetchAll(PDO::FETCH_ASSOC);
$livelli = [];
$stmt = $pdo->query("SELECT employee_id, skill_id, level FROM employee_skills");
while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
$livelli[$r['employee_id']][$r['skill_id']] = $r['level'];
}
?>
<!doctype html>
<html lang="it">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<?php include('cssinclude.php'); ?>
<title>Matrice Skills</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css">
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
<style>
body {
font-size: 0.95rem;
background: #f8fafc;
}
.card {
border-radius: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.back-btn {
background: #cfe3ff !important;
color: #1f2d3d !important;
border: 1px solid #bcd4f4 !important;
border-radius: 10px;
font-weight: 600;
padding: 8px 16px;
}
.table th,
.table td {
text-align: center;
vertical-align: middle;
padding: 6px 8px;
}
.table thead th {
background: #cfe3ff;
color: #1f2d3d;
white-space: nowrap;
}
.table thead th.group {
background: #a5d8ff;
font-weight: bold;
font-size: 1.05rem;
}
.fixed-name {
min-width: 220px !important;
max-width: 260px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-weight: 600;
background: #e9f3ff !important;
position: sticky;
left: 0;
z-index: 1;
}
.skill-col {
min-width: 60px;
}
.skill-header {
font-size: 0.72rem !important;
line-height: 1.0;
padding: 4px 6px !important;
}
.table select,
.table input[type="text"] {
width: 100%;
font-size: 0.85rem;
padding: 4px 6px;
text-align: center;
border-radius: 4px;
border: 1px solid #ccc;
}
.table input[type="text"] {
background: #fffacd;
/* giallo chiaro per distinguere il campo testo */
}
/* COLORI LIVELLI (solo per select) */
.level-Q {
background: #d4edda;
color: #155724;
font-weight: 600;
}
.level-CQ {
background: #fff3cd;
color: #856404;
}
.level-C {
background: #ffeeba;
color: #856404;
}
.level-DF {
background: #f8d7da;
color: #721c24;
}
.level-si {
background: #28a745;
color: white;
font-weight: bold;
}
.level-no {
background: #dc3545;
color: white;
}
.level-NON-RICH {
background: #e9ecef;
color: #6c757d;
}
.table-responsive {
overflow-x: auto;
}
</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">
<div class="card p-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Matrice Skills</h5>
<button class="btn back-btn" onclick="location.href='employees.php'">↩️ Dipendenti</button>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table id="matrix" class="table table-bordered table-sm">
<thead>
<tr>
<th rowspan="2" class="fixed-name" style="background:#cfe3ff;">Dipendente</th>
<th colspan="2" class="group text-center" style="background:#fff;"></th>
<th colspan="2" class="group text-center">UHF</th>
<th colspan="2" class="group text-center">BSF</th>
<th colspan="2" class="group text-center">Gerlach</th>
</tr>
<tr>
<?php foreach ($skills as $s): ?>
<th class="skill-col skill-header"
title="<?= htmlspecialchars($s['nome_completo']) ?>">
<?= htmlspecialchars($s['acronimo']) ?>
</th>
<?php endforeach; ?>
</tr>
</thead>
<tbody>
<?php foreach ($employees as $emp): ?>
<tr>
<td class="fixed-name"><?= htmlspecialchars($emp['nome']) ?></td>
<?php foreach ($skills as $s):
$val = $livelli[$emp['id']][$s['id']] ?? '';
$cls = str_replace(['.', ' '], '-', $val);
?>
<td>
<?php if ($s['id'] == 29): ?>
<!-- Campo testo libero per id=29 -->
<input type="text"
class="form-control"
value="<?= htmlspecialchars($val) ?>"
onblur="salvaTesto(<?= $emp['id'] ?>, <?= $s['id'] ?>, this.value)">
<?php else: ?>
<!-- Tendina normale per tutte le altre -->
<select class="form-select level-<?= $cls ?>"
onchange="salva(<?= $emp['id'] ?>, <?= $s['id'] ?>, this.value, this)">
<?php if (strpos($s['nome_completo'], 'TURNO NOTTURNO') !== false): ?>
<option value="si" <?= $val === 'si' ? 'selected' : '' ?>>si</option>
<option value="no" <?= $val === 'no' ? 'selected' : '' ?>>no</option>
<?php else: ?>
<option value="DF" <?= $val === 'DF' ? 'selected' : '' ?>>DF</option>
<option value="C" <?= $val === 'C' ? 'selected' : '' ?>>C</option>
<option value="CQ" <?= $val === 'CQ' ? 'selected' : '' ?>>CQ</option>
<option value="Q" <?= $val === 'Q' ? 'selected' : '' ?>>Q</option>
<option value="NON RICH." <?= $val === 'NON RICH.' ? 'selected' : '' ?>></option>
<?php endif; ?>
</select>
<?php endif; ?>
</td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<script>
// Salvataggio per tendina (onchange)
function salva(empId, skillId, val, selectElement) {
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `ajax=1&action=save_single_skill&employee_id=${empId}&skill_id=${skillId}&level=${encodeURIComponent(val)}`
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'OK',
timer: 700,
showConfirmButton: false
});
// Aggiorna colore SOLO se selectElement è valido
if (selectElement && selectElement.tagName === 'SELECT') {
// Rimuovi tutte le classi level-*
selectElement.classList.forEach(c => {
if (c.startsWith('level-')) selectElement.classList.remove(c);
});
// Aggiungi la nuova classe level-*
const newCls = 'level-' + val.replace(/[\.\s]/g, '-');
selectElement.classList.add(newCls);
// (sicurezza) assicurati che resti form-select
selectElement.classList.add('form-select');
}
} else {
Swal.fire({
icon: 'error',
title: 'Errore server',
text: data.message || '?'
});
}
})
.catch(err => {
console.error('Fetch error:', err);
Swal.fire({
icon: 'error',
title: 'Errore rete o parsing',
text: err.message || 'Controlla console'
});
});
}
// Salvataggio per campo testo (onblur)
function salvaTesto(empId, skillId, val) {
val = val.trim();
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `ajax=1&action=save_single_skill&employee_id=${empId}&skill_id=${skillId}&level=${encodeURIComponent(val)}`
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Salvato',
timer: 700,
showConfirmButton: false
});
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message || '?'
});
}
})
.catch(() => Swal.fire({
icon: 'error',
title: 'Errore rete'
}));
}
$(document).ready(function() {
$('#matrix').DataTable({
scrollX: true,
scrollCollapse: true,
paging: false,
searching: false,
info: false,
ordering: false,
fixedColumns: {
left: 1
},
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
},
columnDefs: [{
targets: 0,
className: 'fixed-name'
}]
});
});
</script>
</body>
</html>