added files for mescole
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
final class CreateMescoleFilesTable extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function change(): void
|
||||||
|
{
|
||||||
|
$table = $this->table('mescole_files', [
|
||||||
|
'id' => 'id',
|
||||||
|
'signed' => true,
|
||||||
|
'engine' => 'InnoDB',
|
||||||
|
'charset' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_general_ci',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$table
|
||||||
|
->addColumn('idmescola', 'integer', [
|
||||||
|
'signed' => true,
|
||||||
|
'null' => false,
|
||||||
|
])
|
||||||
|
->addColumn('categoria', 'string', [
|
||||||
|
'limit' => 100,
|
||||||
|
'null' => false,
|
||||||
|
'comment' => 'slug categoria: schede_tecniche, certificati_analisi, ...',
|
||||||
|
])
|
||||||
|
->addColumn('titolo', 'string', [
|
||||||
|
'limit' => 255,
|
||||||
|
'null' => false,
|
||||||
|
])
|
||||||
|
->addColumn('filename', 'string', [
|
||||||
|
'limit' => 255,
|
||||||
|
'null' => false,
|
||||||
|
'comment' => 'nome fisico del file salvato su disco (random, non l\'originale)',
|
||||||
|
])
|
||||||
|
->addColumn('original_filename', 'string', [
|
||||||
|
'limit' => 255,
|
||||||
|
'null' => false,
|
||||||
|
])
|
||||||
|
->addColumn('mime_type', 'string', [
|
||||||
|
'limit' => 150,
|
||||||
|
'null' => true,
|
||||||
|
])
|
||||||
|
->addColumn('filesize', 'integer', [
|
||||||
|
'null' => true,
|
||||||
|
])
|
||||||
|
->addColumn('uploaded_at', 'datetime', [
|
||||||
|
'default' => 'CURRENT_TIMESTAMP',
|
||||||
|
])
|
||||||
|
->addIndex(['idmescola'])
|
||||||
|
->addIndex(['categoria'])
|
||||||
|
->addForeignKey('idmescola', 'mescole', 'id', [
|
||||||
|
'delete' => 'CASCADE',
|
||||||
|
'update' => 'CASCADE',
|
||||||
|
])
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Categorie disponibili per i file associati alle mescole.
|
||||||
|
* Chiave = slug salvato nel DB (colonna mescole_files.categoria)
|
||||||
|
* Valore = etichetta mostrata in UI
|
||||||
|
*
|
||||||
|
* Per aggiungere una nuova categoria in futuro basta aggiungere
|
||||||
|
* una riga qui, senza toccare il database.
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
'schede_tecniche' => 'Schede Tecniche',
|
||||||
|
'certificati_analisi' => 'Certificati di Analisi',
|
||||||
|
];
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$id = isset($_POST['id']) ? (int)$_POST['id'] : 0;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT idmescola, filename FROM mescole_files WHERE id = ?");
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'File non trovato']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$del = $pdo->prepare("DELETE FROM mescole_files WHERE id = ?");
|
||||||
|
$del->execute([$id]);
|
||||||
|
|
||||||
|
$path = __DIR__ . '/uploads/mescole/' . $row['idmescola'] . '/' . $row['filename'];
|
||||||
|
if (is_file($path)) {
|
||||||
|
@unlink($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore database: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$idmescola = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
$categoria = $_GET['categoria'] ?? null;
|
||||||
|
|
||||||
|
if ($idmescola <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID mescola non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$categorie = require __DIR__ . '/config/mescole_file_categories.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$sql = "SELECT id, idmescola, categoria, titolo, filename, original_filename, mime_type, filesize, uploaded_at
|
||||||
|
FROM mescole_files
|
||||||
|
WHERE idmescola = ?";
|
||||||
|
$params = [$idmescola];
|
||||||
|
|
||||||
|
if (!empty($categoria)) {
|
||||||
|
$sql .= " AND categoria = ?";
|
||||||
|
$params[] = $categoria;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= " ORDER BY uploaded_at DESC";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
|
||||||
|
$rows = [];
|
||||||
|
while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||||
|
$r['categoria_label'] = $categorie[$r['categoria']] ?? $r['categoria'];
|
||||||
|
$r['url'] = 'uploads/mescole/' . $r['idmescola'] . '/' . $r['filename'];
|
||||||
|
$rows[] = $r;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'rows' => $rows, 'categorie' => $categorie]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore server: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$sql = "
|
||||||
|
SELECT
|
||||||
|
m.id,
|
||||||
|
m.nome,
|
||||||
|
m.nomeuscita,
|
||||||
|
m.is_active,
|
||||||
|
IFNULL(q.qty_totale, 0) AS qty_totale,
|
||||||
|
GROUP_CONCAT(DISTINCT pl.name SEPARATOR ', ') AS linee
|
||||||
|
FROM mescole m
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT idmescola, SUM(qty) AS qty_totale
|
||||||
|
FROM mescole_supplier_lots
|
||||||
|
GROUP BY idmescola
|
||||||
|
) q ON q.idmescola = m.id
|
||||||
|
LEFT JOIN mescole_lines ml ON m.id = ml.idmescola
|
||||||
|
LEFT JOIN production_lines pl ON ml.idlinea = pl.id
|
||||||
|
WHERE m.id = ?
|
||||||
|
GROUP BY m.id
|
||||||
|
";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute([$id]);
|
||||||
|
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$row) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Mescola non trovata']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'data' => $row]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore database: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
+276
-20
@@ -106,6 +106,17 @@
|
|||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tabellaMescole td:nth-child(2) a {
|
||||||
|
color: #1f2d3d;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabellaMescole td:nth-child(2) a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
/* Q.tà totale */
|
/* Q.tà totale */
|
||||||
#tabellaMescole th:nth-child(3),
|
#tabellaMescole th:nth-child(3),
|
||||||
#tabellaMescole td:nth-child(3) {
|
#tabellaMescole td:nth-child(3) {
|
||||||
@@ -130,8 +141,27 @@
|
|||||||
/* Azioni */
|
/* Azioni */
|
||||||
#tabellaMescole th:nth-child(6),
|
#tabellaMescole th:nth-child(6),
|
||||||
#tabellaMescole td:nth-child(6) {
|
#tabellaMescole td:nth-child(6) {
|
||||||
width: 330px;
|
width: 190px;
|
||||||
max-width: 330px;
|
max-width: 190px;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.azioni-cell {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.azioni-cell .btn {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
padding: 0;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
@@ -246,33 +276,50 @@
|
|||||||
$toggleText = $isActive ? "Disattiva" : "Attiva";
|
$toggleText = $isActive ? "Disattiva" : "Attiva";
|
||||||
$toggleClass = $isActive ? "btn-outline-warning" : "btn-outline-success";
|
$toggleClass = $isActive ? "btn-outline-warning" : "btn-outline-success";
|
||||||
|
|
||||||
|
$nomeUscitaSafe = htmlspecialchars($row['nomeuscita']);
|
||||||
|
|
||||||
echo "<tr data-mescola-id='{$row['id']}'>
|
echo "<tr data-mescola-id='{$row['id']}'>
|
||||||
<td>{$row['id']}</td>
|
<td>{$row['id']}</td>
|
||||||
<td>" . htmlspecialchars($row['nomeuscita']) . "</td>
|
<td>
|
||||||
|
<a href='scheda_mescola.php?id={$row['id']}' title='Apri scheda mescola'>
|
||||||
|
{$nomeUscitaSafe}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td><span class='fw-semibold'>{$qtyTot}</span></td>
|
<td><span class='fw-semibold'>{$qtyTot}</span></td>
|
||||||
<td>{$linee}</td>
|
<td>{$linee}</td>
|
||||||
<td>{$badge}</td>
|
<td>{$badge}</td>
|
||||||
<td>
|
<td class='azioni-cell'>
|
||||||
<button class='btn btn-sm btn-outline-dark associa-fornitori'
|
<button type='button' class='btn btn-sm btn-outline-dark associa-fornitori'
|
||||||
data-id='{$row['id']}'
|
data-id='{$row['id']}'
|
||||||
data-nomeuscita='" . htmlspecialchars($row['nomeuscita'], ENT_QUOTES) . "'>
|
data-nomeuscita='" . htmlspecialchars($row['nomeuscita'], ENT_QUOTES) . "'
|
||||||
🧾 Fornitori
|
data-bs-toggle='tooltip' data-bs-placement='top' title='Fornitori / Lotti'>
|
||||||
|
🧾
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button class='btn btn-sm btn-outline-primary associa-linee'
|
<button type='button' class='btn btn-sm btn-outline-info associa-file'
|
||||||
data-id='{$row['id']}'>
|
|
||||||
⚙️ Linee
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class='btn btn-sm {$toggleClass} toggle-active'
|
|
||||||
data-id='{$row['id']}'>
|
|
||||||
🔁 {$toggleText}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class='btn btn-sm btn-outline-secondary edit-mescola'
|
|
||||||
data-id='{$row['id']}'
|
data-id='{$row['id']}'
|
||||||
data-nomeuscita='" . htmlspecialchars($row['nomeuscita'], ENT_QUOTES) . "'>
|
data-nomeuscita='" . htmlspecialchars($row['nomeuscita'], ENT_QUOTES) . "'
|
||||||
✏️ Modifica
|
data-bs-toggle='tooltip' data-bs-placement='top' title='File'>
|
||||||
|
📁
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type='button' class='btn btn-sm btn-outline-primary associa-linee'
|
||||||
|
data-id='{$row['id']}'
|
||||||
|
data-bs-toggle='tooltip' data-bs-placement='top' title='Linee Associate'>
|
||||||
|
⚙️
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type='button' class='btn btn-sm {$toggleClass} toggle-active'
|
||||||
|
data-id='{$row['id']}'
|
||||||
|
data-bs-toggle='tooltip' data-bs-placement='top' title='{$toggleText}'>
|
||||||
|
🔁
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button type='button' class='btn btn-sm btn-outline-secondary edit-mescola'
|
||||||
|
data-id='{$row['id']}'
|
||||||
|
data-nomeuscita='" . htmlspecialchars($row['nomeuscita'], ENT_QUOTES) . "'
|
||||||
|
data-bs-toggle='tooltip' data-bs-placement='top' title='Modifica'>
|
||||||
|
✏️
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>";
|
</tr>";
|
||||||
@@ -444,6 +491,56 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- MODALE FILE / REPOSITORY -->
|
||||||
|
<div class="modal fade" id="associaFileModal" 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">📁 File - <span id="fNomeUscita"></span></h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<input type="hidden" id="fIdMescola">
|
||||||
|
|
||||||
|
<div class="row g-2 align-items-end mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Categoria</label>
|
||||||
|
<select class="form-select" id="fCategoria"></select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">Titolo File</label>
|
||||||
|
<input type="text" class="form-control" id="fTitolo">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label fw-semibold">File</label>
|
||||||
|
<input type="file" class="form-control" id="fFileInput">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-12 text-end">
|
||||||
|
<button class="btn btn-add" id="fSaveBtn">➕ Carica File</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped align-middle text-center" id="fTable">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>Categoria</th>
|
||||||
|
<th>Titolo</th>
|
||||||
|
<th>Nome File</th>
|
||||||
|
<th>Caricato il</th>
|
||||||
|
<th>Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php include('jsinclude.php'); ?>
|
<?php include('jsinclude.php'); ?>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -463,6 +560,8 @@
|
|||||||
language: {
|
language: {
|
||||||
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
|
url: 'https://cdn.datatables.net/plug-ins/1.13.6/i18n/it-IT.json'
|
||||||
}
|
}
|
||||||
|
}).on('draw.dt', function() {
|
||||||
|
initTooltips();
|
||||||
});
|
});
|
||||||
|
|
||||||
// filter reload
|
// filter reload
|
||||||
@@ -472,8 +571,19 @@
|
|||||||
url.searchParams.set('active', v);
|
url.searchParams.set('active', v);
|
||||||
window.location.href = url.toString();
|
window.location.href = url.toString();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
initTooltips();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* -------- TOOLTIP BOOTSTRAP SUI PULSANTI ICONA -------- */
|
||||||
|
function initTooltips() {
|
||||||
|
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => {
|
||||||
|
const existing = bootstrap.Tooltip.getInstance(el);
|
||||||
|
if (existing) existing.dispose();
|
||||||
|
new bootstrap.Tooltip(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/* -------- TOGGLE ACTIVE -------- */
|
/* -------- TOGGLE ACTIVE -------- */
|
||||||
$(document).on('click', '.toggle-active', function() {
|
$(document).on('click', '.toggle-active', function() {
|
||||||
const id = $(this).data('id');
|
const id = $(this).data('id');
|
||||||
@@ -882,6 +992,152 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ============================
|
||||||
|
// FILE / REPOSITORY
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
function fLoadRows(idMescola) {
|
||||||
|
fetch("get_mescola_files.php?id=" + encodeURIComponent(idMescola))
|
||||||
|
.then(r => r.json())
|
||||||
|
.then(data => {
|
||||||
|
// popola dropdown categorie (solo la prima volta che arrivano)
|
||||||
|
const sel = $("#fCategoria");
|
||||||
|
if (sel.children().length === 0 && data.categorie) {
|
||||||
|
Object.keys(data.categorie).forEach(slug => {
|
||||||
|
sel.append(`<option value="${slug}">${data.categorie[slug]}</option>`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const tbody = $("#fTable tbody");
|
||||||
|
tbody.empty();
|
||||||
|
|
||||||
|
if (!data.success || !Array.isArray(data.rows) || data.rows.length === 0) {
|
||||||
|
tbody.append(`<tr>
|
||||||
|
<td class="text-muted" colspan="5">Nessun file caricato</td>
|
||||||
|
</tr>`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.rows.forEach(f => {
|
||||||
|
tbody.append(`
|
||||||
|
<tr>
|
||||||
|
<td>${f.categoria_label}</td>
|
||||||
|
<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">⬇️</a>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger f-del" data-id="${f.id}">🗑️</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open modal
|
||||||
|
$(document).on("click", ".associa-file", function() {
|
||||||
|
const idMescola = $(this).data("id");
|
||||||
|
const nomeUscita = $(this).data("nomeuscita");
|
||||||
|
|
||||||
|
$("#fIdMescola").val(idMescola);
|
||||||
|
$("#fNomeUscita").text(nomeUscita);
|
||||||
|
$("#fTitolo").val("");
|
||||||
|
$("#fFileInput").val("");
|
||||||
|
|
||||||
|
$("#associaFileModal").modal("show");
|
||||||
|
fLoadRows(idMescola);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Upload file
|
||||||
|
$("#fSaveBtn").on("click", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const idMescola = $("#fIdMescola").val();
|
||||||
|
const categoria = $("#fCategoria").val();
|
||||||
|
const titolo = $("#fTitolo").val().trim();
|
||||||
|
const fileInput = document.getElementById("fFileInput");
|
||||||
|
|
||||||
|
if (!titolo) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: "warning",
|
||||||
|
title: "Attenzione",
|
||||||
|
text: "Il titolo del file è obbligatorio"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fileInput.files.length) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: "warning",
|
||||||
|
title: "Attenzione",
|
||||||
|
text: "Seleziona un file da caricare"
|
||||||
|
});
|
||||||
|
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(data => {
|
||||||
|
if (data.success) {
|
||||||
|
$("#fTitolo").val("");
|
||||||
|
$("#fFileInput").val("");
|
||||||
|
fLoadRows(idMescola);
|
||||||
|
} else {
|
||||||
|
Swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Errore",
|
||||||
|
text: data.message || "Upload non riuscito"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete file
|
||||||
|
$(document).on("click", ".f-del", function() {
|
||||||
|
const id = $(this).data("id");
|
||||||
|
const idMescola = $("#fIdMescola").val();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
fLoadRows(idMescola);
|
||||||
|
} else {
|
||||||
|
Swal.fire({
|
||||||
|
icon: "error",
|
||||||
|
title: "Errore",
|
||||||
|
text: data.message || "Cancellazione non riuscita"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
include('include/headscript.php');
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
$categorie = require __DIR__ . '/config/mescole_file_categories.php';
|
||||||
|
|
||||||
|
$idmescola = isset($_POST['idmescola']) ? (int)$_POST['idmescola'] : 0;
|
||||||
|
$categoria = $_POST['categoria'] ?? '';
|
||||||
|
$titolo = trim($_POST['titolo'] ?? '');
|
||||||
|
|
||||||
|
if ($idmescola <= 0) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'ID mescola non valido']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (!array_key_exists($categoria, $categorie)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Categoria non valida']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($titolo === '') {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Il titolo del file è obbligatorio']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'File mancante o upload non riuscito']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Validazioni di sicurezza sul file ---
|
||||||
|
$allowedExt = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'jpg', 'jpeg', 'png'];
|
||||||
|
$maxSize = 15 * 1024 * 1024; // 15 MB
|
||||||
|
|
||||||
|
$originalName = $_FILES['file']['name'];
|
||||||
|
$tmpPath = $_FILES['file']['tmp_name'];
|
||||||
|
$size = (int)$_FILES['file']['size'];
|
||||||
|
$ext = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
if (!in_array($ext, $allowedExt, true)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Estensione file non consentita (' . $ext . ')']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($size <= 0 || $size > $maxSize) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Il file supera la dimensione massima di 15MB']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$finfo = finfo_open(FILEINFO_MIME_TYPE);
|
||||||
|
$mimeType = finfo_file($finfo, $tmpPath);
|
||||||
|
finfo_close($finfo);
|
||||||
|
|
||||||
|
// Cartella dedicata per mescola: uploads/mescole/{idmescola}/
|
||||||
|
$destDir = __DIR__ . '/uploads/mescole/' . $idmescola . '/';
|
||||||
|
if (!is_dir($destDir)) {
|
||||||
|
mkdir($destDir, 0775, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nome fisico casuale: evita collisioni e path traversal
|
||||||
|
$storedName = bin2hex(random_bytes(16)) . '.' . $ext;
|
||||||
|
$destPath = $destDir . $storedName;
|
||||||
|
|
||||||
|
if (!move_uploaded_file($tmpPath, $destPath)) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Impossibile salvare il file sul server']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = DBHandlerSelect::getInstance();
|
||||||
|
$pdo = $db->getConnection();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("
|
||||||
|
INSERT INTO mescole_files (idmescola, categoria, titolo, filename, original_filename, mime_type, filesize, uploaded_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
|
||||||
|
");
|
||||||
|
$stmt->execute([$idmescola, $categoria, $titolo, $storedName, $originalName, $mimeType, $size]);
|
||||||
|
|
||||||
|
echo json_encode(['success' => true, 'id' => $pdo->lastInsertId()]);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
// rollback file se il DB fallisce
|
||||||
|
@unlink($destPath);
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Errore database: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
@@ -0,0 +1,397 @@
|
|||||||
|
<?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>
|
||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user