added multi webcam functionality

This commit is contained in:
Claudio 2025-08-27 20:21:38 +02:00
parent 7e4ed56f28
commit f6ef9c39d2
3 changed files with 361 additions and 171 deletions

View File

@ -499,6 +499,22 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
.proceed-btn { .proceed-btn {
margin-top: 20px; margin-top: 20px;
} }
.grid-cell.button-cell,
.grid-header.button-header {
min-width: 210px !important;
flex: 0 0 210px !important;
}
.action-btn {
padding: 6px 8px;
margin-right: 5px;
border: none;
border-radius: 5px;
cursor: pointer;
width: 50px;
box-sizing: border-box;
}
</style> </style>
<title>Dati Storici - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title> <title>Dati Storici - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?></title>
</head> </head>
@ -610,142 +626,190 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
</div> </div>
<div id="noResults" class="text-danger" style="display:none;">Nessun risultato trovato</div> <div id="noResults" class="text-danger" style="display:none;">Nessun risultato trovato</div>
<div class="scrollbar-container"></div> <div class="scrollbar-container"></div>
<form id="editForm"> <form id="editForm">
<div class="grid-container"> <div class="grid-container">
<?php $fixedColumns = ['filename_import', 'status', 'importdate']; ?> <div class="grid-top">
<?php if ($status === 'i'): ?> <div class="grid-cell actions-cell" style="flex: 0 0 200px;">
<div class="grid-top">
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 100px;"></div>
<div class="grid-cell" style="flex: 0 0 150px;"></div>
<?php
foreach ($fixedColumns as $col) {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
$autoIndex = 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual']) {
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
echo "<select class='custom-field dropdown-select $inputClass' data-column='auto_$autoIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
} else {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
$autoIndex++;
}
}
$manualIndex = 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual']) {
$fieldValue = $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='manual_$manualIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
}
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
echo "</div>";
$manualIndex++;
}
}
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>";
?>
</div>
<?php endif; ?>
<div class="grid-row">
<div class="grid-header" style="flex: 0 0 100px;">Save</div>
<div class="grid-header" style="flex: 0 0 100px;">Photos</div>
<div class="grid-header" style="flex: 0 0 100px;">Parts</div>
<div class="grid-header" data-index="3" style="flex: 0 0 150px; position: relative;">Import Reference Code<div class="resizer"></div>
</div> </div>
<?php <?php
$headerIndex = 4; // Campo con main_field = 1
foreach ($fixedColumns as $col) { if ($mainFieldMapping) {
$inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
$index = $mainFieldMapping['is_manual'] ? "manual_0" : "auto_0";
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='$index' data-field-id='{$mainFieldMapping['field_id']}' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='$index' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
$fieldValue = $mainFieldMapping['manual_default'] ?? '';
if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
if ($mainFieldMapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} elseif ($mainFieldMapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='$index' value='" . htmlspecialchars($fieldValue) . "' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
}
echo "<button type='button' class='propagate-btn' data-column='$index' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
}
echo "</div>";
} else {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
// Campi automatici (escluso main_field)
$autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
$inputClass = 'auto-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='auto_$autoIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='auto_$autoIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
echo "<div style='height: 34px;'></div>";
}
echo "</div>";
$autoIndex++;
}
}
// Campi manuali (escluso main_field)
$manualIndex = ($mainFieldMapping && $mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
$fieldValue = $mapping['manual_default'] ?? '';
if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') {
$fieldValue = date('Y-m-d');
}
$inputClass = 'manual-input';
if ($mapping['is_required']) $inputClass .= ' required-input';
echo "<div class='grid-cell' style='flex: 0 0 150px;'>";
if ($mapping['data_type'] === 'SceltaMultipla') {
echo "<select class='custom-field dropdown-select $inputClass' data-column='manual_$manualIndex' data-field-id='{$mapping['field_id']}' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<option value=''>Seleziona...</option>";
echo "</select>";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'DATE') {
echo "<input type='date' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} elseif ($mapping['data_type'] === 'INT') {
echo "<input type='number' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
} else {
echo "<input type='text' class='custom-field $inputClass' data-column='manual_$manualIndex' value='" . htmlspecialchars($fieldValue) . "' " . ($mapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<button type='button' class='propagate-btn' data-column='manual_$manualIndex' " . ($is_readonly ? 'disabled' : '') . "><i class='fas fa-arrow-down'></i></button>";
}
echo "</div>";
$manualIndex++;
}
}
// Colonne status, Import Reference Code, filename_import
$fixedColumnsReduced = ['status'];
foreach ($fixedColumnsReduced as $col) {
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>";
}
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // Import Reference Code
echo "<div class='grid-cell' style='flex: 0 0 150px;'></div>"; // filename_import
// AWB Number e Tracking Info
echo "<div class='grid-cell' style='flex: 0 0 200px;'></div>";
echo "<div class='grid-cell' style='flex: 0 0 250px;'></div>";
?>
</div>
<div class="grid-row">
<div class="grid-header actions-cell" style="flex: 0 0 200px; position: relative;">Azioni<div class="resizer"></div>
</div>
<?php
// Header per il campo main_field = 1
$headerIndex = 1;
if ($mainFieldMapping) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mainFieldMapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
// Header per campi automatici (escluso main_field)
foreach ($allMappings as $mapping) {
if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
}
// Header per campi manuali (escluso main_field)
foreach ($allMappings as $mapping) {
if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
}
// Header per status, Import Reference Code, filename_import
foreach ($fixedColumnsReduced as $col) {
$displayName = $slugMapping[$col] ?? $col; $displayName = $slugMapping[$col] ?? $col;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>$displayName<div class='resizer'></div></div>"; echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>$displayName<div class='resizer'></div></div>";
$headerIndex++; $headerIndex++;
} }
foreach ($allMappings as $mapping) { echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>Import Reference Code<div class='resizer'></div></div>";
if (!$mapping['is_manual']) { $headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>"; echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>File<div class='resizer'></div></div>";
$headerIndex++; $headerIndex++;
} // Header per AWB Number e Tracking Info
}
foreach ($allMappings as $mapping) {
if ($mapping['is_manual']) {
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 150px; position: relative;'>" . htmlspecialchars($mapping['field_label']) . "<div class='resizer'></div></div>";
$headerIndex++;
}
}
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 200px; position: relative;'>AWB Number<div class='resizer'></div></div>"; echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 200px; position: relative;'>AWB Number<div class='resizer'></div></div>";
echo "<div class='grid-header' data-index='" . ($headerIndex + 1) . "' style='flex: 0 0 250px; position: relative;'>Tracking Info<div class='resizer'></div></div>"; $headerIndex++;
echo "<div class='grid-header' data-index='$headerIndex' style='flex: 0 0 250px; position: relative;'>Tracking Info<div class='resizer'></div></div>";
?> ?>
</div> </div>
<?php foreach ($importedData as $index => $row): ?> <?php foreach ($importedData as $index => $row): ?>
<div class="grid-row" data-id="<?= $row['iddatadb'] ?>"> <div class="grid-row" data-id="<?= $row['iddatadb'] ?>">
<div class="grid-cell" style="flex: 0 0 100px; position: relative;"> <div class="grid-cell actions-cell" style="flex: 0 0 200px; position: relative;">
<?php if (!$is_readonly): ?> <div style="display: flex; gap: 5px; justify-content: center;">
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #28a745; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-save"></i></button> <?php if (!$is_readonly): ?>
<?php else: ?> <button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #28a745; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; flex: 1;"><i class="fas fa-save"></i></button>
<button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; width: 100%; box-sizing: border-box;" disabled><i class="fas fa-save"></i></button> <button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #007bff; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; flex: 1;"><i class="fas fa-camera"></i></button>
<?php endif; ?> <button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ffc107; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; flex: 1;"><i class="fas fa-puzzle-piece"></i></button>
</div> <?php else: ?>
<div class="grid-cell" style="flex: 0 0 100px; position: relative;"> <button type="button" class="save-btn action-btn" data-row="<?= $index ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-save"></i></button>
<button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #007bff; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-camera"></i></button> <button type="button" class="photos-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-camera"></i></button>
</div> <button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ccc; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: not-allowed; flex: 1;" disabled><i class="fas fa-puzzle-piece"></i></button>
<div class="grid-cell" style="flex: 0 0 100px; position: relative;"> <?php endif; ?>
<button type="button" class="parts-btn action-btn" data-row="<?= $index ?>" data-iddatadb="<?= $row['iddatadb'] ?>" style="background: #ffc107; color: white; border: none; padding: 8px 12px; border-radius: 5px; cursor: pointer; width: 100%; box-sizing: border-box;"><i class="fas fa-puzzle-piece"></i></button> </div>
</div> </div>
<?php <?php
$cellIndex = 3; $cellIndex = 1;
echo "<div class='grid-cell' data-col='importreferencecode' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>"; $rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']);
echo "<span>" . htmlspecialchars($row['importreferencecode']) . "</span>"; // Campo con main_field = 1
echo "<input type='hidden' name='rows[$index][importreferencecode]' value='" . htmlspecialchars($row['importreferencecode']) . "'>"; if ($mainFieldMapping) {
echo "</div>"; $detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mainFieldMapping['id']);
$cellIndex++; $detail = reset($detail) ?: ['field_value' => $mainFieldMapping['manual_default']];
foreach ($fixedColumns as $col) { $fieldValue = $detail['field_value'] ?? $mainFieldMapping['manual_default'] ?? '';
$value = $row[$col] ?? ''; $requiredClass = ($mainFieldMapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : '';
echo "<div class='grid-cell editable-cell' data-col='$col' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>"; $inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input';
if ($col === 'importdate') { if ($mainFieldMapping['is_required']) $inputClass .= ' required-input';
echo "<span>" . htmlspecialchars($value) . "</span>"; $indexField = $mainFieldMapping['is_manual'] ? "manual_0" : "auto_0";
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value) . "'>"; echo "<div class='grid-cell editable-cell $requiredClass' data-col='$indexField' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
} elseif ($col === 'filename_import') { if ($mainFieldMapping['data_type'] === 'SceltaMultipla') {
echo "<a href='imported_trf/" . htmlspecialchars($value) . "' target='_blank'>File</a>"; echo "<select name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' class='cell-input dropdown-select $inputClass' data-mapping-id='{$mainFieldMapping['id']}' data-field-id='{$mainFieldMapping['field_id']}' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value) . "'>"; echo "<option value=''>Seleziona...</option>";
} elseif ($col === 'status') { echo "</select>";
$badgeClass = $value === 'i' ? 'status-i' : ($value === 'P' ? 'status-P' : 'status-l'); } elseif ($mainFieldMapping['data_type'] === 'DATE') {
$badgeText = $value === 'i' ? 'Imported' : ($value === 'P' ? 'Progress' : 'LIMS'); echo "<input type='date' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
echo "<span class='status-badge $badgeClass'>" . htmlspecialchars($badgeText) . "</span>"; } elseif ($mainFieldMapping['data_type'] === 'INT') {
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value ?? 'i') . "'>"; echo "<input type='number' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} else {
echo "<input type='text' name='rows[$index][details][{$mainFieldMapping['id']}][field_value]' value='" . htmlspecialchars($fieldValue) . "' class='cell-input $inputClass' " . ($mainFieldMapping['is_required'] ? 'required' : '') . ($is_readonly ? ' readonly' : '') . ">";
} }
echo "</div>"; echo "</div>";
$cellIndex++; $cellIndex++;
} }
$rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']); // Campi automatici (escluso main_field)
$autoIndex = 0; $autoIndex = ($mainFieldMapping && !$mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) { foreach ($allMappings as $mapping) {
if (!$mapping['is_manual']) { if (!$mapping['is_manual'] && $mapping['main_field'] != 1) {
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']); $detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']);
$detail = reset($detail) ?: ['field_value' => $mapping['manual_default']]; $detail = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? ''; $fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
@ -769,9 +833,10 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$autoIndex++; $autoIndex++;
} }
} }
$manualIndex = 0; // Campi manuali (escluso main_field)
$manualIndex = ($mainFieldMapping && $mainFieldMapping['is_manual']) ? 1 : 0;
foreach ($allMappings as $mapping) { foreach ($allMappings as $mapping) {
if ($mapping['is_manual']) { if ($mapping['is_manual'] && $mapping['main_field'] != 1) {
$detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']); $detail = array_filter($rowDetails, fn($d) => $d['mapping_id'] == $mapping['id']);
$detail = reset($detail) ?: ['field_value' => $mapping['manual_default']]; $detail = reset($detail) ?: ['field_value' => $mapping['manual_default']];
$fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? ''; $fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? '';
@ -798,6 +863,32 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
$manualIndex++; $manualIndex++;
} }
} }
// Colonna status
$fixedColumnsReduced = ['status'];
foreach ($fixedColumnsReduced as $col) {
$value = $row[$col] ?? '';
echo "<div class='grid-cell editable-cell' data-col='$col' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
if ($col === 'status') {
$badgeClass = $value === 'i' ? 'status-i' : ($value === 'P' ? 'status-P' : 'status-l');
$badgeText = $value === 'i' ? 'Imported' : ($value === 'P' ? 'Progress' : 'LIMS');
echo "<span class='status-badge $badgeClass'>" . htmlspecialchars($badgeText) . "</span>";
echo "<input type='hidden' name='rows[$index][$col]' value='" . htmlspecialchars($value ?? 'i') . "'>";
}
echo "</div>";
$cellIndex++;
}
// Colonne Import Reference Code e filename_import
echo "<div class='grid-cell' data-col='importreferencecode' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
echo "<span>" . htmlspecialchars($row['importreferencecode']) . "</span>";
echo "<input type='hidden' name='rows[$index][importreferencecode]' value='" . htmlspecialchars($row['importreferencecode']) . "'>";
echo "</div>";
$cellIndex++;
echo "<div class='grid-cell' data-col='filename_import' data-row='$index' data-index='$cellIndex' style='flex: 0 0 150px;'>";
echo "<a href='imported_trf/" . htmlspecialchars($row['filename_import']) . "' target='_blank'>File</a>";
echo "<input type='hidden' name='rows[$index][filename_import]' value='" . htmlspecialchars($row['filename_import']) . "'>";
echo "</div>";
$cellIndex++;
// Colonne AWB Number e Tracking Info
?> ?>
<div class="grid-cell" style="flex: 0 0 200px;"> <div class="grid-cell" style="flex: 0 0 200px;">
<select name="rows[<?= $index ?>][carrier]" class="carrier-select" <?= $is_readonly ? 'disabled' : '' ?>> <select name="rows[<?= $index ?>][carrier]" class="carrier-select" <?= $is_readonly ? 'disabled' : '' ?>>
@ -833,6 +924,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
</ul> </ul>
</nav> </nav>
</form> </form>
<?php <?php
if (file_exists('modal_parts.php')) { if (file_exists('modal_parts.php')) {
include 'modal_parts.php'; include 'modal_parts.php';
@ -977,6 +1069,8 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
cell.classList.add('flash-success'); cell.classList.add('flash-success');
}); });
setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500); setTimeout(() => cells.forEach(cell => cell.classList.remove('flash-success')), 500);
// Ricarica i dropdown dopo il salvataggio
setTimeout(populateDropdowns, 100);
} else { } else {
alert('Errore durante il salvataggio: ' + data.message); alert('Errore durante il salvataggio: ' + data.message);
} }
@ -1119,42 +1213,49 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
}); });
// Gestione dropdown // Gestione dropdown
const dropdownData = {};
async function populateDropdowns() { async function populateDropdowns() {
if (<?= json_encode($is_readonly) ?>) return; if (<?= json_encode($is_readonly) ?>) return;
const dropdowns = document.querySelectorAll('.dropdown-select'); const dropdowns = document.querySelectorAll('.dropdown-select');
if (dropdowns.length === 0) return; if (dropdowns.length === 0) return;
const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId); const uniqueFieldIds = [...new Set(Array.from(dropdowns).map(d => d.getAttribute('data-field-id')))].filter(fieldId => fieldId);
for (const fieldId of uniqueFieldIds) { if (uniqueFieldIds.length === 0) return;
if (!dropdownData[fieldId]) {
try { try {
const response = await fetch(`get_customfield_values.php?field_id=${fieldId}`); const response = await fetch(`get_customfield_values.php?field_ids=${uniqueFieldIds.join(',')}`);
const data = await response.json(); const data = await response.json();
if (data.error) { if (data.error) {
console.error('Errore per field_id', fieldId, ':', data.error); console.error('Errore nel caricamento dei valori dei dropdown:', data.error);
continue; dropdowns.forEach(dropdown => {
} dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
dropdownData[fieldId] = data.CustomFieldsValues || []; });
} catch (error) {
console.error('Errore nel fetch per field_id', fieldId, ':', error);
}
}
}
dropdowns.forEach(dropdown => {
const fieldId = dropdown.getAttribute('data-field-id');
if (!fieldId || !dropdownData[fieldId]) {
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
return; return;
} }
dropdown.innerHTML = '<option value="">Seleziona...</option>';
dropdownData[fieldId].forEach(value => { dropdowns.forEach(dropdown => {
const option = document.createElement('option'); const fieldId = dropdown.getAttribute('data-field-id');
option.value = value.IdCustomFieldsValue; const options = data[fieldId] || [];
option.textContent = value.Valore; const currentValue = dropdown.value;
if (dropdown.value === option.value) option.selected = true;
dropdown.appendChild(option); // Rimuovi opzioni esistenti (tranne il placeholder)
dropdown.innerHTML = '<option value="">Seleziona...</option>';
// Aggiungi nuove opzioni
options.forEach(option => {
const opt = document.createElement('option');
opt.value = option.Value;
opt.textContent = option.Value;
if (currentValue === option.Value) {
opt.selected = true;
}
dropdown.appendChild(opt);
});
}); });
}); } catch (error) {
console.error('Errore nel fetch dei valori dei dropdown:', error);
dropdowns.forEach(dropdown => {
dropdown.innerHTML = '<option value="">Errore nel caricamento</option>';
});
}
} }
populateDropdowns(); populateDropdowns();
saveButtons.forEach(btn => { saveButtons.forEach(btn => {

View File

@ -28,6 +28,7 @@ document.addEventListener("DOMContentLoaded", function () {
const webcamVideo = document.getElementById("webcamVideo"); const webcamVideo = document.getElementById("webcamVideo");
const captureBtn = document.getElementById("captureBtn"); const captureBtn = document.getElementById("captureBtn");
const closeWebcamBtn = document.getElementById("closeWebcamBtn"); const closeWebcamBtn = document.getElementById("closeWebcamBtn");
const webcamSelect = document.getElementById("webcamSelect");
let stream = null; let stream = null;
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
@ -41,25 +42,116 @@ document.addEventListener("DOMContentLoaded", function () {
!webcamArea || !webcamArea ||
!webcamVideo || !webcamVideo ||
!captureBtn || !captureBtn ||
!closeWebcamBtn !closeWebcamBtn ||
!webcamSelect
) { ) {
console.error("Elementi webcam mancanti"); console.error("Elementi webcam mancanti", {
openWebcamBtn,
webcamArea,
webcamVideo,
captureBtn,
closeWebcamBtn,
webcamSelect,
});
return; return;
} }
// Apri la webcam // Funzione per avviare la webcam con un deviceId specifico
openWebcamBtn.addEventListener("click", async () => { async function startWebcam(deviceId = null) {
try { try {
stream = await navigator.mediaDevices.getUserMedia({ // Ferma il flusso video esistente, se presente
video: true, if (stream) {
}); stream.getTracks().forEach((track) => track.stop());
stream = null;
webcamVideo.srcObject = null;
}
// Configura i vincoli per getUserMedia
const constraints = {
video: deviceId ? { deviceId: { exact: deviceId } } : true,
};
// Avvia il flusso video
stream = await navigator.mediaDevices.getUserMedia(constraints);
webcamVideo.srcObject = stream; webcamVideo.srcObject = stream;
webcamArea.style.display = "block"; webcamArea.style.display = "block";
openWebcamBtn.style.display = "none"; openWebcamBtn.style.display = "none";
dropArea.style.display = "none"; dropArea.style.display = "none";
} catch (error) { } catch (error) {
console.error("Errore nell'accesso alla webcam:", error);
alert("Errore nell'accesso alla webcam: " + error.message); alert("Errore nell'accesso alla webcam: " + error.message);
webcamArea.style.display = "none";
openWebcamBtn.style.display = "block";
dropArea.style.display = "block";
} }
}
// Funzione per popolare il dropdown delle webcam
async function populateWebcamSelect() {
try {
// Richiedi i permessi per accedere ai dispositivi
await navigator.mediaDevices.getUserMedia({ video: true });
const devices = await navigator.mediaDevices.enumerateDevices();
const videoDevices = devices.filter(
(device) => device.kind === "videoinput",
);
// Svuota il dropdown
webcamSelect.innerHTML =
'<option value="">Select a webcam</option>';
// Popola il dropdown con le webcam disponibili
videoDevices.forEach((device) => {
const option = document.createElement("option");
option.value = device.deviceId;
option.text =
device.label || `Webcam ${webcamSelect.options.length}`;
webcamSelect.appendChild(option);
});
// Mostra il dropdown solo se ci sono più webcam
webcamSelect.style.display =
videoDevices.length > 1 ? "block" : "none";
// Avvia la webcam predefinita se ce n'è almeno una
if (videoDevices.length > 0) {
await startWebcam(videoDevices[0].deviceId);
} else {
alert("Nessuna webcam rilevata.");
webcamArea.style.display = "none";
openWebcamBtn.style.display = "block";
dropArea.style.display = "block";
}
} catch (error) {
console.error("Errore nel recupero dei dispositivi:", error);
alert("Errore nel recupero dei dispositivi: " + error.message);
webcamSelect.style.display = "none";
}
}
// Apri la webcam e popola il dropdown
openWebcamBtn.addEventListener("click", async () => {
await populateWebcamSelect();
});
// Gestisci il cambio della webcam selezionata
webcamSelect.addEventListener("change", async (e) => {
const deviceId = e.target.value;
if (deviceId) {
await startWebcam(deviceId);
}
});
// Chiudi la webcam
closeWebcamBtn.addEventListener("click", () => {
if (stream) {
stream.getTracks().forEach((track) => track.stop());
stream = null;
webcamVideo.srcObject = null;
}
webcamArea.style.display = "none";
openWebcamBtn.style.display = "block";
dropArea.style.display = "block";
}); });
// Cattura la foto // Cattura la foto
@ -71,7 +163,6 @@ document.addEventListener("DOMContentLoaded", function () {
.getContext("2d") .getContext("2d")
.drawImage(webcamVideo, 0, 0, canvas.width, canvas.height); .drawImage(webcamVideo, 0, 0, canvas.width, canvas.height);
// Converti l'immagine in un file
canvas.toBlob(async (blob) => { canvas.toBlob(async (blob) => {
const file = new File( const file = new File(
[blob], [blob],
@ -84,24 +175,16 @@ document.addEventListener("DOMContentLoaded", function () {
loader.style.display = "flex"; loader.style.display = "flex";
} }
await handleFiles([file], iddatadb); await handleFiles([file], iddatadb);
closeWebcam(); if (stream) {
}, "image/jpeg"); stream.getTracks().forEach((track) => track.stop());
}); stream = null;
webcamVideo.srcObject = null;
// Chiudi la webcam }
closeWebcamBtn.addEventListener("click", () => {
closeWebcam();
});
function closeWebcam() {
if (stream) {
stream.getTracks().forEach((track) => track.stop());
webcamVideo.srcObject = null;
webcamArea.style.display = "none"; webcamArea.style.display = "none";
openWebcamBtn.style.display = "block"; openWebcamBtn.style.display = "block";
dropArea.style.display = "block"; dropArea.style.display = "block";
} }, "image/jpeg");
} });
} }
// Funzione per attaccare gli event listener al contenuto del popup // Funzione per attaccare gli event listener al contenuto del popup
@ -198,6 +281,9 @@ document.addEventListener("DOMContentLoaded", function () {
}); });
const result = await response.json(); const result = await response.json();
if (result.success) { if (result.success) {
console.log(
"Foto eliminata con successo, ricarico popup",
);
loadPopupContent(iddatadb); loadPopupContent(iddatadb);
} else { } else {
alert( alert(

View File

@ -116,16 +116,19 @@ $result->saveToFile($qrCodeFile);
<input type="file" id="photoInput" multiple accept="image/*" style="display: none;"> <input type="file" id="photoInput" multiple accept="image/*" style="display: none;">
</div> </div>
<!-- Area per la webcam --> <!-- Area per la webcam -->
<!-- Area per la webcam -->
<div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;"> <div id="webcamArea" style="display: none; text-align: center; margin-bottom: 20px;">
<p>Webcam Preview</p> <p>Webcam Preview</p>
<select id="webcamSelect" style="margin-bottom: 10px; padding: 5px;">
<option value="">Select a webcam</option>
</select>
<video id="webcamVideo" autoplay playsinline style="max-width: 100%; max-height: 300px;"></video> <video id="webcamVideo" autoplay playsinline style="max-width: 100%; max-height: 300px;"></video>
<div style="margin-top: 10px;"> <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="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> <button id="closeWebcamBtn" style="padding: 10px 20px; background: #dc3545; color: white; border: none; cursor: pointer;">Close Webcam</button>
</div> </div>
</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> <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 -->
<!-- Elenco delle foto -->
<div id="photosList"> <div id="photosList">
<?php if (empty($photos)): ?> <?php if (empty($photos)): ?>
<p>No Photos present.</p> <p>No Photos present.</p>