mix part and loader

This commit is contained in:
Claudio 2025-07-30 15:43:14 +02:00
parent b3f19be47d
commit 6d66c5cf97
60 changed files with 3973 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

View File

@ -31,6 +31,6 @@ Content-Length: 51
< strict-transport-security: max-age=2592000
< x-powered-by: ASP.NET
< x-content-type-options: nosniff
< date: Wed, 30 Jul 2025 08:42:50 GMT
< date: Wed, 30 Jul 2025 13:38:07 GMT
<
* Connection #0 to host 93.43.5.102 left intact

View File

@ -15,11 +15,11 @@
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: 93.43.5.102]
* [HTTP/2] [1] [:path: /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues]
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1Mzg3MjE3MCwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.EpboyTkahMCz-ctZyx0HlgjD2TcQKV9TnlYSo--3lp8]
* [HTTP/2] [1] [authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1Mzg4OTg4NywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.fka4MClGYcSJycwopdVtHtp-59VPTCgT_waRi8qdLmE]
* [HTTP/2] [1] [accept: application/json]
> GET /limsapi/api/odata/CustomField(1083)?$expand=CustomFieldsValues HTTP/2
Host: 93.43.5.102
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1Mzg3MjE3MCwiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.EpboyTkahMCz-ctZyx0HlgjD2TcQKV9TnlYSo--3lp8
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjQ5MiIsIlhhZlNlY3VyaXR5QXV0aFBhc3NlZCI6IlhhZlNlY3VyaXR5QXV0aFBhc3NlZCIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiJXZWJBcGlVc2VyIiwiWGFmU2VjdXJpdHkiOiJYYWZTZWN1cml0eSIsIlhhZkxvZ29uUGFyYW1zIjoicTFZS0xVNHQ4a3ZNVFZXeVVncFBUWElzeUFRSktPa29CU1FXRjVmbkY2VUF4Y3RUa3hJTE1rdUI0Z2FHU3JVQSIsImV4cCI6MTc1Mzg4OTg4NywiaXNzIjoiTXkiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjQyMDAifQ.fka4MClGYcSJycwopdVtHtp-59VPTCgT_waRi8qdLmE
Accept: application/json
< HTTP/2 200
@ -30,6 +30,6 @@ Accept: application/json
< odata-version: 4.0
< x-powered-by: ASP.NET
< x-content-type-options: nosniff
< date: Wed, 30 Jul 2025 08:42:50 GMT
< date: Wed, 30 Jul 2025 13:38:08 GMT
<
* Connection #0 to host 93.43.5.102 left intact

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -75,3 +75,6 @@ https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField
https://93.43.5.102/limsapi/api/odata/SchemaCustomField

View File

@ -25,6 +25,7 @@
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
<td>
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
@ -92,6 +93,9 @@
#partsList .list-group-item {
cursor: pointer;
transition: background-color 0.2s;
display: flex;
justify-content: space-between;
align-items: center;
}
#partsList .list-group-item:hover {
@ -113,18 +117,14 @@
.draggable-marker {
position: absolute;
width: 24px;
/* Aumentato da 16px */
height: 24px;
/* Aumentato da 16px */
background: rgba(255, 0, 0, 0.5);
border: 1px solid #ff0000;
border-radius: 50%;
color: #ffffff;
text-align: center;
line-height: 24px;
/* Aumentato per allineare il testo */
font-size: 12px;
/* Aumentato da 8px */
cursor: move;
user-select: none;
z-index: 1000;
@ -137,4 +137,9 @@
width: 100%;
height: 100%;
}
.add-to-mix-btn {
padding: 0.1rem 0.3rem;
font-size: 0.8rem;
}
</style>

View File

