mix part and loader
BIN
public/photostrf/594-20250730091737-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/595-20250730092054-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/596-20250730102350-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 38 KiB |
BIN
public/photostrf/608-20250730124047-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/610-20250730124129-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/611-20250730124600-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/612-20250730124728-images.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
public/photostrf/613-20250730125239-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/614-20250730125611-images.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
public/photostrf/615-20250730125820-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/616-20250730130101-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/617-20250730130314-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/618-20250730130647-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/619-20250730130728-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/620-20250730130910-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/621-20250730131506-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/622-20250730132046-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/623-20250730132131-images.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
public/photostrf/624-20250730132231-images (1).jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
public/photostrf/631-20250730133747-images.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
BIN
public/photostrf/qrcodes/qrcode_594.png
Normal file
|
After Width: | Height: | Size: 514 B |
BIN
public/photostrf/qrcodes/qrcode_595.png
Normal file
|
After Width: | Height: | Size: 506 B |
BIN
public/photostrf/qrcodes/qrcode_596.png
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
public/photostrf/qrcodes/qrcode_604.png
Normal file
|
After Width: | Height: | Size: 510 B |
BIN
public/photostrf/qrcodes/qrcode_605.png
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
public/photostrf/qrcodes/qrcode_606.png
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
public/photostrf/qrcodes/qrcode_608.png
Normal file
|
After Width: | Height: | Size: 516 B |
BIN
public/photostrf/qrcodes/qrcode_610.png
Normal file
|
After Width: | Height: | Size: 511 B |
BIN
public/photostrf/qrcodes/qrcode_611.png
Normal file
|
After Width: | Height: | Size: 514 B |
BIN
public/photostrf/qrcodes/qrcode_612.png
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
public/photostrf/qrcodes/qrcode_613.png
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
public/photostrf/qrcodes/qrcode_614.png
Normal file
|
After Width: | Height: | Size: 521 B |
BIN
public/photostrf/qrcodes/qrcode_615.png
Normal file
|
After Width: | Height: | Size: 511 B |
BIN
public/photostrf/qrcodes/qrcode_616.png
Normal file
|
After Width: | Height: | Size: 508 B |
BIN
public/photostrf/qrcodes/qrcode_617.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
public/photostrf/qrcodes/qrcode_618.png
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
public/photostrf/qrcodes/qrcode_619.png
Normal file
|
After Width: | Height: | Size: 515 B |
BIN
public/photostrf/qrcodes/qrcode_620.png
Normal file
|
After Width: | Height: | Size: 515 B |
BIN
public/photostrf/qrcodes/qrcode_621.png
Normal file
|
After Width: | Height: | Size: 511 B |
BIN
public/photostrf/qrcodes/qrcode_622.png
Normal file
|
After Width: | Height: | Size: 515 B |
BIN
public/photostrf/qrcodes/qrcode_623.png
Normal file
|
After Width: | Height: | Size: 513 B |
BIN
public/photostrf/qrcodes/qrcode_624.png
Normal file
|
After Width: | Height: | Size: 507 B |
BIN
public/photostrf/qrcodes/qrcode_629.png
Normal file
|
After Width: | Height: | Size: 521 B |
BIN
public/photostrf/qrcodes/qrcode_630.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
public/photostrf/qrcodes/qrcode_631.png
Normal file
|
After Width: | Height: | Size: 515 B |
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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>
|
||||
@ -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}`);
|
||||
}
|
||||
});
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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>
|
||||
@ -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) {
|
||||
|
||||