Files
zibo-dashboard/public/userarea/employees.php
T

1438 lines
68 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 HANDLERS (ADD / EDIT / DELETE / SKILLS)
========================================== */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
header('Content-Type: application/json');
$action = $_POST['action'] ?? '';
try {
if ($action === 'add') {
$employee_code = trim($_POST['employee_code'] ?? '');
$first_name = trim($_POST['first_name'] ?? '');
$last_name = trim($_POST['last_name'] ?? '');
$address = trim($_POST['address'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$email = trim($_POST['email'] ?? '');
$department_id = $_POST['department_id'] !== '' ? (int)$_POST['department_id'] : null;
$job_role_id = ($_POST['job_role_id'] ?? '') !== '' ? (int)$_POST['job_role_id'] : null;
$hire_date = trim($_POST['hire_date'] ?? '');
$status = trim($_POST['status'] ?? 'active');
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_id'] : null;
$role_id = $_POST['role_id'] !== '' ? (int)$_POST['role_id'] : null;
if ($first_name === '' || $last_name === '') {
echo json_encode([
'success' => false,
'message' => 'First name and Last name are required.'
]);
exit;
}
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(['success' => false, 'message' => 'Email non valida.']);
exit;
}
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
$status = 'active';
}
$sql = "INSERT INTO employees
(auth_user_id, employee_code, first_name, last_name, address, phone, email,
department_id, job_role_id, hire_date, status, created_at, updated_at)
VALUES
(:auth_user_id, :employee_code, :first_name, :last_name, :address, :phone, :email,
:department_id, :job_role_id, :hire_date, :status, NOW(), NOW())";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'auth_user_id' => $auth_user_id,
'employee_code' => $employee_code !== '' ? $employee_code : null,
'first_name' => $first_name,
'last_name' => $last_name,
'address' => $address !== '' ? $address : null,
'phone' => $phone !== '' ? $phone : null,
'email' => $email !== '' ? $email : null,
'department_id' => $department_id,
'job_role_id' => $job_role_id,
'hire_date' => $hire_date !== '' ? $hire_date : null,
'status' => $status
]);
if ($auth_user_id !== null && $role_id !== null) {
$checkRole = $pdo->prepare("SELECT COUNT(*) FROM auth_roles WHERE id = ?");
$checkRole->execute([$role_id]);
if ((int)$checkRole->fetchColumn() > 0) {
$stmtRole = $pdo->prepare("UPDATE auth_users SET role_id = :role_id, updated_at = NOW() WHERE id = :auth_user_id");
$stmtRole->execute([
'role_id' => $role_id,
'auth_user_id' => $auth_user_id
]);
}
}
echo json_encode(['success' => true]);
exit;
}
if ($action === 'edit') {
$id = (int)($_POST['id'] ?? 0);
$employee_code = trim($_POST['employee_code'] ?? '');
$first_name = trim($_POST['first_name'] ?? '');
$last_name = trim($_POST['last_name'] ?? '');
$address = trim($_POST['address'] ?? '');
$phone = trim($_POST['phone'] ?? '');
$email = trim($_POST['email'] ?? '');
$department_id = $_POST['department_id'] !== '' ? (int)$_POST['department_id'] : null;
$job_role_id = ($_POST['job_role_id'] ?? '') !== '' ? (int)$_POST['job_role_id'] : null;
$hire_date = trim($_POST['hire_date'] ?? '');
$status = trim($_POST['status'] ?? 'active');
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_id'] : null;
$role_id = $_POST['role_id'] !== '' ? (int)$_POST['role_id'] : null;
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid employee ID.']);
exit;
}
if ($first_name === '' || $last_name === '') {
echo json_encode([
'success' => false,
'message' => 'First name and Last name are required.'
]);
exit;
}
if ($email !== '' && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(['success' => false, 'message' => 'Email non valida.']);
exit;
}
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
$status = 'active';
}
$sql = "UPDATE employees
SET auth_user_id = :auth_user_id,
employee_code = :employee_code,
first_name = :first_name,
last_name = :last_name,
address = :address,
phone = :phone,
email = :email,
department_id = :department_id,
job_role_id = :job_role_id,
hire_date = :hire_date,
status = :status,
updated_at = NOW()
WHERE id = :id";
$stmt = $pdo->prepare($sql);
$stmt->execute([
'auth_user_id' => $auth_user_id,
'employee_code' => $employee_code !== '' ? $employee_code : null,
'first_name' => $first_name,
'last_name' => $last_name,
'address' => $address !== '' ? $address : null,
'phone' => $phone !== '' ? $phone : null,
'email' => $email !== '' ? $email : null,
'department_id' => $department_id,
'job_role_id' => $job_role_id,
'hire_date' => $hire_date !== '' ? $hire_date : null,
'status' => $status,
'id' => $id
]);
if ($auth_user_id !== null && $role_id !== null) {
$checkRole = $pdo->prepare("SELECT COUNT(*) FROM auth_roles WHERE id = ?");
$checkRole->execute([$role_id]);
if ((int)$checkRole->fetchColumn() > 0) {
$stmtRole = $pdo->prepare("UPDATE auth_users SET role_id = :role_id, updated_at = NOW() WHERE id = :auth_user_id");
$stmtRole->execute([
'role_id' => $role_id,
'auth_user_id' => $auth_user_id
]);
}
}
echo json_encode(['success' => true]);
exit;
}
if ($action === 'delete') {
// Codice originale per delete
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid employee ID.']);
exit;
}
$stmt = $pdo->prepare("DELETE FROM employees WHERE id = :id");
$stmt->execute(['id' => $id]);
echo json_encode(['success' => true]);
exit;
}
if ($action === 'get_employee_skills') {
$id = (int)$_POST['id'];
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid ID']);
exit;
}
$stmt = $pdo->prepare("SELECT skill_id, level FROM employee_skills WHERE employee_id = ?");
$stmt->execute([$id]);
$skills = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$skills[$row['skill_id']] = $row['level'];
}
echo json_encode(['success' => true, 'skills' => $skills]);
exit;
}
if ($action === 'save_employee_skills') {
$id = (int)$_POST['id'];
$skills_json = $_POST['skills'] ?? '';
$skills = json_decode($skills_json, true);
if ($id <= 0 || !is_array($skills)) {
echo json_encode(['success' => false, 'message' => 'Invalid data']);
exit;
}
$pdo->beginTransaction();
$stmtDelete = $pdo->prepare("DELETE FROM employee_skills WHERE employee_id = ?");
$stmtDelete->execute([$id]);
$stmtInsert = $pdo->prepare("INSERT INTO employee_skills (employee_id, skill_id, level) VALUES (?, ?, ?)");
foreach ($skills as $skill_id => $level) {
$stmtInsert->execute([$id, (int)$skill_id, $level]);
}
$pdo->commit();
echo json_encode(['success' => true]);
exit;
}
echo json_encode(['success' => false, 'message' => 'Unknown action.']);
exit;
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
echo json_encode([
'success' => false,
'message' => $e->getMessage()
]);
exit;
}
}
/* ==========================================
PAGE DATA (LIST + USERS LIST + SKILLS LIST)
========================================== */
// Employees list
$sql = "
SELECT e.*,
d.name AS department_name,
d.color AS department_color,
jr.name AS job_role_name,
au.email AS user_email,
au.role_id AS user_role_id,
ar.display_name AS role_display_name,
ar.name AS role_name,
CONCAT(COALESCE(au.first_name, ''), ' ', COALESCE(au.last_name, '')) AS user_fullname
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
LEFT JOIN job_roles jr ON jr.id = e.job_role_id
LEFT JOIN auth_users au ON e.auth_user_id = au.id
LEFT JOIN auth_roles ar ON ar.id = au.role_id
ORDER BY e.id DESC
";
$stmtEmployees = $pdo->query($sql);
$employees = $stmtEmployees->fetchAll(PDO::FETCH_ASSOC);
// Employees for the bulk-DPI multiselect (alphabetical, with department for the "whole department" shortcut)
$employeesForSelect = $pdo->query("
SELECT id, first_name, last_name, employee_code, department_id
FROM employees
ORDER BY last_name, first_name
")->fetchAll(PDO::FETCH_ASSOC);
// Job roles for the dropdown
$jobRoles = $pdo->query("
SELECT id, name FROM job_roles WHERE is_active = 1 ORDER BY sort_order, name
")->fetchAll(PDO::FETCH_ASSOC);
// Users list for select
$sqlUsers = "
SELECT id,
role_id,
CONCAT(
COALESCE(first_name, ''),
' ',
COALESCE(last_name, ''),
' (',
email,
')'
) AS label
FROM auth_users
ORDER BY first_name, last_name, email
";
$stmtUsers = $pdo->query($sqlUsers);
$users = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
// Roles list for select
$sqlRoles = "
SELECT id, name, display_name
FROM auth_roles
ORDER BY display_name, name
";
$stmtRoles = $pdo->query($sqlRoles);
$roles = $stmtRoles->fetchAll(PDO::FETCH_ASSOC);
// Departments list for select
$sqlDepartments = "
SELECT id, name, code, color
FROM departments
WHERE is_active = 1
ORDER BY sort_order ASC, name ASC
";
$stmtDepartments = $pdo->query($sqlDepartments);
$departments = $stmtDepartments->fetchAll(PDO::FETCH_ASSOC);
// Skills list for JS
$sqlSkills = "
SELECT s.id, s.name, pl.name as line_name, pl.line_number
FROM skills s
LEFT JOIN production_lines pl ON s.production_line_id = pl.id
ORDER BY IFNULL(pl.line_number, 999), s.name
";
$stmtSkills = $pdo->query($sqlSkills);
$allSkills = $stmtSkills->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 Dipendenti - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
<!-- jQuery e Bootstrap -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<!-- DataTables -->
<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>
<!-- Select2 -->
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.full.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;
font-size: 1rem;
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;
transition: all 0.2s ease-in-out;
}
.btn-add:hover {
background-color: #0b5ed7;
transform: scale(1.02);
}
.table thead {
background-color: #cfe3ff;
color: #1f2d3d;
}
.modal-content {
border-radius: 16px;
}
#tabellaDipendenti 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;
}
.badge-status.suspended {
background-color: #fee2e2;
color: #b91c1c;
}
.btn-matrix {
background-color: #198754;
color: #fff;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
transition: all 0.2s ease-in-out;
margin-right: 10px;
}
.btn-matrix:hover {
background-color: #157347;
transform: scale(1.02);
}
.department-badge {
display: inline-block;
color: #fff;
padding: 0.25rem 0.6rem;
border-radius: 999px;
font-size: 0.8rem;
font-weight: 600;
}
</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">
<h5 class="mb-0">Gestione Dipendenti</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">
<h6 class="fw-semibold mb-0">Elenco Completo</h6>
<div>
<button class="btn btn-matrix" onclick="location.href='skill_matrix.php'">
📊 Matrice Skills
</button>
<button type="button" class="btn btn-matrix" id="btnBulkPpe" data-bs-toggle="modal" data-bs-target="#bulkPpeModal">
🦺 Assegna DPI
</button>
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addEmployeeModal">
Aggiungi Dipendente
</button>
</div>
</div>
<!-- TABELLA -->
<div class="table-responsive">
<table id="tabellaDipendenti" class="table table-striped align-middle text-center" style="width:100%;">
<thead>
<tr>
<th>ID</th>
<th>Codice</th>
<th>Nome</th>
<th>Contatti</th>
<th>Reparto</th>
<th>Mansione</th>
<th>Data Assunzione</th>
<th>Stato</th>
<th>Utente collegato</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php if (!empty($employees)): ?>
<?php foreach ($employees as $row): ?>
<?php
$fullName = trim(($row['first_name'] ?? '') . ' ' . ($row['last_name'] ?? ''));
$hireDate = $row['hire_date'] && $row['hire_date'] !== '0000-00-00'
? date('d/m/Y', strtotime($row['hire_date']))
: '-';
$status = $row['status'] ?? 'active';
$statusClass = $status;
$statusLabel = ucfirst($status);
$linkedUser = '-';
if (!empty($row['user_email'])) {
$labelName = trim($row['user_fullname']);
if ($labelName !== '') {
$linkedUser = htmlspecialchars($labelName . ' (' . $row['user_email'] . ')');
} else {
$linkedUser = htmlspecialchars($row['user_email']);
}
}
?>
<tr>
<td><?= (int)$row['id'] ?></td>
<td><?= htmlspecialchars($row['employee_code'] ?? '') ?></td>
<td>
<a href="employee-profile.php?id=<?= (int)$row['id'] ?>" class="fw-semibold text-decoration-none">
<?= htmlspecialchars($fullName) ?>
</a>
</td>
<td class="text-start">
<?php if (!empty($row['email'])): ?>
<a href="mailto:<?= htmlspecialchars($row['email'], ENT_QUOTES) ?>" class="text-decoration-none small">
✉️ <?= htmlspecialchars($row['email']) ?>
</a><br>
<?php endif; ?>
<?php if (!empty($row['phone'])): ?>
<a href="tel:<?= htmlspecialchars($row['phone'], ENT_QUOTES) ?>" class="text-decoration-none small">
📞 <?= htmlspecialchars($row['phone']) ?>
</a>
<?php endif; ?>
<?php if (empty($row['email']) && empty($row['phone'])): ?>-<?php endif; ?>
</td>
<td>
<?php if (!empty($row['department_name'])): ?>
<span class="department-badge" style="background-color: <?= htmlspecialchars($row['department_color'] ?? '#6c757d', ENT_QUOTES) ?>;">
<?= htmlspecialchars($row['department_name']) ?>
</span>
<?php else: ?>
-
<?php endif; ?>
</td>
<td><?= !empty($row['job_role_name']) ? htmlspecialchars($row['job_role_name']) : '-' ?></td>
<td><?= $hireDate ?></td>
<td>
<span class="badge-status <?= $statusClass ?>">
<?= htmlspecialchars($statusLabel) ?>
</span>
</td>
<td><?= $linkedUser ?></td>
<td>
<button
class="btn btn-sm btn-outline-secondary edit-employee"
data-id="<?= (int)$row['id'] ?>"
data-code="<?= htmlspecialchars($row['employee_code'] ?? '', ENT_QUOTES) ?>"
data-first_name="<?= htmlspecialchars($row['first_name'] ?? '', ENT_QUOTES) ?>"
data-last_name="<?= htmlspecialchars($row['last_name'] ?? '', ENT_QUOTES) ?>"
data-department_id="<?= $row['department_id'] !== null ? (int)$row['department_id'] : '' ?>"
data-job_role_id="<?= $row['job_role_id'] !== null ? (int)$row['job_role_id'] : '' ?>"
data-address="<?= htmlspecialchars($row['address'] ?? '', ENT_QUOTES) ?>"
data-phone="<?= htmlspecialchars($row['phone'] ?? '', ENT_QUOTES) ?>"
data-email="<?= htmlspecialchars($row['email'] ?? '', ENT_QUOTES) ?>"
data-hire_date="<?= htmlspecialchars($row['hire_date'] ?? '', ENT_QUOTES) ?>"
data-status="<?= htmlspecialchars($status, ENT_QUOTES) ?>"
data-auth_user_id="<?= $row['auth_user_id'] !== null ? (int)$row['auth_user_id'] : '' ?>"
data-role_id="<?= $row['user_role_id'] !== null ? (int)$row['user_role_id'] : '' ?>">
✏️ Modifica
</button>
<button
class="btn btn-sm btn-outline-info manage-skills"
data-id="<?= (int)$row['id'] ?>"
data-name="<?= htmlspecialchars($fullName, ENT_QUOTES) ?>">
🛠️ Skills
</button>
<button
class="btn btn-sm btn-outline-danger delete-employee"
data-id="<?= (int)$row['id'] ?>"
data-name="<?= htmlspecialchars($fullName, ENT_QUOTES) ?>">
🗑️ Cancella
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- MODALE AGGIUNTA DIPENDENTE -->
<div class="modal fade" id="addEmployeeModal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Aggiungi Nuovo Dipendente</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addEmployeeForm">
<div class="mb-3">
<label class="form-label fw-semibold">Codice Dipendente</label>
<input type="text" class="form-control" id="addEmployeeCode" name="employee_code" placeholder="Opzionale">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Nome</label>
<input type="text" class="form-control" id="addFirstName" name="first_name" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Cognome</label>
<input type="text" class="form-control" id="addLastName" name="last_name" required>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Indirizzo</label>
<input type="text" class="form-control" id="addAddress" name="address" placeholder="Via, città, CAP">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Telefono</label>
<input type="tel" class="form-control" id="addPhone" name="phone">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Email</label>
<input type="email" class="form-control" id="addEmail" name="email">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Reparto</label>
<select class="form-select" id="addDepartmentId" name="department_id" style="width:100%;">
<option value="">-- Nessuno --</option>
<?php foreach ($departments as $d): ?>
<option value="<?= (int)$d['id'] ?>">
<?= htmlspecialchars($d['name']) ?>
<?= !empty($d['code']) ? ' (' . htmlspecialchars($d['code']) . ')' : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Mansione</label>
<select class="form-select" id="addJobRoleId" name="job_role_id" style="width:100%;">
<option value="">-- Nessuna --</option>
<?php foreach ($jobRoles as $jr): ?>
<option value="<?= (int)$jr['id'] ?>"><?= htmlspecialchars($jr['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Data Assunzione</label>
<input type="date" class="form-control" id="addHireDate" name="hire_date">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Stato</label>
<select class="form-select" id="addStatus" name="status">
<option value="active" selected>Attivo</option>
<option value="inactive">Cessato</option>
<option value="suspended">Sospeso</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Utente collegato (account login)</label>
<select class="form-select" id="addAuthUserId" name="auth_user_id" style="width:100%;">
<option value="">-- Nessuno --</option>
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>" data-role_id="<?= (int)$u['role_id'] ?>">
<?= htmlspecialchars($u['label']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3 d-none" id="addRoleWrapper">
<label class="form-label fw-semibold">Ruolo di accesso</label>
<select class="form-select" id="addRoleId" name="role_id" style="width:100%;">
<option value="">-- Seleziona ruolo --</option>
<?php foreach ($roles as $r): ?>
<option value="<?= (int)$r['id'] ?>">
<?= htmlspecialchars($r['display_name'] ?: $r['name']) ?>
</option>
<?php endforeach; ?>
</select>
<small class="text-muted">Visibile solo quando è collegato un utente di sistema.</small>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- MODALE EDIT DIPENDENTE -->
<div class="modal fade" id="editEmployeeModal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Modifica Dipendente</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="editEmployeeForm">
<input type="hidden" id="editEmployeeId">
<div class="mb-3">
<label class="form-label fw-semibold">Codice Dipendente</label>
<input type="text" class="form-control" id="editEmployeeCode" name="employee_code" placeholder="Opzionale">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Nome</label>
<input type="text" class="form-control" id="editFirstName" name="first_name" required>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Cognome</label>
<input type="text" class="form-control" id="editLastName" name="last_name" required>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Indirizzo</label>
<input type="text" class="form-control" id="editAddress" name="address">
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Telefono</label>
<input type="tel" class="form-control" id="editPhone" name="phone">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Email</label>
<input type="email" class="form-control" id="editEmail" name="email">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Reparto</label>
<select class="form-select" id="editDepartmentId" name="department_id" style="width:100%;">
<option value="">-- Nessuno --</option>
<?php foreach ($departments as $d): ?>
<option value="<?= (int)$d['id'] ?>">
<?= htmlspecialchars($d['name']) ?>
<?= !empty($d['code']) ? ' (' . htmlspecialchars($d['code']) . ')' : '' ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Mansione</label>
<select class="form-select" id="editJobRoleId" name="job_role_id" style="width:100%;">
<option value="">-- Nessuna --</option>
<?php foreach ($jobRoles as $jr): ?>
<option value="<?= (int)$jr['id'] ?>"><?= htmlspecialchars($jr['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Data Assunzione</label>
<input type="date" class="form-control" id="editHireDate" name="hire_date">
</div>
<div class="col-md-6 mb-3">
<label class="form-label fw-semibold">Stato</label>
<select class="form-select" id="editStatus" name="status">
<option value="active">Attivo</option>
<option value="inactive">Cessato</option>
<option value="suspended">Sospeso</option>
</select>
</div>
</div>
<div class="mb-3">
<label class="form-label fw-semibold">Utente collegato (account login)</label>
<select class="form-select" id="editAuthUserId" name="auth_user_id" style="width:100%;">
<option value="">-- Nessuno --</option>
<?php foreach ($users as $u): ?>
<option value="<?= (int)$u['id'] ?>" data-role_id="<?= (int)$u['role_id'] ?>">
<?= htmlspecialchars($u['label']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3 d-none" id="editRoleWrapper">
<label class="form-label fw-semibold">Ruolo di accesso</label>
<select class="form-select" id="editRoleId" name="role_id" style="width:100%;">
<option value="">-- Seleziona ruolo --</option>
<?php foreach ($roles as $r): ?>
<option value="<?= (int)$r['id'] ?>">
<?= htmlspecialchars($r['display_name'] ?: $r['name']) ?>
</option>
<?php endforeach; ?>
</select>
<small class="text-muted">Visibile solo quando è collegato un utente di sistema.</small>
</div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Save Changes</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- MODALE GESTIONE SKILLS -->
<div class="modal fade" id="manageSkillsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background-color:#cfe3ff;">
<h5 class="modal-title">Gestione Skills per <span id="skillsEmployeeName"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="manageSkillsForm">
<input type="hidden" id="skillsEmployeeId">
<div id="skillsContainer"></div>
<div class="text-center">
<button type="submit" class="btn btn-add">💾 Salva Skills</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- BULK DPI MODAL -->
<div class="modal fade" id="bulkPpeModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">🦺 Assegna DPI a più dipendenti</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Chiudi"></button>
</div>
<form id="bulkPpeForm">
<div class="modal-body" style="max-height:65vh; overflow-y:auto;">
<p class="text-muted small">Registra la consegna dello stesso DPI, con gli stessi dati, per più dipendenti contemporaneamente.</p>
<div class="row g-3">
<div class="col-12 col-md-6">
<label class="form-label fw-semibold">DPI <span class="text-danger">*</span></label>
<input type="text" id="bulkPpeItemName" class="form-control" maxlength="255" placeholder="es. Casco, Guanti, Scarpe antinfortunistiche" required>
</div>
<div class="col-6 col-md-3">
<label class="form-label fw-semibold">Data consegna</label>
<input type="date" id="bulkPpeDeliveryDate" class="form-control" value="<?= date('Y-m-d') ?>">
</div>
<div class="col-6 col-md-3">
<label class="form-label fw-semibold">Consegnato da</label>
<input type="text" id="bulkPpeDeliveredBy" class="form-control" maxlength="255" placeholder="Nome o azienda">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Note</label>
<textarea id="bulkPpeNotes" class="form-control" rows="2" placeholder="Opzionale"></textarea>
</div>
<div class="col-12">
<hr class="my-1">
</div>
<div class="col-12">
<label class="form-label fw-semibold">Dipendenti <span class="text-danger">*</span></label>
<div class="d-flex flex-wrap gap-2 mb-2 align-items-end">
<div>
<select id="bulkPpeDept" class="form-select form-select-sm" style="min-width:180px">
<option value="">— Reparto —</option>
<?php foreach ($departments as $d): ?>
<option value="<?= (int)$d['id'] ?>"><?= htmlspecialchars($d['name'], ENT_QUOTES, 'UTF-8') ?></option>
<?php endforeach; ?>
</select>
</div>
<button type="button" class="btn btn-sm btn-outline-primary" id="bulkPpeAddDept">+ Aggiungi reparto</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="bulkPpeSelectAll">Tutti</button>
<button type="button" class="btn btn-sm btn-outline-secondary" id="bulkPpeClear">Pulisci</button>
</div>
<select id="bulkPpeEmployees" class="form-select" multiple required>
<?php foreach ($employeesForSelect as $e): ?>
<option value="<?= (int)$e['id'] ?>" data-dept="<?= (int)($e['department_id'] ?? 0) ?>">
<?= htmlspecialchars(trim($e['last_name'] . ' ' . $e['first_name']), ENT_QUOTES, 'UTF-8') ?><?php if (!empty($e['employee_code'])): ?> (<?= htmlspecialchars($e['employee_code'], ENT_QUOTES, 'UTF-8') ?>)<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text"><span id="bulkPpeCount">0</span> dipendenti selezionati</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light border" data-bs-dismiss="modal">Annulla</button>
<button type="submit" class="btn btn-primary" id="bulkPpeSaveBtn">Assegna DPI</button>
</div>
</form>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
const allSkills = <?= json_encode($allSkills) ?>;
$(document).ready(function() {
// DataTable
$('#tabellaDipendenti').DataTable({
order: [
[0, 'desc']
],
pageLength: 25,
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json',
emptyTable: 'Nessun dipendente presente'
}
});
// Select2 on user selects
$('#addAuthUserId, #editAuthUserId, #addDepartmentId, #editDepartmentId, #addRoleId, #editRoleId, #addJobRoleId, #editJobRoleId').select2({
theme: 'bootstrap-5',
width: '100%'
});
/* -------- BULK DPI ASSIGN -------- */
var $bulkPpeEmp = $('#bulkPpeEmployees');
$bulkPpeEmp.select2({
theme: 'bootstrap-5',
placeholder: 'Seleziona dipendenti...',
dropdownParent: $('#bulkPpeModal'),
closeOnSelect: false,
width: '100%'
});
function bulkPpeUpdateCount() {
$('#bulkPpeCount').text(($bulkPpeEmp.val() || []).length);
}
$bulkPpeEmp.on('change', bulkPpeUpdateCount);
// Reset the form (and the save button) each time the modal opens
$('#btnBulkPpe').on('click', function() {
document.getElementById('bulkPpeForm').reset();
$bulkPpeEmp.val(null).trigger('change');
bulkPpeUpdateCount();
var sb = document.getElementById('bulkPpeSaveBtn');
sb.disabled = false;
sb.innerHTML = 'Assegna DPI';
});
// Add every employee of the chosen department to the selection
$('#bulkPpeAddDept').on('click', function() {
var dept = $('#bulkPpeDept').val();
if (!dept) return;
var current = ($bulkPpeEmp.val() || []).map(String);
$bulkPpeEmp.find('option').each(function() {
if (this.getAttribute('data-dept') === String(dept) && current.indexOf(this.value) === -1) {
current.push(this.value);
}
});
$bulkPpeEmp.val(current).trigger('change');
});
$('#bulkPpeSelectAll').on('click', function() {
var all = $bulkPpeEmp.find('option').map(function() {
return this.value;
}).get();
$bulkPpeEmp.val(all).trigger('change');
});
$('#bulkPpeClear').on('click', function() {
$bulkPpeEmp.val(null).trigger('change');
});
$('#bulkPpeForm').on('submit', function(e) {
e.preventDefault();
var itemName = $('#bulkPpeItemName').val().trim();
var emps = $bulkPpeEmp.val() || [];
if (!itemName) {
Swal.fire('Attenzione', 'Indicare il nome del DPI.', 'warning');
return;
}
if (emps.length === 0) {
Swal.fire('Attenzione', 'Selezionare almeno un dipendente.', 'warning');
return;
}
var btn = document.getElementById('bulkPpeSaveBtn');
btn.disabled = true;
var orig = btn.innerHTML;
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> Salvataggio...';
var fd = new FormData();
fd.append('item_name', itemName);
fd.append('delivery_date', $('#bulkPpeDeliveryDate').val());
fd.append('delivered_by', $('#bulkPpeDeliveredBy').val());
fd.append('notes', $('#bulkPpeNotes').val());
emps.forEach(function(id) {
fd.append('employee_ids[]', id);
});
fetch('ajax/employee_profile/save_bulk_ppe.php', {
method: 'POST',
body: fd
})
.then(function(r) {
return r.json();
})
.then(function(data) {
if (data.success) {
bootstrap.Modal.getInstance(document.getElementById('bulkPpeModal')).hide();
Swal.fire({
icon: 'success',
title: 'Fatto',
text: data.message,
timer: 2000,
showConfirmButton: false
});
} else {
btn.disabled = false;
btn.innerHTML = orig;
Swal.fire('Errore', data.message || 'Errore.', 'error');
}
})
.catch(function() {
btn.disabled = false;
btn.innerHTML = orig;
Swal.fire('Errore', 'Errore di connessione.', 'error');
});
});
function syncAddRoleVisibility() {
const authUserId = $('#addAuthUserId').val();
if (authUserId) {
$('#addRoleWrapper').removeClass('d-none');
const selectedRoleId = $('#addAuthUserId option:selected').data('role_id');
if (selectedRoleId) {
$('#addRoleId').val(String(selectedRoleId)).trigger('change');
}
} else {
$('#addRoleWrapper').addClass('d-none');
$('#addRoleId').val('').trigger('change');
}
}
function syncEditRoleVisibility() {
const authUserId = $('#editAuthUserId').val();
if (authUserId) {
$('#editRoleWrapper').removeClass('d-none');
const selectedRoleId = $('#editAuthUserId option:selected').data('role_id');
if (selectedRoleId) {
$('#editRoleId').val(String(selectedRoleId)).trigger('change');
}
} else {
$('#editRoleWrapper').addClass('d-none');
$('#editRoleId').val('').trigger('change');
}
}
$('#addAuthUserId').on('change', syncAddRoleVisibility);
$('#editAuthUserId').on('change', syncEditRoleVisibility);
/* -------- ADD EMPLOYEE -------- */
$("#addEmployeeForm").on("submit", function(e) {
e.preventDefault();
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'add');
payload.append('employee_code', $("#addEmployeeCode").val().trim());
payload.append('first_name', $("#addFirstName").val().trim());
payload.append('last_name', $("#addLastName").val().trim());
payload.append('address', $("#addAddress").val().trim());
payload.append('phone', $("#addPhone").val().trim());
payload.append('email', $("#addEmail").val().trim());
payload.append('department_id', $("#addDepartmentId").val() || '');
payload.append('job_role_id', $("#addJobRoleId").val() || '');
payload.append('hire_date', $("#addHireDate").val());
payload.append('status', $("#addStatus").val());
payload.append('auth_user_id', $("#addAuthUserId").val() || '');
payload.append('role_id', $("#addAuthUserId").val() ? ($("#addRoleId").val() || '') : '');
fetch("", {
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: "Saved!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to save employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
/* -------- OPEN EDIT MODAL -------- */
$(document).on("click", ".edit-employee", function() {
const btn = $(this);
$("#editEmployeeId").val(btn.data("id"));
$("#editEmployeeCode").val(btn.data("code"));
$("#editFirstName").val(btn.data("first_name"));
$("#editLastName").val(btn.data("last_name"));
$("#editDepartmentId").val(btn.data("department_id") ? String(btn.data("department_id")) : '').trigger('change');
$("#editJobRoleId").val(btn.data("job_role_id") ? String(btn.data("job_role_id")) : '').trigger('change');
$("#editAddress").val(btn.data("address"));
$("#editPhone").val(btn.data("phone"));
$("#editEmail").val(btn.data("email"));
$("#editHireDate").val(btn.data("hire_date"));
$("#editStatus").val(btn.data("status"));
const authUserId = btn.data("auth_user_id");
$("#editAuthUserId").val(authUserId ? String(authUserId) : '').trigger('change');
const roleId = btn.data("role_id");
if (authUserId && roleId) {
$("#editRoleWrapper").removeClass('d-none');
$("#editRoleId").val(String(roleId)).trigger('change');
} else {
$("#editRoleWrapper").addClass('d-none');
$("#editRoleId").val('').trigger('change');
}
$("#editEmployeeModal").modal("show");
$("#editEmployeeModal").modal("show");
});
/* -------- SAVE EDIT -------- */
$("#editEmployeeForm").on("submit", function(e) {
e.preventDefault();
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'edit');
payload.append('id', $("#editEmployeeId").val());
payload.append('employee_code', $("#editEmployeeCode").val().trim());
payload.append('first_name', $("#editFirstName").val().trim());
payload.append('last_name', $("#editLastName").val().trim());
payload.append('address', $("#editAddress").val().trim());
payload.append('phone', $("#editPhone").val().trim());
payload.append('email', $("#editEmail").val().trim());
payload.append('department_id', $("#editDepartmentId").val() || '');
payload.append('job_role_id', $("#editJobRoleId").val() || '');
payload.append('hire_date', $("#editHireDate").val());
payload.append('status', $("#editStatus").val());
payload.append('auth_user_id', $("#editAuthUserId").val() || '');
payload.append('role_id', $("#editAuthUserId").val() ? ($("#editRoleId").val() || '') : '');
fetch("", {
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: "Updated!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to update employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
/* -------- DELETE EMPLOYEE -------- */
$(document).on("click", ".delete-employee", function() {
const id = $(this).data("id");
const name = $(this).data("name");
Swal.fire({
title: "Confermi la cancellazione?",
text: name ? ("Dipendente: " + name) : "This employee will be deleted.",
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#d33",
cancelButtonColor: "#6c757d",
confirmButtonText: "Sì, cancella",
cancelButtonText: "Annulla"
}).then((result) => {
if (!result.isConfirmed) return;
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'delete');
payload.append('id', id);
fetch("", {
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: "Deleted!",
confirmButtonColor: "#3085d6"
})
.then(() => location.reload());
} else {
Swal.fire({
icon: "error",
title: "Error",
text: data.message || "Unable to delete employee."
});
}
})
.catch(err => {
Swal.fire({
icon: "error",
title: "Error",
text: "Communication error."
});
console.error(err);
});
});
});
/* -------- OPEN SKILLS MODAL -------- */
$(document).on('click', '.manage-skills', function() {
const id = $(this).data('id');
const name = $(this).data('name');
$('#skillsEmployeeId').val(id);
$('#skillsEmployeeName').text(name);
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'get_employee_skills');
payload.append('id', id);
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: payload.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
const currentSkills = data.skills || {};
let html = '';
let currentLine = '';
allSkills.forEach(skill => {
let line = skill.line_name || 'Generali';
if (line !== currentLine) {
if (currentLine) html += '</div>';
html += `<h6 class="mt-3">${line}</h6><div class="row">`;
currentLine = line;
}
let level = currentSkills[skill.id] || 'NON RICH.';
let options = '';
if (skill.name === 'TURNO NOTTURNO') {
options = `
<option value="si" ${level === 'si' ? 'selected' : ''}>Si</option>
<option value="no" ${level === 'no' ? 'selected' : ''}>No</option>
`;
} else {
options = `
<option value="DF" ${level === 'DF' ? 'selected' : ''}>Da formare</option>
<option value="C" ${level === 'C' ? 'selected' : ''}>Conosce l'attività</option>
<option value="CQ" ${level === 'CQ' ? 'selected' : ''}>Conoscenza media</option>
<option value="Q" ${level === 'Q' ? 'selected' : ''}>Qualificato</option>
<option value="NON RICH." ${level === 'NON RICH.' ? 'selected' : ''}>Non richiesto</option>
`;
}
html += `
<div class="col-md-6 mb-3">
<label class="form-label">${skill.name}</label>
<select name="skills[${skill.id}]" class="form-select">
${options}
</select>
</div>
`;
});
if (currentLine) html += '</div>';
$('#skillsContainer').html(html);
$('#manageSkillsModal').modal('show');
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message || 'Unable to load skills.'
});
}
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Communication error.'
});
console.error(err);
});
});
/* -------- SAVE SKILLS -------- */
$('#manageSkillsForm').on('submit', function(e) {
e.preventDefault();
const id = $('#skillsEmployeeId').val();
const skills = {};
$('select[name^="skills["]').each(function() {
const skillId = $(this).attr('name').match(/\[(\d+)\]/)[1];
skills[skillId] = $(this).val();
});
const payload = new URLSearchParams();
payload.append('ajax', '1');
payload.append('action', 'save_employee_skills');
payload.append('id', id);
payload.append('skills', JSON.stringify(skills));
fetch('', {
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: 'Skills salvate!'
});
$('#manageSkillsModal').modal('hide');
} else {
Swal.fire({
icon: 'error',
title: 'Error',
text: data.message || 'Unable to save skills.'
});
}
})
.catch(err => {
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Communication error.'
});
console.error(err);
});
});
});
</script>
</body>
</html>