@ -28,8 +28,8 @@ $(document).ready(function () {
loadExistingParts(iddatadb);
if (partsModal) {
const modal = new bootstrap.Modal(partsModal); // Create a new instance
modal.show(); // Show the modal
const modal = new bootstrap.Modal(partsModal);
modal.show();
} else {
console.error("Modal Parts non trovato");
}
@ -40,8 +40,8 @@ $(document).ready(function () {
if (closeBtn) {
closeBtn.addEventListener("click", function () {
partsModal.style.display = "none";
overlay.style.display = "none"; // Nascondi overlay
document.body.style.pointerEvents = "auto"; // Riattiva la pagina
overlay.style.display = "none";
document.body.style.pointerEvents = "auto";
});
}
@ -49,8 +49,8 @@ $(document).ready(function () {
window.addEventListener("click", function (event) {
if (event.target === partsModal) {
partsModal.style.display = "none";
overlay.style.display = "none"; // Nascondi overlay
document.body.style.pointerEvents = "auto"; // Riattiva la pagina
overlay.style.display = "none";
document.body.style.pointerEvents = "auto";
}
});
}
@ -98,13 +98,15 @@ $(document).ready(function () {
});
}
function addNewRow(nextPartNumber) {
function addNewRow(nextPartNumber, isMix = false) {
const description = isMix ? "Mix" : "";
const newRow = `
<tr data-part-id="new">
<td><input type="number" class="form-control form-control-sm part-number" value="${nextPartNumber || 1}" style="width: 80px;"></td>
<td><input type="text" class="form-control form-control-sm part-description" placeholder="Inserisci descrizione" style="width: 100%;"></td>
<td><input type="text" class="form-control form-control-sm part-description" value="${description}" placeholder="Inserisci descrizione" style="width: 100%;"></td>
<td>
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem; display: none;"><i class="fas fa-trash fa-xs"></i></button>
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
@ -141,6 +143,20 @@ $(document).ready(function () {
updatePartsList();
});
$(document).on("click", ".add-mix-row", function (e) {
e.preventDefault();
console.log("Pulsante Aggiungi Mix cliccato");
const maxPartNumber = Math.max(
...$("#partsTableBody tr")
.map(function () {
return parseInt($(this).find(".part-number").val()) || 0;
})
.get(),
);
addNewRow(maxPartNumber + 1, true);
updatePartsList();
});
$(document).on("click", ".remove-row", function (e) {
e.preventDefault();
console.log("Pulsante Rimuovi riga cliccato");
@ -202,8 +218,13 @@ $(document).ready(function () {
const $saveStatus = $row.find(".save-status");
const $saveLoading = $row.find(".save-loading");
const iddatadb = $("#partsModal").data("iddatadb");
const isMix = partDescription.startsWith("Mix") ? "Y" : "N";
console.log("Evento blur su input:", { partNumber, partDescription });
console.log("Evento blur su input:", {
partNumber,
partDescription,
isMix,
});
if (partDescription && iddatadb) {
$saveLoading.show();
@ -218,6 +239,7 @@ $(document).ready(function () {
{
part_number: partNumber,
part_description: partDescription,
mix: isMix,
},
],
}),
@ -264,6 +286,7 @@ $(document).ready(function () {
<td><input type="text" class="form-control form-control-sm part-description" value="${part.part_description}" style="width: 100%;"></td>
<td>
<button type="button" class="btn btn-success btn-sm add-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
<button type="button" class="btn btn-primary btn-sm add-mix-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;">M</button>
<button type="button" class="btn btn-danger btn-sm remove-row" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-trash fa-xs"></i></button>
<span class="save-status text-success" style="display: none; margin-left: 5px;"><i class="fas fa-check fa-xs"></i></span>
<span class="save-loading text-warning" style="display: none; margin-left: 5px;"><i class="fas fa-spinner fa-spin fa-xs"></i></span>
@ -297,19 +320,61 @@ $(document).ready(function () {
$("#partsTableBody tr").each(function () {
const partNumber = $(this).find(".part-number").val();
const partDescription = $(this).find(".part-description").val();
if (partNumber && partDescription) {
const listItem = `<li class="list-group-item" data-part-number="${partNumber}">${partNumber} - ${partDescription}</li>`;
if (
partNumber &&
partDescription &&
!partDescription.startsWith("Mix")
) {
const listItem = `
<li class="list-group-item" data-part-number="${partNumber}">
${partNumber} - ${partDescription}
<button type="button" class="btn btn-success btn-sm add-to-mix-btn" style="padding: 0.1rem 0.3rem; font-size: 0.8rem;"><i class="fas fa-plus fa-xs"></i></button>
</li>`;
$("#partsList").append(listItem);
}
});
}
$(document).on("click", ".add-to-mix-btn", function () {
const $listItem = $(this).closest("li");
const partDescription = $listItem.text().split(" - ")[1].trim(); // Prende tutta la descrizione dopo il trattino
const $mixRow = $("#partsTableBody tr")
.filter(function () {
return $(this)
.find(".part-description")
.val()
.startsWith("Mix");
})
.last();
if ($mixRow.length === 0) {
alert("Crea prima una riga Mix usando il pulsante 'M'.");
return;
}
const $descriptionInput = $mixRow.find(".part-description");
let currentDescription = $descriptionInput.val().trim();
if (currentDescription === "Mix") {
currentDescription = `Mix ${partDescription}`;
} else if (!currentDescription.includes(partDescription)) {
currentDescription += ` + ${partDescription}`;
} else {
return; // Parte già presente, non aggiungerla
}
$descriptionInput.val(currentDescription);
$descriptionInput.trigger("blur"); // Attiva il salvataggio
updatePartsList();
});
let selectedPartNumber = null;
let markers = [];
let descriptionPosition = { x: 10, y: 10 };
let hasDescriptions = false;
$("#partsList").on("click", "li", function () {
$("#partsList").on("click", "li", function (e) {
if ($(e.target).hasClass("add-to-mix-btn")) return;
selectedPartNumber = $(this).data("part-number");
console.log("Part number selezionato:", selectedPartNumber);
$(this).addClass("active").siblings().removeClass("active");
@ -451,7 +516,11 @@ $(document).ready(function () {
$("#partsTableBody tr").each(function () {
const partNumber = $(this).find(".part-number").val();
const partDescription = $(this).find(".part-description").val();
if (partNumber && partDescription) {
if (
partNumber &&
partDescription &&
!partDescription.startsWith("Mix")
) {
partsList.push(`${partNumber} ${partDescription}`);
}
});
@ -525,7 +594,11 @@ $(document).ready(function () {
$("#partsTableBody tr").each(function () {
const partNumber = $(this).find(".part-number").val();
const partDescription = $(this).find(".part-description").val();
if (partNumber && partDescription) {
if (
partNumber &&
partDescription &&
!partDescription.startsWith("Mix")
) {
partsList.push(`${partNumber} ${partDescription}`);
}
});

View File

@ -21,6 +21,89 @@ document.addEventListener("DOMContentLoaded", function () {
}
}
// Funzione per gestire la webcam
function setupWebcam(iddatadb) {
const openWebcamBtn = document.getElementById("openWebcamBtn");
const webcamArea = document.getElementById("webcamArea");
const webcamVideo = document.getElementById("webcamVideo");
const captureBtn = document.getElementById("captureBtn");
const closeWebcamBtn = document.getElementById("closeWebcamBtn");
let stream = null;
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
console.warn("La webcam non è supportata dal browser.");
if (openWebcamBtn) openWebcamBtn.style.display = "none";
return;
}
if (
!openWebcamBtn ||
!webcamArea ||
!webcamVideo ||
!captureBtn ||
!closeWebcamBtn
) {
console.error("Elementi webcam mancanti");
return;
}
// Apri la webcam
openWebcamBtn.addEventListener("click", async () => {
try {
stream = await navigator.mediaDevices.getUserMedia({
video: true,
});
webcamVideo.srcObject = stream;
webcamArea.style.display = "block";
openWebcamBtn.style.display = "none";
dropArea.style.display = "none";
} catch (error) {
alert("Errore nell'accesso alla webcam: " + error.message);
}
});
// Cattura la foto
captureBtn.addEventListener("click", () => {
const canvas = document.createElement("canvas");
canvas.width = webcamVideo.videoWidth;
canvas.height = webcamVideo.videoHeight;
canvas
.getContext("2d")
.drawImage(webcamVideo, 0, 0, canvas.width, canvas.height);
// Converti l'immagine in un file
canvas.toBlob(async (blob) => {
const file = new File(
[blob],
`webcam_photo_${Date.now()}.jpg`,
{ type: "image/jpeg" },
);
const loader = document.getElementById("loader");
if (loader) {
console.log("Mostro loader per upload webcam");
loader.style.display = "flex";
}
await handleFiles([file], iddatadb);
closeWebcam();
}, "image/jpeg");
});
// Chiudi la webcam
closeWebcamBtn.addEventListener("click", () => {
closeWebcam();
});
function closeWebcam() {
if (stream) {
stream.getTracks().forEach((track) => track.stop());
webcamVideo.srcObject = null;
webcamArea.style.display = "none";
openWebcamBtn.style.display = "block";
dropArea.style.display = "block";
}
}
}
// Funzione per attaccare gli event listener al contenuto del popup
function attachPhotoEventListeners(iddatadb) {
const dropArea = document.getElementById("dropArea");
@ -67,17 +150,35 @@ document.addEventListener("DOMContentLoaded", function () {
dropArea.addEventListener(
"drop",
(e) => {
console.log("Evento drop attivato");
const files = e.dataTransfer.files;
handleFiles(files, iddatadb);
if (files.length > 0) {
handleFiles(files, iddatadb);
}
},
false,
);
dropArea.addEventListener("click", () => photoInput.click(), false);
dropArea.addEventListener(
"click",
() => {
console.log("Click su dropArea, apro input file");
photoInput.click();
},
false,
);
photoInput.addEventListener(
"change",
() => handleFiles(photoInput.files, iddatadb),
(e) => {
console.log("Evento change su photoInput");
const files = e.target.files;
if (files.length > 0) {
handleFiles(files, iddatadb);
}
// Resetta l'input per consentire il caricamento dello stesso file
e.target.value = "";
},
false,
);
@ -116,6 +217,7 @@ document.addEventListener("DOMContentLoaded", function () {
// Gestione ingrandimento immagini
document.querySelectorAll(".thumbnail").forEach((img) => {
img.addEventListener("click", function () {
console.log("Click su thumbnail, apro modale immagine");
const enlargedImage = document.getElementById("enlargedImage");
enlargedImage.src = this.src;
document.getElementById("imageModal").style.display = "block";
@ -126,6 +228,7 @@ document.addEventListener("DOMContentLoaded", function () {
const imageCloseBtn = document.querySelector(".image-modal-close");
if (imageCloseBtn) {
imageCloseBtn.addEventListener("click", () => {
console.log("Chiusura modale immagine");
document.getElementById("imageModal").style.display = "none";
});
}
@ -133,18 +236,46 @@ document.addEventListener("DOMContentLoaded", function () {
.getElementById("imageModal")
.addEventListener("click", function (event) {
if (event.target === this) {
console.log(
"Chiusura modale immagine cliccando sullo sfondo",
);
this.style.display = "none";
}
});
// Inizializza la gestione della webcam
setupWebcam(iddatadb);
// Assicurati che il loader sia nascosto all'apertura del popup
const loader = document.getElementById("loader");
if (loader) {
console.log("Nascondo loader all'apertura del popup");
loader.style.display = "none";
}
}
// Funzione per gestire il caricamento dei file
async function handleFiles(files, iddatadb) {
const loader = document.getElementById("loader");
if (!loader) {
console.error("Elemento loader non trovato");
return;
}
if (!files || files.length === 0) {
console.warn("Nessun file da caricare");
return;
}
for (const file of files) {
if (!file.type.startsWith("image/")) {
alert("Per favore, carica solo immagini!");
continue;
}
console.log("Inizio upload del file:", file.name);
loader.style.display = "flex";
const formData = new FormData();
formData.append("photo", file);
formData.append("iddatadb", iddatadb);
@ -155,12 +286,18 @@ document.addEventListener("DOMContentLoaded", function () {
});
const result = await response.json();
if (result.success) {
console.log(
"Upload completato con successo, ricarico popup",
);
loadPopupContent(iddatadb);
} else {
alert("Errore durante il caricamento: " + result.message);
}
} catch (error) {
alert("Errore durante il caricamento: " + error.message);
} finally {
console.log("Nascondo loader dopo upload");
loader.style.display = "none";
}
}
}
@ -185,6 +322,7 @@ document.addEventListener("DOMContentLoaded", function () {
});
closeBtn.addEventListener("click", function () {
console.log("Chiusura modale photos");
photosModal.style.display = "none";
document.querySelector(".overlay").style.display = "none";
document.body.style.pointerEvents = "auto";
@ -192,6 +330,7 @@ document.addEventListener("DOMContentLoaded", function () {
window.addEventListener("click", function (event) {
if (event.target === photosModal) {
console.log("Chiusura modale photos cliccando sullo sfondo");
photosModal.style.display = "none";
document.querySelector(".overlay").style.display = "none";
document.body.style.pointerEvents = "auto";

View File

@ -73,6 +73,12 @@ $result->saveToFile($qrCodeFile);
?>
<div class="popup-content">
<div id="loader" class="loader" style="display: none;">
<div style="text-align: center; color: white;">
<i class="fas fa-spinner fa-spin" style="font-size: 40px;"></i>
<p>Caricamento in corso...</p>
</div>
</div>
<h3>Manage Photos</h3>
<p><strong>ID Row:</strong> <?= htmlspecialchars($idriga) ?></p>
<p><strong>Sample Code:</strong> <?= htmlspecialchars($sampleCode) ?></p>
@ -91,7 +97,16 @@ $result->saveToFile($qrCodeFile);
<p>Drag the photo here or click to select</p>
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
</div>
<!-- Area per la webcam -->
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
<p>Webcam Preview</p>
<video id="webcamVideo" autoplay playsinline style="max-width: 100%; max-height: 300px;"></video>
<div style="margin-top: 10px;">
<button id="captureBtn" style="padding: 10px 20px; background: #28a745; color: white; border: none; cursor: pointer;">Capture Photo</button>
<button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
</div>
</div>
<button id="openWebcamBtn" style="padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; margin-bottom: 20px;">Take Photo with Webcam</button>
<!-- Elenco delle foto -->
<div id="photosList">
<?php if (empty($photos)): ?>
@ -149,7 +164,6 @@ $result->saveToFile($qrCodeFile);
display: none;
position: fixed;
z-index: 1001;
/* Sopra il popup principale */
left: 0;
top: 0;
width: 100%;
@ -184,31 +198,30 @@ $result->saveToFile($qrCodeFile);
color: #bbb;
text-decoration: none;
}
</style>
<script>
// Gestione del click sulle immagini per ingrandirle
document.querySelectorAll('.thumbnail').forEach(img => {
img.addEventListener('click', function() {
const modal = document.getElementById('imageModal');
const enlargedImage = document.getElementById('enlargedImage');
enlargedImage.src = this.src;
modal.style.display = 'block';
});
});
/* Stili per il loader */
.loader {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1002;
display: flex;
align-items: center;
justify-content: center;
}
// Gestione della chiusura del modale
const modal = document.getElementById('imageModal');
const closeBtn = document.querySelector('.image-modal-close');
.loader .fa-spinner {
font-size: 40px;
color: white;
}
closeBtn.addEventListener('click', function() {
modal.style.display = 'none';
});
// Chiudi il modale cliccando fuori dall'immagine
modal.addEventListener('click', function(event) {
if (event.target === modal) {
modal.style.display = 'none';
}
});
</script>
.loader p {
margin-top: 10px;
font-size: 16px;
color: white;
}
</style>

View File

@ -19,14 +19,16 @@ if (!$iddatadb || empty($parts)) {
$part = $parts[0];
$partNumber = $part['part_number'] ?? null;
$partDescription = $part['part_description'] ?? '';
$mix = $part['mix'] ?? 'N'; // Aggiunto per gestire il campo mix
if ($partDescription) {
try {
$stmt = $pdo->prepare("INSERT INTO identification_parts (iddatadb, part_number, part_description, created_at, updated_at) VALUES (:iddatadb, :part_number, :part_description, NOW(), NOW())");
$stmt = $pdo->prepare("INSERT INTO identification_parts (iddatadb, part_number, part_description, mix, created_at, updated_at) VALUES (:iddatadb, :part_number, :part_description, :mix, NOW(), NOW())");
$stmt->execute([
':iddatadb' => $iddatadb,
':part_number' => $partNumber,
':part_description' => $partDescription
':part_description' => $partDescription,
':mix' => $mix
]);
echo json_encode(['success' => true, 'message' => 'Parte salvata con successo']);
} catch (PDOException $e) {