user profile
This commit is contained in:
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
include('include/headscript.php');
|
||||
|
||||
$db = DBHandlerSelect::getInstance();
|
||||
$pdo = $db->getConnection();
|
||||
|
||||
/* ==========================================
|
||||
PAGE DATA
|
||||
========================================== */
|
||||
$sql = "
|
||||
SELECT jr.*,
|
||||
(SELECT COUNT(*) FROM employees e WHERE e.job_role_id = jr.id) AS employees_count
|
||||
FROM job_roles jr
|
||||
ORDER BY jr.sort_order ASC, jr.name ASC
|
||||
";
|
||||
$jobRoles = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
<!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>Gestione Mansioni - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.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: 1.05rem; background: #f8fafc; }
|
||||
.card { border-radius: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); }
|
||||
.back-dashboard {
|
||||
background-color: #cfe3ff !important; color: #1f2d3d !important;
|
||||
border: 1px solid #bcd4f4 !important; border-radius: 10px;
|
||||
font-weight: 600; padding: 10px 18px;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
.back-dashboard:hover { background-color: #b9d3ff !important; transform: translateY(-2px); }
|
||||
.btn-add { background-color: #0d6efd; color: #fff; border-radius: 8px; padding: 10px 20px; font-weight: 500; }
|
||||
.btn-add:hover { background-color: #0b5ed7; transform: scale(1.02); }
|
||||
.table thead { background-color: #cfe3ff; color: #1f2d3d; }
|
||||
.modal-content { border-radius: 16px; }
|
||||
#tabellaJobRoles thead th { text-align: center; vertical-align: middle; }
|
||||
.badge-status { padding: 0.25rem 0.6rem; border-radius: 999px; font-size: 0.8rem; font-weight: 600; }
|
||||
.badge-status.active { background-color: #d1fae5; color: #065f46; }
|
||||
.badge-status.inactive { background-color: #e5e7eb; color: #374151; }
|
||||
.description-cell {
|
||||
max-width: 320px; white-space: nowrap; overflow: hidden;
|
||||
text-overflow: ellipsis; text-align: left;
|
||||
}
|
||||
@media (max-width: 767.98px) {
|
||||
.card-header { flex-direction: column; align-items: flex-start !important; gap: .5rem; }
|
||||
.back-dashboard { width: 100%; }
|
||||
.btn-add { width: 100%; }
|
||||
}
|
||||
|
||||
.jr-card {
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 14px;
|
||||
padding: 14px 16px;
|
||||
margin-bottom: 12px;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
.jr-card-title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
margin: 0 0 4px 0;
|
||||
word-break: break-word;
|
||||
}
|
||||
.jr-card-desc {
|
||||
color: #475569;
|
||||
font-size: 0.95rem;
|
||||
margin: 0 0 10px 0;
|
||||
word-break: break-word;
|
||||
}
|
||||
.jr-card-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 14px;
|
||||
font-size: 0.85rem;
|
||||
color: #64748b;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.jr-card-meta b { color: #1f2937; font-weight: 600; }
|
||||
.jr-card-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.jr-card-actions .btn {
|
||||
flex: 1;
|
||||
}
|
||||
.jr-empty {
|
||||
text-align: center;
|
||||
color: #94a3b8;
|
||||
padding: 24px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrapper" id="appWrapper">
|
||||
<?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 flex-wrap gap-2">
|
||||
<h5 class="mb-0">Gestione Mansioni</h5>
|
||||
<button type="button" class="btn back-dashboard" onclick="location.href='production_dashboard.php'">
|
||||
↩️ Torna alla Dashboard
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||
<h6 class="fw-semibold mb-0">Elenco Mansioni / Job Roles</h6>
|
||||
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addJobRoleModal">
|
||||
➕ Aggiungi Mansione
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- DESKTOP / TABLET ≥768px: TABLE -->
|
||||
<div class="table-responsive d-none d-md-block"><!-- hide on <md -->
|
||||
<table id="tabellaJobRoles" class="table table-striped align-middle text-center" style="width:100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nome</th>
|
||||
<th>Descrizione</th>
|
||||
<th>Ordine</th>
|
||||
<th>Stato</th>
|
||||
<th>Dipendenti</th>
|
||||
<th>Creato</th>
|
||||
<th>Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($jobRoles as $row): ?>
|
||||
<?php
|
||||
$id = (int)$row['id'];
|
||||
$name = $row['name'] ?? '';
|
||||
$description = $row['description'] ?? '';
|
||||
$sortOrder = (int)($row['sort_order'] ?? 999);
|
||||
$isActive = (int)($row['is_active'] ?? 1);
|
||||
$cnt = (int)($row['employees_count'] ?? 0);
|
||||
$statusClass = $isActive === 1 ? 'active' : 'inactive';
|
||||
$statusLabel = $isActive === 1 ? 'Attivo' : 'Inattivo';
|
||||
$createdAt = !empty($row['created_at'])
|
||||
? date('d/m/Y H:i', strtotime($row['created_at']))
|
||||
: '-';
|
||||
?>
|
||||
<tr>
|
||||
<td><?= $id ?></td>
|
||||
<td class="fw-semibold text-start"><?= htmlspecialchars($name) ?></td>
|
||||
<td class="description-cell" title="<?= htmlspecialchars($description, ENT_QUOTES) ?>">
|
||||
<?= $description !== '' ? htmlspecialchars($description) : '-' ?>
|
||||
</td>
|
||||
<td><?= $sortOrder ?></td>
|
||||
<td>
|
||||
<span class="badge-status <?= $statusClass ?>"><?= $statusLabel ?></span>
|
||||
</td>
|
||||
<td><?= $cnt ?></td>
|
||||
<td><?= $createdAt ?></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-secondary edit-job-role"
|
||||
data-id="<?= $id ?>"
|
||||
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
|
||||
data-description="<?= htmlspecialchars($description, ENT_QUOTES) ?>"
|
||||
data-sort_order="<?= $sortOrder ?>"
|
||||
data-is_active="<?= $isActive ?>">
|
||||
✏️ Modifica
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger delete-job-role"
|
||||
data-id="<?= $id ?>"
|
||||
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
|
||||
data-count="<?= $cnt ?>">
|
||||
🗑️ Cancella
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- MOBILE <768px: CARDS -->
|
||||
<div class="d-block d-md-none">
|
||||
<?php if (empty($jobRoles)): ?>
|
||||
<div class="jr-empty">Nessuna mansione presente</div>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($jobRoles as $row): ?>
|
||||
<?php
|
||||
$id = (int)$row['id'];
|
||||
$name = $row['name'] ?? '';
|
||||
$description = $row['description'] ?? '';
|
||||
$sortOrder = (int)($row['sort_order'] ?? 999);
|
||||
$isActive = (int)($row['is_active'] ?? 1);
|
||||
$cnt = (int)($row['employees_count'] ?? 0);
|
||||
$statusClass = $isActive === 1 ? 'active' : 'inactive';
|
||||
$statusLabel = $isActive === 1 ? 'Attivo' : 'Inattivo';
|
||||
?>
|
||||
<div class="jr-card">
|
||||
<h6 class="jr-card-title"><?= htmlspecialchars($name) ?></h6>
|
||||
<?php if ($description !== ''): ?>
|
||||
<p class="jr-card-desc"><?= htmlspecialchars($description) ?></p>
|
||||
<?php endif; ?>
|
||||
<div class="jr-card-meta">
|
||||
<span><span class="badge-status <?= $statusClass ?>"><?= $statusLabel ?></span></span>
|
||||
<span><b>Dipendenti:</b> <?= $cnt ?></span>
|
||||
<span><b>Ordine:</b> <?= $sortOrder ?></span>
|
||||
</div>
|
||||
<div class="jr-card-actions">
|
||||
<button class="btn btn-sm btn-outline-secondary edit-job-role"
|
||||
data-id="<?= $id ?>"
|
||||
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
|
||||
data-description="<?= htmlspecialchars($description, ENT_QUOTES) ?>"
|
||||
data-sort_order="<?= $sortOrder ?>"
|
||||
data-is_active="<?= $isActive ?>">
|
||||
✏️ Modifica
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger delete-job-role"
|
||||
data-id="<?= $id ?>"
|
||||
data-name="<?= htmlspecialchars($name, ENT_QUOTES) ?>"
|
||||
data-count="<?= $cnt ?>">
|
||||
🗑️ Cancella
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('include/footer.php'); ?>
|
||||
</div>
|
||||
|
||||
<!-- ADD MODAL -->
|
||||
<div class="modal fade" id="addJobRoleModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-fullscreen-sm-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background-color:#cfe3ff;">
|
||||
<h5 class="modal-title">Aggiungi Mansione</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addJobRoleForm">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Nome</label>
|
||||
<input type="text" class="form-control" id="addName" name="name" placeholder="es. Saldatore" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Descrizione</label>
|
||||
<textarea class="form-control" id="addDescription" name="description" rows="3" placeholder="Opzionale"></textarea>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label class="form-label fw-semibold">Ordine</label>
|
||||
<input type="number" class="form-control" id="addSortOrder" name="sort_order" value="999" min="0">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label class="form-label fw-semibold">Stato</label>
|
||||
<select class="form-select" id="addIsActive" name="is_active">
|
||||
<option value="1" selected>Attivo</option>
|
||||
<option value="0">Inattivo</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-add">💾 Salva</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- EDIT MODAL -->
|
||||
<div class="modal fade" id="editJobRoleModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered modal-fullscreen-sm-down">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="background-color:#cfe3ff;">
|
||||
<h5 class="modal-title">Modifica Mansione</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editJobRoleForm">
|
||||
<input type="hidden" id="editJobRoleId">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Nome</label>
|
||||
<input type="text" class="form-control" id="editName" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold">Descrizione</label>
|
||||
<textarea class="form-control" id="editDescription" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label class="form-label fw-semibold">Ordine</label>
|
||||
<input type="number" class="form-control" id="editSortOrder" name="sort_order" value="999" min="0">
|
||||
</div>
|
||||
<div class="col-12 col-md-6 mb-3">
|
||||
<label class="form-label fw-semibold">Stato</label>
|
||||
<select class="form-select" id="editIsActive" name="is_active">
|
||||
<option value="1">Attivo</option>
|
||||
<option value="0">Inattivo</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-add">💾 Salva Modifiche</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include('jsinclude.php'); ?>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('#tabellaJobRoles').DataTable({
|
||||
order: [[3, 'asc'], [1, 'asc']],
|
||||
pageLength: 25,
|
||||
language: {
|
||||
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json',
|
||||
emptyTable: 'Nessuna mansione presente'
|
||||
}
|
||||
});
|
||||
|
||||
function ajaxPost(url, payload, successTitle, errorFallback) {
|
||||
return fetch(url, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
body: payload.toString()
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
Swal.fire({ icon: "success", title: successTitle, confirmButtonColor: "#3085d6" })
|
||||
.then(() => location.reload());
|
||||
} else {
|
||||
Swal.fire({ icon: "error", title: "Errore", text: data.message || errorFallback });
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
Swal.fire({ icon: "error", title: "Errore", text: "Errore di comunicazione." });
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
$("#addJobRoleForm").on("submit", function(e) {
|
||||
e.preventDefault();
|
||||
const p = new URLSearchParams();
|
||||
p.append('name', $("#addName").val().trim());
|
||||
p.append('description', $("#addDescription").val().trim());
|
||||
p.append('sort_order', $("#addSortOrder").val());
|
||||
p.append('is_active', $("#addIsActive").val());
|
||||
ajaxPost("ajax/job_roles/save.php", p, "Salvato!", "Impossibile salvare la mansione.");
|
||||
});
|
||||
|
||||
$(document).on("click", ".edit-job-role", function() {
|
||||
const b = $(this);
|
||||
$("#editJobRoleId").val(b.data("id"));
|
||||
$("#editName").val(b.data("name"));
|
||||
$("#editDescription").val(b.data("description"));
|
||||
$("#editSortOrder").val(b.data("sort_order"));
|
||||
$("#editIsActive").val(String(b.data("is_active")));
|
||||
$("#editJobRoleModal").modal("show");
|
||||
});
|
||||
|
||||
$("#editJobRoleForm").on("submit", function(e) {
|
||||
e.preventDefault();
|
||||
const p = new URLSearchParams();
|
||||
p.append('id', $("#editJobRoleId").val());
|
||||
p.append('name', $("#editName").val().trim());
|
||||
p.append('description', $("#editDescription").val().trim());
|
||||
p.append('sort_order', $("#editSortOrder").val());
|
||||
p.append('is_active', $("#editIsActive").val());
|
||||
ajaxPost("ajax/job_roles/save.php", p, "Aggiornato!", "Impossibile aggiornare la mansione.");
|
||||
});
|
||||
|
||||
$(document).on("click", ".delete-job-role", function() {
|
||||
const id = $(this).data("id");
|
||||
const name = $(this).data("name");
|
||||
const cnt = parseInt($(this).data("count")) || 0;
|
||||
|
||||
if (cnt > 0) {
|
||||
Swal.fire({
|
||||
icon: "warning",
|
||||
title: "Impossibile cancellare",
|
||||
text: "La mansione \"" + name + "\" è assegnata a " + cnt + " dipendente/i. Rimuovi prima l'associazione."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Swal.fire({
|
||||
title: "Confermi la cancellazione?",
|
||||
text: name ? ("Mansione: " + name) : "La mansione verrà cancellata.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#d33",
|
||||
cancelButtonColor: "#6c757d",
|
||||
confirmButtonText: "Sì, cancella",
|
||||
cancelButtonText: "Annulla"
|
||||
}).then((result) => {
|
||||
if (!result.isConfirmed) return;
|
||||
const p = new URLSearchParams();
|
||||
p.append('id', id);
|
||||
ajaxPost("ajax/job_roles/delete.php", p, "Cancellato!", "Impossibile cancellare la mansione.");
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user