Merge feature/quotations into main, prefer quotations version for modal_parts.php and parts.js

This commit is contained in:
Claudio 2025-09-22 08:24:05 +02:00
commit 960832efb1
15 changed files with 1724 additions and 754 deletions

View File

@ -32,3 +32,4 @@ $langdatatables = [
"paginate_next" => "Next", "paginate_next" => "Next",
"paginate_previous" => "Previous" "paginate_previous" => "Previous"
]; ];
$quotationstitle = "Quotations";

View File

@ -0,0 +1,28 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$data = json_decode(file_get_contents('php://input'), true);
$partId = $data['part_id'] ?? null;
if (!$partId) {
echo json_encode(['success' => false, 'message' => 'ID parte mancante']);
exit;
}
try {
$stmt = $pdo->prepare("DELETE FROM identification_parts WHERE id = :part_id");
$stmt->execute([':part_id' => $partId]);
$rowCount = $stmt->rowCount();
if ($rowCount > 0) {
echo json_encode(['success' => true, 'message' => 'Parte eliminata con successo']);
} else {
echo json_encode(['success' => false, 'message' => 'Nessuna parte trovata con ID ' . $partId]);
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nell\'eliminazione: ' . $e->getMessage()]);
}

View File

@ -41,7 +41,21 @@
</li> </li>
</ul> </ul>
</li>--> </li>
<li>
<a href="javascript:;" class="has-arrow">
<div class="parent-icon"><i class="bx bx-category"></i>
</div>
<div class="menu-title">Other Functions</div>
</a>
<ul>
<li> <a href="quotations.php"><i class='bx bx-radio-circle'></i><?php echo $quotationstitle; ?></a>
</li>
</ul>
</li>

View File

@ -0,0 +1,23 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$idquotations = $_GET['idquotations'] ?? null;
if (!$idquotations) {
echo json_encode(['success' => false, 'message' => 'ID quotations mancante']);
exit;
}
try {
$stmt = $pdo->prepare("SELECT id, idquotations, part_number, part_description FROM identification_parts WHERE idquotations = :idquotations ORDER BY part_number ASC");
$stmt->execute([':idquotations' => $idquotations]);
$parts = $stmt->fetchAll();
echo json_encode(['success' => true, 'parts' => $parts]);
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
}

View File

