991 lines
43 KiB
PHP
991 lines
43 KiB
PHP
<?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') {
|
||
// Codice originale per add
|
||
$employee_code = trim($_POST['employee_code'] ?? '');
|
||
$first_name = trim($_POST['first_name'] ?? '');
|
||
$last_name = trim($_POST['last_name'] ?? '');
|
||
$department = trim($_POST['department'] ?? '');
|
||
$position = trim($_POST['position'] ?? '');
|
||
$hire_date = trim($_POST['hire_date'] ?? '');
|
||
$status = trim($_POST['status'] ?? 'active');
|
||
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_id'] : null;
|
||
|
||
if ($first_name === '' || $last_name === '') {
|
||
echo json_encode([
|
||
'success' => false,
|
||
'message' => 'First name and Last name are required.'
|
||
]);
|
||
exit;
|
||
}
|
||
|
||
if (!in_array($status, ['active', 'inactive', 'suspended'], true)) {
|
||
$status = 'active';
|
||
}
|
||
|
||
$sql = "INSERT INTO employees
|
||
(auth_user_id, employee_code, first_name, last_name, department, position, hire_date, status, created_at, updated_at)
|
||
VALUES
|
||
(:auth_user_id, :employee_code, :first_name, :last_name, :department, :position, :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,
|
||
'department' => $department !== '' ? $department : null,
|
||
'position' => $position !== '' ? $position : null,
|
||
'hire_date' => $hire_date !== '' ? $hire_date : null,
|
||
'status' => $status
|
||
]);
|
||
|
||
echo json_encode(['success' => true]);
|
||
exit;
|
||
}
|
||
|
||
if ($action === 'edit') {
|
||
// Codice originale per edit
|
||
$id = (int)($_POST['id'] ?? 0);
|
||
$employee_code = trim($_POST['employee_code'] ?? '');
|
||
$first_name = trim($_POST['first_name'] ?? '');
|
||
$last_name = trim($_POST['last_name'] ?? '');
|
||
$department = trim($_POST['department'] ?? '');
|
||
$position = trim($_POST['position'] ?? '');
|
||
$hire_date = trim($_POST['hire_date'] ?? '');
|
||
$status = trim($_POST['status'] ?? 'active');
|
||
$auth_user_id = $_POST['auth_user_id'] !== '' ? (int)$_POST['auth_user_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 (!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,
|
||
department = :department,
|
||
position = :position,
|
||
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,
|
||
'department' => $department !== '' ? $department : null,
|
||
'position' => $position !== '' ? $position : null,
|
||
'hire_date' => $hire_date !== '' ? $hire_date : null,
|
||
'status' => $status,
|
||
'id' => $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.*,
|
||
au.email AS user_email,
|
||
CONCAT(COALESCE(au.first_name, ''), ' ', COALESCE(au.last_name, '')) AS user_fullname
|
||
FROM employees e
|
||
LEFT JOIN auth_users au ON e.auth_user_id = au.id
|
||
ORDER BY e.id DESC
|
||
";
|
||
$stmtEmployees = $pdo->query($sql);
|
||
$employees = $stmtEmployees->fetchAll(PDO::FETCH_ASSOC);
|
||
|
||
// Users list for select
|
||
$sqlUsers = "
|
||
SELECT 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);
|
||
|
||
// 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/bootstrap@5.3.3/dist/js/bootstrap.bundle.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);
|
||
}
|
||
</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">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 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>Code</th>
|
||
<th>Name</th>
|
||
<th>Department</th>
|
||
<th>Position</th>
|
||
<th>Hire Date</th>
|
||
<th>Status</th>
|
||
<th>Linked User</th>
|
||
<th>Actions</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><?= htmlspecialchars($fullName) ?></td>
|
||
<td><?= htmlspecialchars($row['department'] ?? '') ?></td>
|
||
<td><?= htmlspecialchars($row['position'] ?? '') ?></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="<?= htmlspecialchars($row['department'] ?? '', ENT_QUOTES) ?>"
|
||
data-position="<?= htmlspecialchars($row['position'] ?? '', 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'] : '' ?>">
|
||
✏️ 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-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">Employee Code</label>
|
||
<input type="text" class="form-control" id="addEmployeeCode" name="employee_code" placeholder="Optional">
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">First Name</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">Last Name</label>
|
||
<input type="text" class="form-control" id="addLastName" name="last_name" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Department</label>
|
||
<input type="text" class="form-control" id="addDepartment" name="department" placeholder="e.g. Production">
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Position</label>
|
||
<input type="text" class="form-control" id="addPosition" name="position" placeholder="e.g. Line Operator">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Hire Date</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">Status</label>
|
||
<select class="form-select" id="addStatus" name="status">
|
||
<option value="active" selected>Active</option>
|
||
<option value="inactive">Inactive</option>
|
||
<option value="suspended">Suspended</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Linked User (auth_users)</label>
|
||
<select class="form-select" id="addAuthUserId" name="auth_user_id" style="width:100%;">
|
||
<option value="">-- None --</option>
|
||
<?php foreach ($users as $u): ?>
|
||
<option value="<?= (int)$u['id'] ?>">
|
||
<?= htmlspecialchars($u['label']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</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-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">Employee Code</label>
|
||
<input type="text" class="form-control" id="editEmployeeCode" name="employee_code" placeholder="Optional">
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">First Name</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">Last Name</label>
|
||
<input type="text" class="form-control" id="editLastName" name="last_name" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Department</label>
|
||
<input type="text" class="form-control" id="editDepartment" name="department">
|
||
</div>
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Position</label>
|
||
<input type="text" class="form-control" id="editPosition" name="position">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row">
|
||
<div class="col-md-6 mb-3">
|
||
<label class="form-label fw-semibold">Hire Date</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">Status</label>
|
||
<select class="form-select" id="editStatus" name="status">
|
||
<option value="active">Active</option>
|
||
<option value="inactive">Inactive</option>
|
||
<option value="suspended">Suspended</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Linked User (auth_users)</label>
|
||
<select class="form-select" id="editAuthUserId" name="auth_user_id" style="width:100%;">
|
||
<option value="">-- None --</option>
|
||
<?php foreach ($users as $u): ?>
|
||
<option value="<?= (int)$u['id'] ?>">
|
||
<?= htmlspecialchars($u['label']) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</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>
|
||
|
||
<?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').select2({
|
||
theme: 'bootstrap-5',
|
||
width: '100%'
|
||
});
|
||
|
||
/* -------- 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('department', $("#addDepartment").val().trim());
|
||
payload.append('position', $("#addPosition").val().trim());
|
||
payload.append('hire_date', $("#addHireDate").val());
|
||
payload.append('status', $("#addStatus").val());
|
||
payload.append('auth_user_id', $("#addAuthUserId").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"));
|
||
$("#editDepartment").val(btn.data("department"));
|
||
$("#editPosition").val(btn.data("position"));
|
||
$("#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');
|
||
|
||
$("#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('department', $("#editDepartment").val().trim());
|
||
payload.append('position', $("#editPosition").val().trim());
|
||
payload.append('hire_date', $("#editHireDate").val());
|
||
payload.append('status', $("#editStatus").val());
|
||
payload.append('auth_user_id', $("#editAuthUserId").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>
|