zibo-dashboard/public/userarea/lookup_values.php

643 lines
27 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();
/**
* ws_lookup_options manager page
* Table expected:
* - id (AI)
* - category (varchar)
* - value (varchar)
* - label (varchar)
* - sort_order (int)
* - is_default (tinyint 0/1)
* - is_active (tinyint 0/1)
*/
// AJAX HANDLERS
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax']) && $_POST['ajax'] == '1') {
header('Content-Type: application/json; charset=utf-8');
$action = $_POST['action'] ?? '';
try {
if ($action === 'add') {
$category = trim($_POST['category'] ?? '');
$value = trim($_POST['value'] ?? '');
$label = trim($_POST['label'] ?? '');
$sort_order = (int)($_POST['sort_order'] ?? 100);
$is_default = (int)($_POST['is_default'] ?? 0) ? 1 : 0;
$is_active = (int)($_POST['is_active'] ?? 1) ? 1 : 0;
if ($category === '' || $value === '' || $label === '') {
echo json_encode(['success' => false, 'message' => 'Compila category, value e label']);
exit;
}
$pdo->beginTransaction();
// If set as default, unset other defaults in same category (simple & reliable)
if ($is_default === 1) {
$stmt = $pdo->prepare("UPDATE ws_lookup_options SET is_default = 0 WHERE category = ?");
$stmt->execute([$category]);
}
$stmt = $pdo->prepare("
INSERT INTO ws_lookup_options
(category, value, label, sort_order, is_default, is_active)
VALUES (?, ?, ?, ?, ?, ?)
");
$stmt->execute([$category, $value, $label, $sort_order, $is_default, $is_active]);
$pdo->commit();
echo json_encode(['success' => true]);
exit;
}
if ($action === 'edit') {
$id = (int)($_POST['id'] ?? 0);
$category = trim($_POST['category'] ?? '');
$value = trim($_POST['value'] ?? '');
$label = trim($_POST['label'] ?? '');
$sort_order = (int)($_POST['sort_order'] ?? 100);
$is_default = (int)($_POST['is_default'] ?? 0) ? 1 : 0;
$is_active = (int)($_POST['is_active'] ?? 1) ? 1 : 0;
if ($id <= 0 || $category === '' || $value === '' || $label === '') {
echo json_encode(['success' => false, 'message' => 'Dati non validi']);
exit;
}
$pdo->beginTransaction();
// If set as default, unset other defaults in same category (excluding current)
if ($is_default === 1) {
$stmt = $pdo->prepare("UPDATE ws_lookup_options SET is_default = 0 WHERE category = ? AND id <> ?");
$stmt->execute([$category, $id]);
}
$stmt = $pdo->prepare("
UPDATE ws_lookup_options SET
category = ?,
value = ?,
label = ?,
sort_order = ?,
is_default = ?,
is_active = ?
WHERE id = ?
");
$stmt->execute([$category, $value, $label, $sort_order, $is_default, $is_active, $id]);
$pdo->commit();
echo json_encode(['success' => true]);
exit;
}
if ($action === 'delete') {
$id = (int)($_POST['id'] ?? 0);
if ($id <= 0) {
echo json_encode(['success' => false, 'message' => 'ID non valido']);
exit;
}
$stmt = $pdo->prepare("DELETE FROM ws_lookup_options WHERE id = ?");
$stmt->execute([$id]);
echo json_encode(['success' => true]);
exit;
}
echo json_encode(['success' => false, 'message' => 'Azione sconosciuta']);
exit;
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
exit;
}
}
// Categories list (static for now, easy to extend)
$categories = [
'marking' => 'Marchiatura',
'lubrication_type' => 'Lubrificazione',
'control_frequency_cut' => 'Frequenza controllo (taglio)',
'control_frequency_drawing' => 'Frequenza controllo disegno',
'control_frequency_jig' => 'Frequenza controllo in dima',
'control_mode_jig' => 'Modalità controllo in dima',
'box_type' => 'Tipo scatola',
'pallet_type' => 'Tipo bancale',
'requested_package_code' => 'Confezione richiesta',
];
// Selected category filter
$categoryFilter = trim($_GET['cat'] ?? '');
if ($categoryFilter !== '' && !array_key_exists($categoryFilter, $categories)) {
$categoryFilter = '';
}
// Load options
$params = [];
$sql = "
SELECT id, category, value, label, sort_order, is_default, is_active, created_at, updated_at
FROM ws_lookup_options
";
if ($categoryFilter !== '') {
$sql .= " WHERE category = ? ";
$params[] = $categoryFilter;
}
$sql .= " ORDER BY category ASC, sort_order ASC, label ASC, id ASC ";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$options = $stmt->fetchAll(PDO::FETCH_ASSOC);
function h($v)
{
return htmlspecialchars((string)$v, ENT_QUOTES);
}
?>
<!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>Lookup Worksheet</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>
<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/@ttskch/select2-bootstrap4-theme@1.5.2/dist/select2-bootstrap4.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.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-dashboard {
background: #cfe3ff !important;
color: #1f2d3d !important;
border: 1px solid #bcd4f4 !important;
border-radius: 10px;
font-weight: 600;
padding: 10px 18px;
}
.btn-add {
background: #0d6efd;
color: white;
border-radius: 8px;
padding: 10px 20px;
font-weight: 500;
}
.table thead {
background: #cfe3ff;
color: #1f2d3d;
}
.modal-content {
border-radius: 16px;
}
.small-hint {
color: #6b7280;
font-size: 0.85rem;
}
/* Select2 sizing alignment */
.select2-container .select2-selection--single {
height: calc(2.375rem + 2px);
padding: 0.375rem 0.75rem;
border: 1px solid #ced4da;
border-radius: 0.375rem;
display: flex;
align-items: center;
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: 1.6;
padding-left: 0;
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
height: calc(2.375rem + 2px);
}
.select2-container {
width: 100% !important;
}
.badge-soft {
background: #eef6ff;
color: #1f2d3d;
border: 1px solid #bcd4f4;
font-weight: 600;
}
.muted {
color: #6b7280;
}
</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">
<div>
<h5 class="mb-0">Lookup Worksheet</h5>
<div class="small-hint">Gestione valori predefiniti (tendine) per i campi dei fogli di lavoro</div>
</div>
<button class="btn back-dashboard" onclick="location.href='production_dashboard.php'">↩️ Dashboard</button>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="d-flex align-items-center gap-2" style="min-width: 420px;">
<div class="fw-semibold">Categoria</div>
<select id="categoryFilter" class="form-select">
<option value="">-- Tutte --</option>
<?php foreach ($categories as $key => $label): ?>
<option value="<?= h($key) ?>" <?= $categoryFilter === $key ? 'selected' : '' ?>>
<?= h($label) ?> (<?= h($key) ?>)
</option>
<?php endforeach; ?>
</select>
</div>
<button class="btn btn-add" data-bs-toggle="modal" data-bs-target="#addModal">
Aggiungi valore
</button>
</div>
<div class="table-responsive">
<table id="tabellaLookup" class="table table-striped table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Category</th>
<th>Value</th>
<th>Label</th>
<th>Ordine</th>
<th>Default</th>
<th>Attivo</th>
<th>Azioni</th>
</tr>
</thead>
<tbody>
<?php foreach ($options as $o): ?>
<tr>
<td><?= (int)$o['id'] ?></td>
<td>
<span class="badge badge-soft"><?= h($o['category']) ?></span>
<div class="small-hint">
<?= h($categories[$o['category']] ?? '-') ?>
</div>
</td>
<td class="fw-semibold"><?= h($o['value']) ?></td>
<td><?= h($o['label']) ?></td>
<td><?= (int)$o['sort_order'] ?></td>
<td><?= (int)$o['is_default'] === 1 ? '✅' : '-' ?></td>
<td><?= (int)$o['is_active'] === 1 ? '✅' : '⛔' ?></td>
<td class="text-nowrap">
<button class="btn btn-sm btn-outline-primary edit-row"
data-id="<?= (int)$o['id'] ?>"
data-category="<?= h($o['category']) ?>"
data-value="<?= h($o['value']) ?>"
data-label="<?= h($o['label']) ?>"
data-sort_order="<?= (int)$o['sort_order'] ?>"
data-is_default="<?= (int)$o['is_default'] ?>"
data-is_active="<?= (int)$o['is_active'] ?>">
✏️ Modifica
</button>
<button class="btn btn-sm btn-outline-danger delete-row"
data-id="<?= (int)$o['id'] ?>"
data-name="<?= h($o['category'] . ' / ' . $o['value']) ?>">
🗑️ Elimina
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="small-hint mt-2">
Suggerimento: imposta <b>Default</b> solo per 1 valore per categoria (questa pagina lo gestisce automaticamente).
</div>
</div>
</div>
</div>
</div>
<?php include('include/footer.php'); ?>
</div>
<!-- MODAL ADD -->
<div class="modal fade" id="addModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background:#cfe3ff;">
<h5 class="modal-title">Aggiungi valore</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="addForm">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold">Categoria *</label>
<select class="form-select" name="category" id="add_category" required>
<option value="">-- Seleziona --</option>
<?php foreach ($categories as $key => $label): ?>
<option value="<?= h($key) ?>"><?= h($label) ?> (<?= h($key) ?>)</option>
<?php endforeach; ?>
</select>
<div class="small-hint">Categoria = campo di destinazione nel worksheet</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Value *</label>
<input type="text" class="form-control" name="value" placeholder="es. S, N, EUR, EACH_COIL" required>
<div class="small-hint">Valore tecnico stabile (quello che salvi nel DB)</div>
</div>
<div class="col-md-8">
<label class="form-label fw-semibold">Label *</label>
<input type="text" class="form-control" name="label" placeholder="Testo visibile in tendina" required>
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Ordine</label>
<input type="number" class="form-control" name="sort_order" value="100" min="1">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Default</label>
<select class="form-select" name="is_default">
<option value="0" selected>No</option>
<option value="1">Sì</option>
</select>
<div class="small-hint">Se “Sì”, gli altri default della stessa categoria verranno disattivati</div>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Attivo</label>
<select class="form-select" name="is_active">
<option value="1" selected>Sì</option>
<option value="0">No</option>
</select>
</div>
<div class="col-12 text-center mt-2">
<button type="submit" class="btn btn-add">💾 Salva</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- MODAL EDIT -->
<div class="modal fade" id="editModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header" style="background:#cfe3ff;">
<h5 class="modal-title">Modifica valore</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form id="editForm">
<input type="hidden" name="id" id="edit_id">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold">Categoria *</label>
<select class="form-select" name="category" id="edit_category" required>
<option value="">-- Seleziona --</option>
<?php foreach ($categories as $key => $label): ?>
<option value="<?= h($key) ?>"><?= h($label) ?> (<?= h($key) ?>)</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Value *</label>
<input type="text" class="form-control" name="value" id="edit_value" required>
</div>
<div class="col-md-8">
<label class="form-label fw-semibold">Label *</label>
<input type="text" class="form-control" name="label" id="edit_label" required>
</div>
<div class="col-md-4">
<label class="form-label fw-semibold">Ordine</label>
<input type="number" class="form-control" name="sort_order" id="edit_sort_order" min="1">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Default</label>
<select class="form-select" name="is_default" id="edit_is_default">
<option value="0">No</option>
<option value="1">Sì</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold">Attivo</label>
<select class="form-select" name="is_active" id="edit_is_active">
<option value="1">Sì</option>
<option value="0">No</option>
</select>
</div>
<div class="col-12 text-center mt-2">
<button type="submit" class="btn btn-add">💾 Salva modifiche</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<?php include('jsinclude.php'); ?>
<script>
$(document).ready(function() {
// DataTable
$('#tabellaLookup').DataTable({
pageLength: 50,
lengthMenu: [10, 25, 50, 100],
order: [
[1, 'asc'],
[4, 'asc'],
[3, 'asc']
],
language: {
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
}
});
// Select2 for category filter + modal selects
$('#categoryFilter, #add_category, #edit_category').select2({
theme: 'bootstrap4',
width: '100%',
placeholder: '-- Seleziona --',
allowClear: true
});
// Filter redirect
$('#categoryFilter').on('change', function() {
const v = $(this).val() || '';
const base = window.location.pathname.split('/').pop();
if (v === '') {
window.location.href = base;
} else {
window.location.href = base + '?cat=' + encodeURIComponent(v);
}
});
// Add
$('#addForm').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('ajax', '1');
formData.append('action', 'add');
fetch('', {
method: 'POST',
body: new URLSearchParams(formData)
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Salvato!',
timer: 900
})
.then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
});
});
// Open edit modal
$(document).on('click', '.edit-row', function() {
const btn = $(this);
$('#edit_id').val(btn.data('id'));
$('#edit_category').val(btn.data('category')).trigger('change');
$('#edit_value').val(btn.data('value'));
$('#edit_label').val(btn.data('label'));
$('#edit_sort_order').val(btn.data('sort_order'));
$('#edit_is_default').val(String(btn.data('is_default')));
$('#edit_is_active').val(String(btn.data('is_active')));
const modal = new bootstrap.Modal(document.getElementById('editModal'));
modal.show();
});
// Save edit
$('#editForm').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('ajax', '1');
formData.append('action', 'edit');
fetch('', {
method: 'POST',
body: new URLSearchParams(formData)
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Aggiornato!',
timer: 900
})
.then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
});
});
// Delete
$(document).on('click', '.delete-row', function() {
const id = $(this).data('id');
const name = $(this).data('name');
Swal.fire({
title: 'Confermi eliminazione?',
text: name,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#6c757d',
confirmButtonText: 'Sì, elimina',
cancelButtonText: 'Annulla'
}).then(result => {
if (!result.isConfirmed) return;
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `ajax=1&action=delete&id=${id}`
})
.then(r => r.json())
.then(data => {
if (data.success) {
Swal.fire({
icon: 'success',
title: 'Eliminato!',
timer: 900
})
.then(() => location.reload());
} else {
Swal.fire({
icon: 'error',
title: 'Errore',
text: data.message
});
}
});
});
});
});
</script>
</body>
</html>