@ -0,0 +1,33 @@
<?php
// load_photo_quotation.php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$idquotations = isset($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
if (!$idquotations) {
echo json_encode(['success' => false, 'message' => 'ID quotation mancante']);
exit;
}
try {
// Seleziona le foto per il dato idquotations dalla tabella datadb_photos
$stmt = $pdo->prepare("SELECT id, file_path FROM datadb_photos WHERE idquotations = ?");
$stmt->execute([$idquotations]);
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($photos && count($photos) > 0) {
$photoPaths = array_map(function ($photo) {
return '../photostrf/' . $photo['file_path'];
}, $photos);
echo json_encode(['success' => true, 'photos' => $photoPaths]);
} else {
echo json_encode(['success' => false, 'message' => 'Nessuna foto trovata']);
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nel caricamento: ' . $e->getMessage()]);
}

View File

@ -1,4 +1,4 @@
<!-- Modal modificato con pulsante per riconoscimento vocale --> <!-- Modal modificato con pulsante per riconoscimento vocale e download -->
<div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true"> <div class="modal fade" id="partsModal" tabindex="-1" aria-labelledby="partsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl" style="max-width: 80% !important; width: 80% !important;"> <div class="modal-dialog modal-xl" style="max-width: 80% !important; width: 80% !important;">
<div class="modal-content"> <div class="modal-content">
@ -44,13 +44,14 @@
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<h6>Foto del Campione</h6> <h6>Foto del Campione</h6>
<div id="photoSelectorContainer" style="display: none;"> <div style="display: flex; align-items: center; margin-bottom: 10px;">
<!-- Dropdown or buttons for photo selection will appear here --> <button type="button" class="btn btn-primary btn-sm" id="downloadPhotoBtn" style="padding: 0.1rem 0.5rem; font-size: 0.8rem; margin-right: 10px;"><i class="fas fa-download"></i> </button>
<div id="photoSelectorContainer" style="display: none;"></div>
</div> </div>
<div style="position: relative; width: 100%; min-height: 400px;"> <div style="position: relative; width: 100%; min-height: 400px;">
<img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;"> <img id="samplePhoto" src="" alt="Foto del campione" style="max-width: 100%; max-height: 100%; object-fit: contain; position: absolute; top: 0; left: 0;">
<canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas> <canvas id="photoCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></canvas>
<div id="descriptionList" class="draggable-description" style="display: none;"></div> <canvas id="overlayCanvas" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000;"></canvas> <!-- Nuovo canvas per Fabric.js -->
<div id="markerContainer"></div> <div id="markerContainer"></div>
</div> </div>
</div> </div>
@ -97,6 +98,14 @@
font-size: 0.6rem !important; font-size: 0.6rem !important;
} }
#partsModal {
z-index: 1060 !important;
}
#partsModal .modal-backdrop {
z-index: 1055 !important;
}
#partsModal .modal-content { #partsModal .modal-content {
width: 100% !important; width: 100% !important;
max-width: 100% !important; max-width: 100% !important;
@ -127,12 +136,33 @@
position: absolute; position: absolute;
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
padding: 5px; padding: 5px;
font-size: 10px;
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
color: #000000; color: #000000;
cursor: move; cursor: move;
user-select: none; user-select: none;
z-index: 1000; z-index: 1000;
min-width: 100px;
min-height: 50px;
overflow: visible;
border: 1px solid #ccc;
}
.draggable-description.active-interaction {
border: 2px dashed #000;
}
.draggable-description div {
white-space: nowrap;
}
.resize-handle {
position: absolute;
bottom: 0;
right: 0;
width: 10px;
height: 10px;
background: #888;
cursor: se-resize;
} }
.draggable-marker { .draggable-marker {
@ -162,21 +192,17 @@
font-size: 0.8rem; font-size: 0.8rem;
} }
/* Normale Save button */
#savePhotoBtn { #savePhotoBtn {
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
} }
/* Unsaved changes */
#savePhotoBtn.unsaved { #savePhotoBtn.unsaved {
background-color: #dc3545 !important; background-color: #dc3545 !important;
/* Rosso */
border-color: #dc3545 !important; border-color: #dc3545 !important;
color: white !important; color: white !important;
animation: pulse 1.2s infinite; animation: pulse 1.2s infinite;
} }
/* Animazione pulsante */
@keyframes pulse { @keyframes pulse {
0% { 0% {
box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7);
@ -191,7 +217,6 @@
} }
} }
/* Stile per il selettore personalizzato dei colori */
.color-picker-container { .color-picker-container {
position: relative; position: relative;
display: inline-block; display: inline-block;

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +1,21 @@
document.addEventListener("DOMContentLoaded", function () { document.addEventListener("DOMContentLoaded", function () {
// Funzione per caricare il contenuto del popup // Funzione per caricare il contenuto del popup
async function loadPopupContent(iddatadb) { async function loadPopupContent(iddatadb, idquotations) {
const popupContent = document.getElementById("popupContent"); const popupContent = document.getElementById("popupContent");
if (!popupContent) { if (!popupContent) {
console.error("Elemento popupContent non trovato"); console.error("Elemento popupContent non trovato");
return; return;
} }
try { try {
const response = await fetch( const endpoint = idquotations
`photos_popup.php?iddatadb=${iddatadb}`, ? `photos_popup.php?idquotations=${idquotations}`
); : `photos_popup.php?iddatadb=${iddatadb}`;
console.log("Caricamento popup da:", endpoint);
const response = await fetch(endpoint);
if (!response.ok) if (!response.ok)
throw new Error("Errore nella risposta del server"); throw new Error("Errore nella risposta del server");
popupContent.innerHTML = await response.text(); popupContent.innerHTML = await response.text();
attachPhotoEventListeners(iddatadb); attachPhotoEventListeners(iddatadb, idquotations);
} catch (error) { } catch (error) {
popupContent.innerHTML = `<p>Errore durante il caricamento: ${error.message}</p>`; popupContent.innerHTML = `<p>Errore durante il caricamento: ${error.message}</p>`;
console.error("Errore in loadPopupContent:", error); console.error("Errore in loadPopupContent:", error);
@ -21,7 +23,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
// Funzione per gestire la webcam // Funzione per gestire la webcam
function setupWebcam(iddatadb) { function setupWebcam(iddatadb, idquotations) {
const openWebcamBtn = document.getElementById("openWebcamBtn"); const openWebcamBtn = document.getElementById("openWebcamBtn");
const webcamArea = document.getElementById("webcamArea"); const webcamArea = document.getElementById("webcamArea");
const webcamVideo = document.getElementById("webcamVideo"); const webcamVideo = document.getElementById("webcamVideo");
@ -158,7 +160,7 @@ document.addEventListener("DOMContentLoaded", function () {
if (loader) { if (loader) {
loader.style.display = "flex"; loader.style.display = "flex";
} }
await handleFiles([file], iddatadb); await handleFiles([file], iddatadb, idquotations);
if (stream) { if (stream) {
stream.getTracks().forEach((track) => track.stop()); stream.getTracks().forEach((track) => track.stop());
stream = null; stream = null;
@ -171,7 +173,7 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
} }
async function handleFiles(files, iddatadb) { async function handleFiles(files, iddatadb, idquotations) {
const loader = document.getElementById("loader"); const loader = document.getElementById("loader");
if (!loader) { if (!loader) {
console.error("Elemento loader non trovato"); console.error("Elemento loader non trovato");
@ -193,7 +195,12 @@ document.addEventListener("DOMContentLoaded", function () {
const formData = new FormData(); const formData = new FormData();
formData.append("photo", file); formData.append("photo", file);
formData.append("iddatadb", iddatadb); if (idquotations) {
formData.append("idquotations", idquotations);
} else {
formData.append("iddatadb", iddatadb);
}
try { try {
const response = await fetch("upload_photo.php", { const response = await fetch("upload_photo.php", {
method: "POST", method: "POST",
@ -201,7 +208,7 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
const result = await response.json(); const result = await response.json();
if (result.success) { if (result.success) {
loadPopupContent(iddatadb); loadPopupContent(iddatadb, idquotations);
} else { } else {
alert("Errore durante il caricamento: " + result.message); alert("Errore durante il caricamento: " + result.message);
} }
@ -213,7 +220,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
} }
function attachPhotoEventListeners(iddatadb) { function attachPhotoEventListeners(iddatadb, idquotations) {
const dropArea = document.getElementById("dropArea"); const dropArea = document.getElementById("dropArea");
const photoInput = document.getElementById("photoInput"); const photoInput = document.getElementById("photoInput");
const photosModal = document.getElementById("photosModal"); const photosModal = document.getElementById("photosModal");
@ -257,7 +264,7 @@ document.addEventListener("DOMContentLoaded", function () {
(e) => { (e) => {
const files = e.dataTransfer.files; const files = e.dataTransfer.files;
if (files.length > 0) { if (files.length > 0) {
handleFiles(files, iddatadb); handleFiles(files, iddatadb, idquotations);
} }
}, },
false, false,
@ -276,7 +283,7 @@ document.addEventListener("DOMContentLoaded", function () {
(e) => { (e) => {
const files = e.target.files; const files = e.target.files;
if (files.length > 0) { if (files.length > 0) {
handleFiles(files, iddatadb); handleFiles(files, iddatadb, idquotations);
} }
e.target.value = ""; e.target.value = "";
}, },
@ -298,7 +305,7 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
const result = await response.json(); const result = await response.json();
if (result.success) { if (result.success) {
loadPopupContent(iddatadb); loadPopupContent(iddatadb, idquotations);
} else { } else {
alert( alert(
"Errore durante l'eliminazione: " + "Errore durante l'eliminazione: " +
@ -336,7 +343,7 @@ document.addEventListener("DOMContentLoaded", function () {
} }
}); });
setupWebcam(iddatadb); setupWebcam(iddatadb, idquotations);
const createCollageBtn = document.getElementById("createCollageBtn"); const createCollageBtn = document.getElementById("createCollageBtn");
if (createCollageBtn) { if (createCollageBtn) {
@ -869,9 +876,9 @@ document.addEventListener("DOMContentLoaded", function () {
type: "image/jpeg", type: "image/jpeg",
}); });
await handleFiles([file], iddatadb); await handleFiles([file], iddatadb, idquotations);
document.getElementById("collageModal").style.display = "none"; document.getElementById("collageModal").style.display = "none";
loadPopupContent(iddatadb); loadPopupContent(iddatadb, idquotations);
}); });
} }
@ -992,8 +999,14 @@ document.addEventListener("DOMContentLoaded", function () {
if (photosButtons.length && photosModal && closeBtn) { if (photosButtons.length && photosModal && closeBtn) {
photosButtons.forEach((button) => { photosButtons.forEach((button) => {
button.addEventListener("click", function () { button.addEventListener("click", function () {
const iddatadb = this.getAttribute("data-iddatadb"); const iddatadb = this.getAttribute("data-iddatadb") || null;
loadPopupContent(iddatadb); const idquotations =
this.getAttribute("data-idquotations") || null;
console.log("Apertura modale foto con:", {
iddatadb,
idquotations,
});
loadPopupContent(iddatadb, idquotations);
photosModal.style.display = "block"; photosModal.style.display = "block";
document.querySelector(".overlay").style.display = "none"; document.querySelector(".overlay").style.display = "none";
}); });

View File

@ -17,69 +17,131 @@ use Endroid\QrCode\QrCode;
use Endroid\QrCode\RoundBlockSizeMode; use Endroid\QrCode\RoundBlockSizeMode;
use Endroid\QrCode\Writer\PngWriter; use Endroid\QrCode\Writer\PngWriter;
// Abilita logging per debug
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/photos_popup_debug.log');
// Log iniziale
error_log("Richiesta a photos_popup.php: " . print_r($_GET, true));
// Carica le variabili d'ambiente // Carica le variabili d'ambiente
try { try {
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../'); $dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../../');
$dotenv->load(); $dotenv->load();
} catch (Exception $e) { } catch (Exception $e) {
error_log("Errore nel caricamento del file .env: " . $e->getMessage()); error_log("Errore nel caricamento del file .env: " . $e->getMessage());
echo json_encode(['error' => 'Errore nel caricamento del file di configurazione']); ?>
<div class="popup-content">
<p>Errore: Impossibile caricare il file di configurazione.</p>
</div>
<?php
exit; exit;
} }
// Verifica che BASE_URL sia definito // Verifica che BASE_URL sia definito
if (!isset($_ENV['BASE_URL'])) { if (!isset($_ENV['BASE_URL'])) {
error_log("Errore: la variabile BASE_URL non è definita nel file .env"); error_log("Errore: la variabile BASE_URL non è definita nel file .env");
echo json_encode(['error' => 'Variabile BASE_URL non definita']); ?>
<div class="popup-content">
<p>Errore: Variabile BASE_URL non definita.</p>
</div>
<?php
exit; exit;
} }
$db = DBHandlerSelect::getInstance(); $db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection(); $pdo = $db->getConnection();
// Verifica che l'iddatadb sia stato passato // Verifica che almeno uno degli ID sia passato
if (!isset($_GET['iddatadb']) || empty($_GET['iddatadb'])) { $iddatadb = isset($_GET['iddatadb']) && !empty($_GET['iddatadb']) ? intval($_GET['iddatadb']) : null;
echo json_encode(['error' => 'ID riga non fornito']); $idquotations = isset($_GET['idquotations']) && !empty($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
if (!$iddatadb && !$idquotations) {
error_log("Errore: ID riga o ID quotations non fornito");
?>
<div class="popup-content">
<p>Errore: ID riga o ID quotations non fornito.</p>
</div>
<?php
exit; exit;
} }
$iddatadb = intval($_GET['iddatadb']); if ($iddatadb && $idquotations) {
error_log("Errore: Non è possibile specificare sia iddatadb che idquotations");
// Recupera i dettagli della riga (idriga e sample_code) ?>
$stmt = $pdo->prepare("SELECT iddatadb, sample_code FROM datadb WHERE iddatadb = ?"); <div class="popup-content">
$stmt->execute([$iddatadb]); <p>Errore: Non è possibile specificare sia iddatadb che idquotations.</p>
$row = $stmt->fetch(PDO::FETCH_ASSOC); </div>
<?php
if (!$row) {
echo json_encode(['error' => 'Riga non trovata']);
exit; exit;
} }
$idriga = $row['iddatadb']; // Determina quale ID e tabella usare
$sampleCode = $row['sample_code'] ?? 'Non disponibile'; $paramName = $iddatadb ? 'iddatadb' : 'id'; // Usa 'id' per quotations
$paramValue = $iddatadb ?: $idquotations;
$table = $iddatadb ? 'datadb' : 'quotations';
$field = $iddatadb ? 'sample_code' : 'description'; // Usa 'description' per quotations
$photoTable = 'datadb_photos'; // Usa sempre datadb_photos
$photoParamName = $iddatadb ? 'iddatadb' : 'idquotations'; // Usa 'idquotations' per datadb_photos
// Recupera i dettagli della riga
try {
$stmt = $pdo->prepare("SELECT {$paramName}, {$field} FROM {$table} WHERE {$paramName} = ?");
$stmt->execute([$paramValue]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) {
error_log("Errore: Riga non trovata per {$paramName} = {$paramValue}");
?>
<div class="popup-content">
<p>Errore: Riga non trovata.</p>
</div>
<?php
exit;
}
} catch (Exception $e) {
error_log("Errore query dettagli riga: " . $e->getMessage());
?>
<div class="popup-content">
<p>Errore: Impossibile recuperare i dettagli della riga.</p>
</div>
<?php
exit;
}
$id = $row[$paramName];
$code = $row[$field] ?? 'Non disponibile';
// Recupera le foto associate alla riga // Recupera le foto associate alla riga
$stmt = $pdo->prepare("SELECT id, file_path, file_name, description, uploaded_at FROM datadb_photos WHERE iddatadb = ? ORDER BY uploaded_at DESC"); try {
$stmt->execute([$iddatadb]); $stmt = $pdo->prepare("SELECT id, file_path, file_name, description, uploaded_at FROM {$photoTable} WHERE {$photoParamName} = ? ORDER BY uploaded_at DESC");
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->execute([$paramValue]);
$photos = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Errore query foto: " . $e->getMessage());
$photos = []; // Imposta array vuoto in caso di errore
}
// Definisci il percorso base per le foto // Definisci il percorso base per le foto
$photoBasePath = '../photostrf/'; $photoBasePath = '../photostrf/';
// Usa la variabile d'ambiente BASE_URL // Usa la variabile d'ambiente BASE_URL
$baseUrl = rtrim($_ENV['BASE_URL'], '/'); // Rimuove eventuali slash finali $baseUrl = rtrim($_ENV['BASE_URL'], '/');
$uploadUrl = $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb; $uploadUrl = $iddatadb
? $baseUrl . "/upload_photos_mobile.php?iddatadb=" . $iddatadb
: $baseUrl . "/upload_photos_mobile.php?idquotations=" . $idquotations;
// Genera il QR code con endroid/qr-code 6.0.6 // Genera il QR code con endroid/qr-code 6.0.6
$qrCodeDir = '../photostrf/qrcodes/'; $qrCodeDir = '../photostrf/qrcodes/';
if (!is_dir($qrCodeDir)) { if (!is_dir($qrCodeDir)) {
mkdir($qrCodeDir, 0755, true); mkdir($qrCodeDir, 0755, true);
} }
$qrCodeFile = $qrCodeDir . "qrcode_{$iddatadb}.png"; $qrCodeFile = $qrCodeDir . "qrcode_{$id}.png";
$writer = new PngWriter(); $writer = new PngWriter();
// Crea il QR code usando il costruttore
$qrCode = new QrCode( $qrCode = new QrCode(
data: $uploadUrl, data: $uploadUrl,
encoding: new Encoding('UTF-8'), encoding: new Encoding('UTF-8'),
@ -103,13 +165,13 @@ $result->saveToFile($qrCodeFile);
</div> </div>
</div> </div>
<h3>Manage Photos</h3> <h3>Manage Photos</h3>
<p><strong>ID Row:</strong> <?= htmlspecialchars($idriga) ?></p> <p><strong>ID:</strong> <?= htmlspecialchars($id) ?></p>
<p><strong>Sample Code:</strong> <?= htmlspecialchars($sampleCode) ?></p> <p><strong>Code:</strong> <?= htmlspecialchars($code) ?></p>
<!-- QR Code per il caricamento da mobile --> <!-- QR Code per il caricamento da mobile -->
<div style="text-align: center; margin-bottom: 20px;"> <div style="text-align: center; margin-bottom: 20px;">
<p>Scan the QR Code with the mobile to take photo with camera:</p> <p>Scan the QR Code with the mobile to take photo with camera:</p>
<img src="../photostrf/qrcodes/qrcode_<?= $iddatadb ?>.png" alt="QR Code" style="max-width: 150px;"> <img src="../photostrf/qrcodes/qrcode_<?= htmlspecialchars($id) ?>.png" alt="QR Code" style="max-width: 150px;">
<p style="margin-top: 10px;"> <p style="margin-top: 10px;">
<a href="<?= htmlspecialchars($uploadUrl) ?>" target="_blank"><?= htmlspecialchars($uploadUrl) ?></a> <a href="<?= htmlspecialchars($uploadUrl) ?>" target="_blank"><?= htmlspecialchars($uploadUrl) ?></a>
</p> </p>
@ -136,7 +198,7 @@ $result->saveToFile($qrCodeFile);
<!-- Elenco delle foto --> <!-- Elenco delle foto -->
<div id="photosList"> <div id="photosList">
<?php if (empty($photos)): ?> <?php if (empty($photos)): ?>
<p>No Photos present.</p> <p>Nessuna foto presente.</p>
<?php else: ?> <?php else: ?>
<?php foreach ($photos as $photo): ?> <?php foreach ($photos as $photo): ?>
<?php <?php

View File

@ -93,6 +93,7 @@ if (isset($_GET['edit_id'])) {
<?php include('cssinclude.php'); ?> <?php include('cssinclude.php'); ?>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2Lw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<style> <style>
/* Stili simili alla pagina fornita, adattati */ /* Stili simili alla pagina fornita, adattati */
.cell-changed { .cell-changed {
@ -174,6 +175,43 @@ if (isset($_GET['edit_id'])) {
.quotation-actions { .quotation-actions {
margin-top: 20px; margin-top: 20px;
} }
.modal {
display: none;
position: fixed;
z-index: 1050;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.5);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 600px;
border-radius: 8px;
position: relative;
}
.close-btn {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close-btn:hover,
.close-btn:focus {
color: #000;
text-decoration: none;
}
</style> </style>
<title>Gestione Quotations - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title> <title>Gestione Quotations - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head> </head>
@ -212,8 +250,8 @@ if (isset($_GET['edit_id'])) {
</form> </form>
<div class="quotation-actions"> <div class="quotation-actions">
<h6 class="mb-3">Azioni</h6> <h6 class="mb-3">Azioni</h6>
<button type="button" class="photos-btn action-btn" data-idquotations="<?= $editQuotation['id'] ?>" title="Photos"><i class="fas fa-camera"></i></button> <button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-idquotations="<?= $editQuotation['id'] ?>" style="background: #007bff; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; flex: 1;"><i class="fas fa-camera"></i></button>
<button type="button" class="parts-btn action-btn" data-idquotations="<?= $editQuotation['id'] ?>" title="Parts"><i class="fas fa-puzzle-piece"></i></button> <button class="parts-btn" data-iddatadb="" data-idquotations="456" data-row="0">Parti</button>
</div> </div>
<?php else: ?> <?php else: ?>
<!-- Lista Quotations --> <!-- Lista Quotations -->
@ -242,11 +280,12 @@ if (isset($_GET['edit_id'])) {
<td> <td>
<input type="text" name="customer" class="cell-input manual-input form-control" value="<?= htmlspecialchars($row['customer']) ?>"> <input type="text" name="customer" class="cell-input manual-input form-control" value="<?= htmlspecialchars($row['customer']) ?>">
</td> </td>
<!-- In quotations.php, nella tabella delle quotations -->
<td> <td>
<button type="button" class="save-btn action-btn edit-btn" data-id="<?= $row['id'] ?>" title="Salva Modifiche"><i class="fas fa-save"></i></button> <button type="button" class="save-btn action-btn edit-btn" data-id="<?= $row['id'] ?>" title="Salva Modifiche"><i class="fas fa-save"></i></button>
<button type="button" class="delete-btn action-btn" data-id="<?= $row['id'] ?>" title="Cancella" data-bs-toggle="modal" data-bs-target="#deleteModal"><i class="fas fa-trash"></i></button> <button type="button" class="delete-btn action-btn" data-id="<?= $row['id'] ?>" title="Cancella" data-bs-toggle="modal" data-bs-target="#deleteModal"><i class="fas fa-trash"></i></button>
<button type="button" class="photos-btn action-btn" data-idquotations="<?= $row['id'] ?>" title="Photos"><i class="fas fa-camera"></i></button> <button type="button" class="photos-btn action-btn" data-entity-type="quotation" data-idquotations="<?= $row['id'] ?>" title="Photos"><i class="fas fa-camera"></i></button>
<button type="button" class="parts-btn action-btn" data-idquotations="<?= $row['id'] ?>" title="Parts"><i class="fas fa-puzzle-piece"></i></button> <button type="button" class="parts-btn action-btn" data-entity-type="quotation" data-idquotations="<?= $row['id'] ?>" title="Parts"><i class="fas fa-puzzle-piece"></i></button>
<a href="quotations.php?edit_id=<?= $row['id'] ?>" class="btn btn-secondary action-btn" title="Modifica Dettagliata"><i class="fas fa-edit"></i></a> <a href="quotations.php?edit_id=<?= $row['id'] ?>" class="btn btn-secondary action-btn" title="Modifica Dettagliata"><i class="fas fa-edit"></i></a>
</td> </td>
</tr> </tr>
@ -376,6 +415,15 @@ if (isset($_GET['edit_id'])) {
// I bottoni photos e parts usano gli script esistenti (photos.js, parts.js), passando data-idquotations // I bottoni photos e parts usano gli script esistenti (photos.js, parts.js), passando data-idquotations
}); });
</script> </script>
<!-- Modale per le foto in quotations.php -->
<div class="modal" id="photosModal">
<div class="modal-content">
<span class="close-btn">&times;</span>
<div class="popup-content"></div>
</div>
</div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,63 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$data = json_decode(file_get_contents('php://input'), true);
$idquotations = $data['idquotations'] ?? null;
$parts = $data['parts'] ?? [];
if (!$idquotations || empty($parts)) {
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
exit;
}
try {
$pdo->beginTransaction();
// Elimina tutte le parti esistenti per idquotations
$stmt = $pdo->prepare("DELETE FROM identification_parts WHERE idquotations = :idquotations");
$stmt->execute([':idquotations' => $idquotations]);
// Prepara l'inserimento delle nuove parti
$stmt = $pdo->prepare("
INSERT INTO identification_parts
(idquotations, part_number, part_description, mix, created_at, updated_at)
VALUES (:idquotations, :part_number, :part_description, :mix, NOW(), NOW())
");
$part_ids = [];
foreach ($parts as $part) {
$partNumber = $part['part_number'] ?? null;
$partDescription = $part['part_description'] ?? '';
$mix = $part['mix'] ?? 'N';
if (!$partNumber || !$partDescription) {
throw new PDOException("Numero parte o descrizione mancante per parte: " . json_encode($part));
}
$stmt->execute([
':idquotations' => $idquotations,
':part_number' => $partNumber,
':part_description' => $partDescription,
':mix' => $mix
]);
$part_ids[] = $pdo->lastInsertId();
}
$pdo->commit();
echo json_encode([
'success' => true,
'part_ids' => $part_ids,
'message' => 'Parti rinumerate con successo'
]);
} catch (PDOException $e) {
$pdo->rollBack();
echo json_encode([
'success' => false,
'message' => 'Errore nel salvataggio: ' . $e->getMessage()
]);
}

View File

@ -0,0 +1,59 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
error_reporting(E_ALL);
ini_set('display_errors', 1);
$dataURL = $_POST['dataURL'] ?? null;
$filename = $_POST['filename'] ?? null;
$idquotations = $_POST['idquotations'] ?? null;
if (!$dataURL || !$filename || !$idquotations) {
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
exit;
}
try {
// Verifica che idquotations esista nella tabella quotations
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$stmt = $pdo->prepare("SELECT idquotations FROM quotations WHERE idquotations = :idquotations");
$stmt->execute([':idquotations' => $idquotations]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'idquotations non valido']);
exit;
}
// Salva l'immagine
$data = explode(',', $dataURL)[1];
$decodedData = base64_decode($data);
$dirPath = '../photostrf/annotated';
if (!file_exists($dirPath)) {
mkdir($dirPath, 0777, true);
}
$filePath = $dirPath . '/' . $filename;
file_put_contents($filePath, $decodedData);
// Registra nel database
$stmt = $pdo->prepare("
INSERT INTO datadb_photos (idquotations, file_path, file_name, uploaded_at, uploaded_by)
VALUES (:idquotations, :file_path, :file_name, NOW(), :uploaded_by)
");
$stmt->execute([
':idquotations' => $idquotations,
':file_path' => $filePath,
':file_name' => $filename,
':uploaded_by' => $iduserlogin
]);
echo json_encode([
'success' => true,
'file_path' => $filePath,
'message' => 'Foto salvata con successo e registrata nel DB'
]);
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]);
}

View File

@ -0,0 +1,60 @@
<?php
header('Content-Type: application/json');
include('include/headscript.php');
$dbHandler = DBHandlerSelect::getInstance();
$pdo = $dbHandler->getConnection();
$data = json_decode(file_get_contents('php://input'), true);
$idquotations = $data['idquotations'] ?? null;
$parts = $data['parts'] ?? [];
if (!$idquotations || empty($parts)) {
echo json_encode(['success' => false, 'message' => 'Dati mancanti']);
exit;
}
$part = $parts[0];
$partId = $part['id'] ?? null;
$partNumber = $part['part_number'] ?? null;
$partDescription = $part['part_description'] ?? '';
$mix = $part['mix'] ?? 'N';
if ($partDescription) {
try {
if ($partId) {
// UPDATE se esiste già la parte
$stmt = $pdo->prepare("UPDATE identification_parts
SET part_number = :part_number,
part_description = :part_description,
mix = :mix,
updated_at = NOW()
WHERE id = :id");
$stmt->execute([
':id' => $partId,
':part_number' => $partNumber,
':part_description' => $partDescription,
':mix' => $mix
]);
echo json_encode(['success' => true, 'part_id' => $partId, 'part_number' => $partNumber, 'message' => 'Parte aggiornata con successo']);
} else {
// INSERT se è nuova
$stmt = $pdo->prepare("INSERT INTO identification_parts
(idquotations, part_number, part_description, mix, created_at, updated_at)
VALUES (:idquotations, :part_number, :part_description, :mix, NOW(), NOW())");
$stmt->execute([
':idquotations' => $idquotations,
':part_number' => $partNumber,
':part_description' => $partDescription,
':mix' => $mix
]);
$newId = $pdo->lastInsertId();
echo json_encode(['success' => true, 'part_id' => $newId, 'part_number' => $partNumber, 'message' => 'Parte salvata con successo']);
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]);
}
} else {
echo json_encode(['success' => false, 'message' => 'Descrizione mancante']);
}

View File

@ -4,13 +4,23 @@ include('include/headscript.php');
header('Content-Type: application/json'); header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['photo']) || !isset($_POST['iddatadb'])) { if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['photo']) || (!isset($_POST['iddatadb']) && !isset($_POST['idquotations']))) {
echo json_encode(['success' => false, 'message' => 'Richiesta non valida']); echo json_encode(['success' => false, 'message' => 'Richiesta non valida']);
exit; exit;
} }
$iddatadb = intval($_POST['iddatadb']); $iddatadb = isset($_POST['iddatadb']) ? intval($_POST['iddatadb']) : null;
$photo = $_FILES['photo']; $idquotations = isset($_POST['idquotations']) ? intval($_POST['idquotations']) : null;
if ($iddatadb && $idquotations) {
echo json_encode(['success' => false, 'message' => 'Non è possibile specificare sia iddatadb che idquotations']);
exit;
}
if (!$iddatadb && !$idquotations) {
echo json_encode(['success' => false, 'message' => 'ID TRF o ID quotations mancante']);
exit;
}
// Verifica che l'utente loggato esista in auth_users // Verifica che l'utente loggato esista in auth_users
$db = DBHandlerSelect::getInstance(); $db = DBHandlerSelect::getInstance();
@ -25,6 +35,28 @@ if (!$userExists) {
exit; exit;
} }
// Verifica l'esistenza dell'ID nella tabella corrispondente
try {
if ($iddatadb) {
$stmt = $pdo->prepare("SELECT iddatadb FROM datadb WHERE iddatadb = ?");
$stmt->execute([$iddatadb]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'iddatadb non valido']);
exit;
}
} else {
$stmt = $pdo->prepare("SELECT id FROM quotations WHERE id = ?");
$stmt->execute([$idquotations]);
if (!$stmt->fetch()) {
echo json_encode(['success' => false, 'message' => 'idquotations non valido']);
exit;
}
}
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore nella validazione: ' . $e->getMessage()]);
exit;
}
// Usa un percorso assoluto per la cartella photostrf // Usa un percorso assoluto per la cartella photostrf
$uploadDir = realpath(__DIR__ . '/../photostrf') . '/'; $uploadDir = realpath(__DIR__ . '/../photostrf') . '/';
if (!is_dir($uploadDir)) { if (!is_dir($uploadDir)) {
@ -41,6 +73,7 @@ if (!is_writable($uploadDir)) {
} }
// Verifica che il file sia un'immagine (inclusi HEIC/HEIF) // Verifica che il file sia un'immagine (inclusi HEIC/HEIF)
$photo = $_FILES['photo'];
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/heic', 'image/heif']; $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/heic', 'image/heif'];
if (!in_array($photo['type'], $allowedTypes)) { if (!in_array($photo['type'], $allowedTypes)) {
echo json_encode(['success' => false, 'message' => 'Il file deve essere un\'immagine (JPEG, PNG, GIF, HEIC)']); echo json_encode(['success' => false, 'message' => 'Il file deve essere un\'immagine (JPEG, PNG, GIF, HEIC)']);
@ -53,10 +86,11 @@ if (!file_exists($photo['tmp_name']) || !is_uploaded_file($photo['tmp_name'])) {
exit; exit;
} }
// Rinomina il file: idriga-timestamp-nomeoriginale.estensione // Rinomina il file: id-timestamp-nomeoriginale.estensione
$timestamp = date('YmdHis'); $timestamp = date('YmdHis');
$originalName = pathinfo($photo['name'], PATHINFO_FILENAME); $originalName = pathinfo($photo['name'], PATHINFO_FILENAME);
$extension = strtolower(pathinfo($photo['name'], PATHINFO_EXTENSION)); $extension = strtolower(pathinfo($photo['name'], PATHINFO_EXTENSION));
$id = $iddatadb ?: $idquotations;
// Se il file è HEIC/HEIF, convertilo in JPEG // Se il file è HEIC/HEIF, convertilo in JPEG
if (in_array($photo['type'], ['image/heic', 'image/heif'])) { if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
@ -74,11 +108,11 @@ if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
} }
// Crea un nuovo nome per il file JPEG // Crea un nuovo nome per il file JPEG
$newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.jpg"; $newFileName = "{$id}-{$timestamp}-{$originalName}.jpg";
$destination = $uploadDir . $newFileName; $destination = $uploadDir . $newFileName;
// Salva l'immagine come JPEG // Salva l'immagine come JPEG
if (!imagejpeg($image, $destination, 90)) { // 90 è la qualità JPEG if (!imagejpeg($image, $destination, 90)) {
imagedestroy($image); imagedestroy($image);
echo json_encode(['success' => false, 'message' => 'Errore durante la conversione del file HEIC in JPEG']); echo json_encode(['success' => false, 'message' => 'Errore durante la conversione del file HEIC in JPEG']);
exit; exit;
@ -88,7 +122,7 @@ if (in_array($photo['type'], ['image/heic', 'image/heif'])) {
imagedestroy($image); imagedestroy($image);
} else { } else {
// Per i formati non HEIC, usa il nome e l'estensione originali // Per i formati non HEIC, usa il nome e l'estensione originali
$newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.{$extension}"; $newFileName = "{$id}-{$timestamp}-{$originalName}.{$extension}";
$destination = $uploadDir . $newFileName; $destination = $uploadDir . $newFileName;
// Salva il file // Salva il file
@ -105,7 +139,12 @@ error_log("Destination: $destination");
error_log("Temp file: " . $photo['tmp_name']); error_log("Temp file: " . $photo['tmp_name']);
// Salva il riferimento nel database // Salva il riferimento nel database
$stmt = $pdo->prepare("INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_by) VALUES (?, ?, ?, ?)"); try {
$stmt->execute([$iddatadb, $newFileName, $newFileName, $iduserlogin]); $stmt = $pdo->prepare("INSERT INTO datadb_photos (iddatadb, idquotations, file_path, file_name, uploaded_by) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$iddatadb, $idquotations, $newFileName, $newFileName, $iduserlogin]);
} catch (PDOException $e) {
echo json_encode(['success' => false, 'message' => 'Errore durante il salvataggio nel database: ' . $e->getMessage()]);
exit;
}
echo json_encode(['success' => true, 'message' => 'Foto caricata con successo']); echo json_encode(['success' => true, 'message' => 'Foto caricata con successo']);

View File

@ -5,24 +5,41 @@ include('include/headscript.php');
$db = DBHandlerSelect::getInstance(); $db = DBHandlerSelect::getInstance();
$pdo = $db->getConnection(); $pdo = $db->getConnection();
// Verifica che l'iddatadb sia stato passato // Verifica che almeno uno degli ID sia passato
if (!isset($_GET['iddatadb']) || empty($_GET['iddatadb'])) { $iddatadb = isset($_GET['iddatadb']) && !empty($_GET['iddatadb']) ? intval($_GET['iddatadb']) : null;
die('ID riga non fornito'); $idquotations = isset($_GET['idquotations']) && !empty($_GET['idquotations']) ? intval($_GET['idquotations']) : null;
if (!$iddatadb && !$idquotations) {
die('ID riga o ID quotations non fornito');
} }
$iddatadb = intval($_GET['iddatadb']); if ($iddatadb && $idquotations) {
die('Non è possibile specificare sia iddatadb che idquotations');
}
// Recupera i dettagli della riga (idriga e sample_code) // Verifica che l'utente loggato esista
$stmt = $pdo->prepare("SELECT iddatadb, sample_code FROM datadb WHERE iddatadb = ?"); $stmt = $pdo->prepare("SELECT id FROM auth_users WHERE id = ?");
$stmt->execute([$iddatadb]); $stmt->execute([$iduserlogin]);
if (!$stmt->fetch(PDO::FETCH_ASSOC)) {
die('Utente non valido');
}
// Determina quale ID usare e verifica l'esistenza
$paramName = $iddatadb ? 'iddatadb' : 'idquotations';
$paramValue = $iddatadb ?: $idquotations;
$table = $iddatadb ? 'datadb' : 'quotations';
$field = $iddatadb ? 'sample_code' : 'quotation_code';
$stmt = $pdo->prepare("SELECT {$paramName}, {$field} FROM {$table} WHERE {$paramName} = ?");
$stmt->execute([$paramValue]);
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$row) { if (!$row) {
die('Riga non trovata'); die('Riga non trovata');
} }
$idriga = $row['iddatadb']; $id = $row[$paramName];
$sampleCode = $row['sample_code'] ?? 'Non disponibile'; $code = $row[$field] ?? 'Non disponibile';
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@ -32,17 +49,23 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Carica Foto da Mobile</title> <title>Carica Foto da Mobile</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
body { body {
font-family: Arial, sans-serif; font-family: Arial, sans-serif;
padding: 20px; padding: 20px;
text-align: center; text-align: center;
background: #f4f4f4;
} }
.upload-area { .upload-area {
border: 2px dashed #ccc; border: 2px dashed #ccc;
padding: 20px; padding: 20px;
margin: 20px 0; margin: 20px auto;
max-width: 500px;
background: white;
border-radius: 8px;
cursor: pointer;
} }
.upload-area.highlight { .upload-area.highlight {
@ -56,57 +79,121 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
margin-bottom: 10px; margin-bottom: 10px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
padding-bottom: 10px; padding-bottom: 10px;
max-width: 500px;
margin-left: auto;
margin-right: auto;
} }
.photo-item img { .photo-item img {
max-width: 100px; max-width: 100px;
max-height: 100px; max-height: 100px;
margin-right: 10px; margin-right: 10px;
border-radius: 4px;
}
.loader {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.loader i {
font-size: 40px;
margin-bottom: 10px;
}
.error-message {
color: red;
margin: 10px 0;
display: none;
}
button.delete-photo-btn {
background: none;
border: none;
color: #dc3545;
cursor: pointer;
font-size: 18px;
} }
</style> </style>
</head> </head>
<body> <body>
<h2>Carica Foto per ID Riga: <?= htmlspecialchars($idriga) ?></h2> <h2>Carica Foto per ID: <?= htmlspecialchars($id) ?></h2>
<p><strong>Sample Code:</strong> <?= htmlspecialchars($sampleCode) ?></p> <p><strong>Codice:</strong> <?= htmlspecialchars($code) ?></p>
<div class="loader" id="loader">
<div>
<i class="fas fa-spinner fa-spin"></i>
<p>Caricamento in corso...</p>
</div>
</div>
<div class="error-message" id="errorMessage"></div>
<div class="upload-area" id="uploadArea"> <div class="upload-area" id="uploadArea">
<p>Scatta una foto o seleziona un'immagine</p> <p>Scatta una foto o seleziona immagini</p>
<input type="file" id="photoInput" accept="image/*" capture="camera"> <input type="file" id="photoInput" accept="image/*" capture="camera" multiple style="display: none;">
</div>
<div id="photosList">
<!-- Le foto verranno caricate dinamicamente -->
</div> </div>
<div id="photosList"></div>
<script> <script>
const uploadArea = document.getElementById('uploadArea'); const uploadArea = document.getElementById('uploadArea');
const photoInput = document.getElementById('photoInput'); const photoInput = document.getElementById('photoInput');
const photosList = document.getElementById('photosList'); const photosList = document.getElementById('photosList');
const loader = document.getElementById('loader');
const errorMessage = document.getElementById('errorMessage');
const iddatadb = '<?= $iddatadb ?>';
const idquotations = '<?= $idquotations ?>';
const endpoint = idquotations ? 'load_photo_quotation.php' : 'load_photo.php';
const dataParam = idquotations ? {
idquotations: idquotations
} : {
iddatadb: iddatadb
};
// Carica le foto esistenti all'avvio // Carica le foto esistenti all'avvio
loadPhotos(); loadPhotos();
// Gestione del click sull'area di upload // Gestione drag-and-drop
uploadArea.addEventListener('click', () => { uploadArea.addEventListener('dragover', (e) => {
photoInput.click(); e.preventDefault();
uploadArea.classList.add('highlight');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('highlight');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('highlight');
handleFiles(e.dataTransfer.files);
}); });
// Gestione del caricamento delle foto // Gestione click sull'area di upload
photoInput.addEventListener('change', () => { uploadArea.addEventListener('click', () => photoInput.click());
handleFiles(photoInput.files);
}); // Gestione caricamento foto
photoInput.addEventListener('change', () => handleFiles(photoInput.files));
async function handleFiles(files) { async function handleFiles(files) {
loader.style.display = 'flex';
errorMessage.style.display = 'none';
for (const file of files) { for (const file of files) {
if (!file.type.startsWith('image/')) { if (!file.type.startsWith('image/')) {
alert('Per favore, carica solo immagini!'); showError('Per favore, carica solo immagini!');
continue; continue;
} }
const formData = new FormData(); const formData = new FormData();
formData.append('photo', file); formData.append('photo', file);
formData.append('iddatadb', '<?= $iddatadb ?>'); if (iddatadb) formData.append('iddatadb', iddatadb);
if (idquotations) formData.append('idquotations', idquotations);
try { try {
const response = await fetch('upload_photo.php', { const response = await fetch('upload_photo.php', {
@ -114,32 +201,86 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile';
body: formData body: formData
}); });
const result = await response.json(); const result = await response.json();
if (!result.success) {
if (result.success) { showError('Errore durante il caricamento: ' + result.message);
loadPhotos(); // Ricarica le foto
} else {
alert('Errore durante il caricamento: ' + result.message);
} }
} catch (error) { } catch (error) {
alert('Errore durante il caricamento: ' + error.message); showError('Errore di rete: ' + error.message);
} }
} }
loadPhotos();
loader.style.display = 'none';
} }
// Funzione per caricare le foto esistenti
async function loadPhotos() { async function loadPhotos() {
loader.style.display = 'flex';
errorMessage.style.display = 'none';
try { try {
const response = await fetch(`photos_popup.php?iddatadb=<?= $iddatadb ?>`); const response = await fetch(`${endpoint}?${new URLSearchParams(dataParam)}`);
const html = await response.text(); const result = await response.json();
const parser = new DOMParser(); photosList.innerHTML = '';
const doc = parser.parseFromString(html, 'text/html'); if (result.success && result.photos && result.photos.length > 0) {
const photosListContent = doc.querySelector('#photosList').innerHTML; for (const photo of result.photos) {
photosList.innerHTML = photosListContent; const photoName = photo.split('/').pop();
const photoItem = document.createElement('div');
photoItem.className = 'photo-item';
photoItem.innerHTML = `
<img src="${photo}" alt="${photoName}">
<div style="flex: 1; text-align: left;">
<strong>Nome:</strong> ${photoName}<br>
<strong>Caricata il:</strong> Non disponibile
</div>
<button class="delete-photo-btn" data-photo-path="${photo}">
<i class="fas fa-trash"></i>
</button>`;
photosList.appendChild(photoItem);
}
} else {
photosList.innerHTML = '<p>Nessuna foto presente.</p>';
}
} catch (error) { } catch (error) {
photosList.innerHTML = `<p>Errore durante il caricamento delle foto: ${error.message}</p>`; showError('Errore durante il caricamento delle foto: ' + error.message);
} }
loader.style.display = 'none';
} }
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
setTimeout(() => errorMessage.style.display = 'none', 5000);
}
// Gestione eliminazione foto
photosList.addEventListener('click', async (e) => {
if (e.target.closest('.delete-photo-btn')) {
const button = e.target.closest('.delete-photo-btn');
const photoPath = button.dataset.photoPath;
if (confirm('Sei sicuro di voler eliminare questa foto?')) {
loader.style.display = 'flex';
try {
const response = await fetch('delete_photo.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
file_path: photoPath
})
});
const result = await response.json();
if (result.success) {
loadPhotos();
} else {
showError('Errore durante l\'eliminazione: ' + result.message);
}
} catch (error) {
showError('Errore durante l\'eliminazione: ' + error.message);
}
loader.style.display = 'none';
}
}
});
</script> </script>
</body> </body>
</html> </html>