397 lines
15 KiB
PHP
397 lines
15 KiB
PHP
<?php include('include/headscript.php'); ?>
|
||
<!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>Scheda Mescola - <?= 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);
|
||
}
|
||
|
||
.info-label {
|
||
font-size: .8rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: .04em;
|
||
color: #6c757d;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.info-value {
|
||
font-size: 1.05rem;
|
||
font-weight: 600;
|
||
color: #1f2d3d;
|
||
}
|
||
|
||
.nav-tabs .nav-link.active {
|
||
background-color: #cfe3ff;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.btn-add {
|
||
background-color: #0d6efd;
|
||
color: #fff;
|
||
border-radius: 8px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.btn-add:hover {
|
||
background-color: #0b5ed7;
|
||
}
|
||
</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">
|
||
|
||
<!-- HEADER INFO GENERALI -->
|
||
<div class="card p-3 mb-3">
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<h5 class="mb-0" id="hNomeUscita">Scheda Mescola</h5>
|
||
<button type="button" class="btn back-dashboard" onclick="location.href='mescole.php'">
|
||
↩️ Torna a Gestione Mescole
|
||
</button>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row g-3">
|
||
<div class="col-md-2">
|
||
<div class="info-label">ID</div>
|
||
<div class="info-value" id="hId">-</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="info-label">Nome Interno</div>
|
||
<div class="info-value" id="hNome">-</div>
|
||
</div>
|
||
<div class="col-md-3">
|
||
<div class="info-label">Q.tà Totale</div>
|
||
<div class="info-value" id="hQty">-</div>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<div class="info-label">Stato</div>
|
||
<div class="info-value" id="hStato">-</div>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<div class="info-label">Linee Associate</div>
|
||
<div class="info-value" id="hLinee">-</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- TAB FILE PER CATEGORIA -->
|
||
<div class="card p-3">
|
||
<div class="card-body">
|
||
<ul class="nav nav-tabs" id="fileTabs" role="tablist"></ul>
|
||
<div class="tab-content pt-3" id="fileTabsContent"></div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<?php include('include/footer.php'); ?>
|
||
</div>
|
||
|
||
<!-- MODALE AGGIUNGI FILE -->
|
||
<div class="modal fade" id="addFileModal" 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 File</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="addFileForm">
|
||
<input type="hidden" id="fCategoria">
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">Titolo File</label>
|
||
<input type="text" class="form-control" id="fTitolo" required>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label fw-semibold">File</label>
|
||
<input type="file" class="form-control" id="fFile" required>
|
||
</div>
|
||
|
||
<div class="text-center">
|
||
<button type="submit" class="btn btn-add">💾 Carica File</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php include('jsinclude.php'); ?>
|
||
|
||
<script>
|
||
const idMescola = new URLSearchParams(window.location.search).get('id');
|
||
let CATEGORIE = {};
|
||
|
||
if (!idMescola) {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Errore',
|
||
text: 'ID mescola mancante'
|
||
}).then(() => location.href = 'mescole.php');
|
||
}
|
||
|
||
function fmtQty(n) {
|
||
return Number(n || 0).toLocaleString('it-IT', {
|
||
minimumFractionDigits: 3,
|
||
maximumFractionDigits: 3
|
||
});
|
||
}
|
||
|
||
function loadGeneral() {
|
||
fetch('get_mescola_general.php?id=' + encodeURIComponent(idMescola))
|
||
.then(r => r.json())
|
||
.then(res => {
|
||
if (!res.success) {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Errore',
|
||
text: res.message
|
||
}).then(() => location.href = 'mescole.php');
|
||
return;
|
||
}
|
||
const d = res.data;
|
||
document.title = 'Scheda Mescola - ' + d.nomeuscita;
|
||
$('#hNomeUscita').text('🧪 ' + d.nomeuscita);
|
||
$('#hId').text(d.id);
|
||
$('#hNome').text(d.nome || '-');
|
||
$('#hQty').text(fmtQty(d.qty_totale));
|
||
$('#hStato').html(
|
||
Number(d.is_active) === 1 ?
|
||
"<span class='badge bg-success'>Attiva</span>" :
|
||
"<span class='badge bg-secondary'>Inattiva</span>"
|
||
);
|
||
$('#hLinee').text(d.linee || 'Nessuna');
|
||
});
|
||
}
|
||
|
||
function buildTabs() {
|
||
fetch('get_mescola_files.php?id=' + encodeURIComponent(idMescola))
|
||
.then(r => r.json())
|
||
.then(res => {
|
||
if (!res.success) return;
|
||
CATEGORIE = res.categorie;
|
||
|
||
const tabsUl = $('#fileTabs');
|
||
const tabsContent = $('#fileTabsContent');
|
||
tabsUl.empty();
|
||
tabsContent.empty();
|
||
|
||
let first = true;
|
||
Object.keys(CATEGORIE).forEach(slug => {
|
||
const label = CATEGORIE[slug];
|
||
const activeTab = first ? 'active' : '';
|
||
const activePane = first ? 'show active' : '';
|
||
|
||
tabsUl.append(`
|
||
<li class="nav-item" role="presentation">
|
||
<button class="nav-link ${activeTab}" id="tab-${slug}" data-bs-toggle="tab"
|
||
data-bs-target="#pane-${slug}" type="button" role="tab">
|
||
${label}
|
||
</button>
|
||
</li>
|
||
`);
|
||
|
||
tabsContent.append(`
|
||
<div class="tab-pane fade ${activePane}" id="pane-${slug}" role="tabpanel">
|
||
<div class="d-flex justify-content-end mb-2">
|
||
<button class="btn btn-add btn-sm add-file-btn" data-categoria="${slug}">
|
||
➕ Aggiungi File
|
||
</button>
|
||
</div>
|
||
<div class="table-responsive">
|
||
<table class="table table-striped align-middle text-center" id="table-${slug}">
|
||
<thead class="table-light">
|
||
<tr>
|
||
<th>Titolo</th>
|
||
<th>Nome File</th>
|
||
<th>Caricato il</th>
|
||
<th>Azioni</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
`);
|
||
|
||
first = false;
|
||
});
|
||
|
||
// popola ogni tab con i file già caricati
|
||
Object.keys(CATEGORIE).forEach(slug => loadFilesForCategory(slug));
|
||
});
|
||
}
|
||
|
||
function loadFilesForCategory(slug) {
|
||
fetch('get_mescola_files.php?id=' + encodeURIComponent(idMescola) + '&categoria=' + encodeURIComponent(slug))
|
||
.then(r => r.json())
|
||
.then(res => {
|
||
const tbody = $('#table-' + slug + ' tbody');
|
||
tbody.empty();
|
||
|
||
if (!res.success || res.rows.length === 0) {
|
||
tbody.append(`<tr>
|
||
<td class="text-muted" colspan="4">Nessun file caricato in questa categoria</td>
|
||
</tr>`);
|
||
return;
|
||
}
|
||
|
||
res.rows.forEach(f => {
|
||
tbody.append(`
|
||
<tr>
|
||
<td>${f.titolo}</td>
|
||
<td><a href="${f.url}" target="_blank" rel="noopener">${f.original_filename}</a></td>
|
||
<td>${f.uploaded_at}</td>
|
||
<td>
|
||
<a class="btn btn-sm btn-outline-primary" href="${f.url}" target="_blank" rel="noopener">⬇️ Scarica</a>
|
||
<button class="btn btn-sm btn-outline-danger del-file-btn" data-id="${f.id}" data-categoria="${slug}">🗑️ Elimina</button>
|
||
</td>
|
||
</tr>
|
||
`);
|
||
});
|
||
});
|
||
}
|
||
|
||
$(document).on('click', '.add-file-btn', function() {
|
||
$('#fCategoria').val($(this).data('categoria'));
|
||
$('#fTitolo').val('');
|
||
$('#fFile').val('');
|
||
$('#addFileModal').modal('show');
|
||
});
|
||
|
||
$('#addFileForm').on('submit', function(e) {
|
||
e.preventDefault();
|
||
|
||
const categoria = $('#fCategoria').val();
|
||
const titolo = $('#fTitolo').val().trim();
|
||
const fileInput = document.getElementById('fFile');
|
||
|
||
if (!fileInput.files.length) {
|
||
Swal.fire({
|
||
icon: 'warning',
|
||
title: 'Attenzione',
|
||
text: 'Seleziona un file'
|
||
});
|
||
return;
|
||
}
|
||
|
||
const formData = new FormData();
|
||
formData.append('idmescola', idMescola);
|
||
formData.append('categoria', categoria);
|
||
formData.append('titolo', titolo);
|
||
formData.append('file', fileInput.files[0]);
|
||
|
||
fetch('save_mescola_file.php', {
|
||
method: 'POST',
|
||
body: formData
|
||
})
|
||
.then(r => r.json())
|
||
.then(res => {
|
||
if (res.success) {
|
||
$('#addFileModal').modal('hide');
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'File caricato!'
|
||
});
|
||
loadFilesForCategory(categoria);
|
||
} else {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Errore',
|
||
text: res.message || 'Upload non riuscito'
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
$(document).on('click', '.del-file-btn', function() {
|
||
const id = $(this).data('id');
|
||
const categoria = $(this).data('categoria');
|
||
|
||
Swal.fire({
|
||
title: 'Eliminare il file?',
|
||
icon: 'warning',
|
||
showCancelButton: true,
|
||
confirmButtonText: 'Sì, elimina',
|
||
cancelButtonText: 'Annulla',
|
||
confirmButtonColor: '#d33'
|
||
}).then(res => {
|
||
if (!res.isConfirmed) return;
|
||
|
||
fetch('delete_mescola_file.php', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/x-www-form-urlencoded'
|
||
},
|
||
body: `id=${encodeURIComponent(id)}`
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
loadFilesForCategory(categoria);
|
||
} else {
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Errore',
|
||
text: data.message || 'Cancellazione non riuscita'
|
||
});
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
$(document).ready(function() {
|
||
loadGeneral();
|
||
buildTabs();
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
|
||
</html>
|