diff --git a/app/Http/Controllers/Userarea/UploadPhotosMobileController.php b/app/Http/Controllers/Userarea/UploadPhotosMobileController.php new file mode 100644 index 0000000..ecbc7d7 --- /dev/null +++ b/app/Http/Controllers/Userarea/UploadPhotosMobileController.php @@ -0,0 +1,74 @@ +query('iddatadb'); + + if (empty($iddatadb)) { + return response('ID riga non fornito', 400); + } + + // Show the upload form + return view('userarea.upload_photos_mobile', [ + 'iddatadb' => $iddatadb + ]); + } + + public function upload(Request $request) + { + // Validation + $request->validate([ + 'photo' => 'required|file|mimes:jpeg,png,gif,heic,heif|max:5120', // 5MB + 'iddatadb' => 'required|integer' + ]); + + $iddatadb = $request->input('iddatadb'); + $photo = $request->file('photo'); + $iduserlogin = auth()->id(); // assuming Laravel authentication + + // Check if user exists + $userExists = DB::table('auth_users')->where('id', $iduserlogin)->exists(); + if (!$userExists) { + return response()->json(['success' => false, 'message' => 'Utente non valido']); + } + + // Upload folder + $uploadDir = public_path('photostrf'); + if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0755, true); + } + if (!is_writable($uploadDir)) { + return response()->json(['success' => false, 'message' => 'La cartella photostrf non è scrivibile']); + } + + // New filename + $timestamp = now()->format('YmdHis'); + $originalName = pathinfo($photo->getClientOriginalName(), PATHINFO_FILENAME); + $extension = strtolower($photo->getClientOriginalExtension()); + + $newFileName = "{$iddatadb}-{$timestamp}-{$originalName}.{$extension}"; + $destination = $uploadDir . '/' . $newFileName; + + // Move uploaded file + $photo->move($uploadDir, $newFileName); + + // Save DB record + DB::table('datadb_photos')->insert([ + 'iddatadb' => $iddatadb, + 'file_path' => $newFileName, + 'file_name' => $newFileName, + 'uploaded_by' => $iduserlogin + ]); + + return response()->json(['success' => true, 'message' => 'Foto caricata con successo']); + } +} diff --git a/public/photostrf/646-20250816171436-webcam_photo_1755364475466.jpg b/public/photostrf/646-20250816171436-webcam_photo_1755364475466.jpg new file mode 100644 index 0000000..b586815 Binary files /dev/null and b/public/photostrf/646-20250816171436-webcam_photo_1755364475466.jpg differ diff --git a/public/photostrf/646-20250816171449-webcam_photo_1755364488146.jpg b/public/photostrf/646-20250816171449-webcam_photo_1755364488146.jpg new file mode 100644 index 0000000..681d72b Binary files /dev/null and b/public/photostrf/646-20250816171449-webcam_photo_1755364488146.jpg differ diff --git a/public/photostrf/647-20250817135743-images.jpg b/public/photostrf/647-20250817135743-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/647-20250817135743-images.jpg differ diff --git a/public/photostrf/647-20250817135749-images (1).jpg b/public/photostrf/647-20250817135749-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/647-20250817135749-images (1).jpg differ diff --git a/public/photostrf/648-20250817140119-images.jpg b/public/photostrf/648-20250817140119-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/648-20250817140119-images.jpg differ diff --git a/public/photostrf/648-20250817140126-images (1).jpg b/public/photostrf/648-20250817140126-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/648-20250817140126-images (1).jpg differ diff --git a/public/photostrf/649-20250817140320-images.jpg b/public/photostrf/649-20250817140320-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/649-20250817140320-images.jpg differ diff --git a/public/photostrf/649-20250817140433-images (1).jpg b/public/photostrf/649-20250817140433-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/649-20250817140433-images (1).jpg differ diff --git a/public/photostrf/666-20250819070024-images.jpg b/public/photostrf/666-20250819070024-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/666-20250819070024-images.jpg differ diff --git a/public/photostrf/666-20250819070034-images (1).jpg b/public/photostrf/666-20250819070034-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/666-20250819070034-images (1).jpg differ diff --git a/public/photostrf/667-20250819070340-images.jpg b/public/photostrf/667-20250819070340-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/667-20250819070340-images.jpg differ diff --git a/public/photostrf/667-20250819070347-images (1).jpg b/public/photostrf/667-20250819070347-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/667-20250819070347-images (1).jpg differ diff --git a/public/photostrf/669-20250819085746-images.jpg b/public/photostrf/669-20250819085746-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/669-20250819085746-images.jpg differ diff --git a/public/photostrf/669-20250819085753-images (1).jpg b/public/photostrf/669-20250819085753-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/669-20250819085753-images (1).jpg differ diff --git a/public/photostrf/670-20250819090251-images.jpg b/public/photostrf/670-20250819090251-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/670-20250819090251-images.jpg differ diff --git a/public/photostrf/670-20250819090257-images (1).jpg b/public/photostrf/670-20250819090257-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/670-20250819090257-images (1).jpg differ diff --git a/public/photostrf/671-20250819090924-images.jpg b/public/photostrf/671-20250819090924-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/671-20250819090924-images.jpg differ diff --git a/public/photostrf/671-20250819090931-images (1).jpg b/public/photostrf/671-20250819090931-images (1).jpg new file mode 100644 index 0000000..f3b7e9a Binary files /dev/null and b/public/photostrf/671-20250819090931-images (1).jpg differ diff --git a/public/photostrf/672-20250819091301-images.jpg b/public/photostrf/672-20250819091301-images.jpg new file mode 100644 index 0000000..78882ed Binary files /dev/null and b/public/photostrf/672-20250819091301-images.jpg differ diff --git a/public/photostrf/annotated/cla_photo_649_2025-08-17T14-13-07-096Z_2025-08-17T14-13-07-096Z.png b/public/photostrf/annotated/cla_photo_649_2025-08-17T14-13-07-096Z_2025-08-17T14-13-07-096Z.png new file mode 100644 index 0000000..71a0118 Binary files /dev/null and b/public/photostrf/annotated/cla_photo_649_2025-08-17T14-13-07-096Z_2025-08-17T14-13-07-096Z.png differ diff --git a/public/photostrf/annotated/clausphoto_2025-08-16T17-10-10-237Z.png b/public/photostrf/annotated/clausphoto_2025-08-16T17-10-10-237Z.png new file mode 100644 index 0000000..00ec3e9 Binary files /dev/null and b/public/photostrf/annotated/clausphoto_2025-08-16T17-10-10-237Z.png differ diff --git a/public/photostrf/annotated/photo_667_2025-08-19T07-04-54-561Z_2025-08-19T07-04-54-561Z.png b/public/photostrf/annotated/photo_667_2025-08-19T07-04-54-561Z_2025-08-19T07-04-54-561Z.png new file mode 100644 index 0000000..005bee0 Binary files /dev/null and b/public/photostrf/annotated/photo_667_2025-08-19T07-04-54-561Z_2025-08-19T07-04-54-561Z.png differ diff --git a/public/photostrf/annotated/photo_669_2025-08-19T08-59-12-023Z_2025-08-19T08-59-12-023Z.png b/public/photostrf/annotated/photo_669_2025-08-19T08-59-12-023Z_2025-08-19T08-59-12-023Z.png new file mode 100644 index 0000000..9d39a39 Binary files /dev/null and b/public/photostrf/annotated/photo_669_2025-08-19T08-59-12-023Z_2025-08-19T08-59-12-023Z.png differ diff --git a/public/photostrf/annotated/photo_670_2025-08-19T09-04-05-078Z_2025-08-19T09-04-05-078Z.png b/public/photostrf/annotated/photo_670_2025-08-19T09-04-05-078Z_2025-08-19T09-04-05-078Z.png new file mode 100644 index 0000000..ae43dfd Binary files /dev/null and b/public/photostrf/annotated/photo_670_2025-08-19T09-04-05-078Z_2025-08-19T09-04-05-078Z.png differ diff --git a/public/photostrf/annotated/photo_670_2025-08-19T09-07-10-383Z_2025-08-19T09-07-10-383Z.png b/public/photostrf/annotated/photo_670_2025-08-19T09-07-10-383Z_2025-08-19T09-07-10-383Z.png new file mode 100644 index 0000000..5334893 Binary files /dev/null and b/public/photostrf/annotated/photo_670_2025-08-19T09-07-10-383Z_2025-08-19T09-07-10-383Z.png differ diff --git a/public/photostrf/qrcodes/qrcode_646.png b/public/photostrf/qrcodes/qrcode_646.png new file mode 100644 index 0000000..88fd547 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_646.png differ diff --git a/public/photostrf/qrcodes/qrcode_647.png b/public/photostrf/qrcodes/qrcode_647.png new file mode 100644 index 0000000..88c90d3 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_647.png differ diff --git a/public/photostrf/qrcodes/qrcode_648.png b/public/photostrf/qrcodes/qrcode_648.png new file mode 100644 index 0000000..3eb5ee6 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_648.png differ diff --git a/public/photostrf/qrcodes/qrcode_649.png b/public/photostrf/qrcodes/qrcode_649.png new file mode 100644 index 0000000..5507728 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_649.png differ diff --git a/public/photostrf/qrcodes/qrcode_666.png b/public/photostrf/qrcodes/qrcode_666.png new file mode 100644 index 0000000..6a36585 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_666.png differ diff --git a/public/photostrf/qrcodes/qrcode_667.png b/public/photostrf/qrcodes/qrcode_667.png new file mode 100644 index 0000000..1a69eec Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_667.png differ diff --git a/public/photostrf/qrcodes/qrcode_669.png b/public/photostrf/qrcodes/qrcode_669.png new file mode 100644 index 0000000..ec580bd Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_669.png differ diff --git a/public/photostrf/qrcodes/qrcode_670.png b/public/photostrf/qrcodes/qrcode_670.png new file mode 100644 index 0000000..a0e694d Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_670.png differ diff --git a/public/photostrf/qrcodes/qrcode_671.png b/public/photostrf/qrcodes/qrcode_671.png new file mode 100644 index 0000000..b2aab9d Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_671.png differ diff --git a/public/photostrf/qrcodes/qrcode_672.png b/public/photostrf/qrcodes/qrcode_672.png new file mode 100644 index 0000000..0c37ae8 Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_672.png differ diff --git a/public/photostrf/qrcodes/qrcode_699.png b/public/photostrf/qrcodes/qrcode_699.png new file mode 100644 index 0000000..f7b130a Binary files /dev/null and b/public/photostrf/qrcodes/qrcode_699.png differ diff --git a/public/userarea/get_customfield_values.php b/public/userarea/get_customfield_values.php index 6001e74..5770073 100644 --- a/public/userarea/get_customfield_values.php +++ b/public/userarea/get_customfield_values.php @@ -1,5 +1,5 @@ ერთი default + if (empty($fieldIds)) { + $fieldIds = [156]; + } - // Recupera i dati dal server - $data = $api->get($endpoint); + $results = []; - // Salva la risposta in un file per debug - file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($data)); + foreach ($fieldIds as $customFieldId) { + $endpoint = "CustomField($customFieldId)?\$expand=CustomFieldsValues"; + $data = $api->get($endpoint); - // Output JSON al client - echo json_encode($data); + $results[$customFieldId] = $data['CustomFieldsValues'] ?? []; + } + + // Debug ფაილი + file_put_contents(__DIR__ . '/customfield_values_response.json', json_encode($results)); + + echo json_encode($results); } catch (Exception $e) { http_response_code(500); echo json_encode([ diff --git a/public/userarea/import_edit2.php b/public/userarea/import_edit2.php index 8ac7f0c..e0bdfcc 100644 --- a/public/userarea/import_edit2.php +++ b/public/userarea/import_edit2.php @@ -19,11 +19,11 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['template_id']) || !i exit; } -$template_id = intval($_POST['template_id']); -$selected_rows = $_POST['selected_rows']; -$columns = json_decode($_POST['columns'], true); // Header dell'XLS -$rows = json_decode($_POST['rows'], true); // Dati dell'XLS -$newFilename = htmlspecialchars($_POST['filename']); +$template_id = intval($_POST['template_id']) ?? $_SESSION['template_id']; +$selected_rows = $_POST['selected_rows'] ?? $_SESSION['selected_rows']; +$columns = json_decode($_POST['columns'], true) ?? $_SESSION['columns']; // Header dell'XLS +$rows = json_decode($_POST['rows'], true) ?? $_SESSION['rows']; // Dati dell'XLS +$newFilename = htmlspecialchars($_POST['filename']) ?? $_SESSION['filename']; // Log dei dati ricevuti error_log("Received Data - Template ID: $template_id, Selected Rows: " . json_encode($selected_rows)); @@ -40,7 +40,7 @@ $pdo = $db->getConnection(); $importReferenceCode = date('YmdHis') . '-' . uniqid(); // Recupera tutti i mapping dal template -$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id FROM template_mapping WHERE template_id = ?"); +$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field FROM template_mapping WHERE template_id = ?"); $stmt->execute([$template_id]); $allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC); @@ -49,71 +49,82 @@ if (empty($allMappings)) { exit; } -// Inserisci le righe selezionate in datadb (solo campi generici con templateid) -$insertedIds = []; -foreach ($selected_rows as $rowIndex) { - $row = $rows[$rowIndex]; - $values = [ - $template_id, // templateid - $importReferenceCode, // importreferencecode - $newFilename, // filename_import - 'i', // status - $user_id, // user_id - null, // limscode - date('Y-m-d') // importdate - ]; - $sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)"; - $stmt = $pdo->prepare($sql); - $stmt->execute($values); - - $iddatadb = $pdo->lastInsertId(); - $insertedIds[] = $iddatadb; - - // Inserisci tutti i campi (automatici e manuali) in import_data_details - foreach ($allMappings as $mapping) { - $fieldValue = null; - if (!$mapping['is_manual']) { // Campi automatici dall'XLS - $excelColumn = trim($mapping['excel_column']); - $excelColumnIndex = array_search($excelColumn, array_map('trim', $columns)); - if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') { - $fieldValue = $row[$excelColumnIndex]; - error_log("Found Excel column '$excelColumn' at index $excelColumnIndex, value: " . var_export($fieldValue, true)); - } else { - $fieldValue = $mapping['manual_default'] ?? ''; - error_log("Excel column '$excelColumn' not found or empty, using default: " . var_export($fieldValue, true)); - } - switch ($mapping['data_type']) { - case 'INT': - $fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0); - break; - case 'DATE': - $fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? '')); - break; - case 'CHAR': - $fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? ''); - break; - case 'Testo': - case 'VARCHAR': - default: - $fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? ''); - break; - } - } else { // Campi manuali - $fieldValue = $mapping['manual_default'] ?? ''; - if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') { - $fieldValue = date('Y-m-d'); - } - } - if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) { - error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']); - } - error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Excel Column: " . ($mapping['excel_column'] ?? 'N/A') . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A')); - $stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)"); - $stmt->execute([$iddatadb, $mapping['id'], $fieldValue]); - error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true)); +// Trova il campo main_field +$mainFieldMapping = null; +foreach ($allMappings as $mapping) { + if ($mapping['main_field'] == 1) { + $mainFieldMapping = $mapping; + break; } } +//// Inserisci le righe selezionate in datadb (solo campi generici con templateid) +//$insertedIds = []; +//foreach ($selected_rows as $rowIndex) { +// $row = $rows[$rowIndex]; +// $values = [ +// $template_id, // templateid +// $importReferenceCode, // importreferencecode +// $newFilename, // filename_import +// 'i', // status +// $user_id, // user_id +// null, // limscode +// date('Y-m-d') // importdate +// ]; +// $sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)"; +// $stmt = $pdo->prepare($sql); +// $stmt->execute($values); +// +// $iddatadb = $pdo->lastInsertId(); +// $insertedIds[] = $iddatadb; +// +// // Inserisci tutti i campi (automatici e manuali) in import_data_details +// foreach ($allMappings as $mapping) { +// $fieldValue = null; +// if (!$mapping['is_manual']) { // Campi automatici dall'XLS +// $excelColumn = trim($mapping['excel_column']); +// $excelColumnIndex = array_search($excelColumn, array_map('trim', $columns)); +// if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') { +// $fieldValue = $row[$excelColumnIndex]; +// error_log("Found Excel column '$excelColumn' at index $excelColumnIndex, value: " . var_export($fieldValue, true)); +// } else { +// $fieldValue = $mapping['manual_default'] ?? ''; +// error_log("Excel column '$excelColumn' not found or empty, using default: " . var_export($fieldValue, true)); +// } +// switch ($mapping['data_type']) { +// case 'INT': +// $fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0); +// break; +// case 'DATE': +// $fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? '')); +// break; +// case 'CHAR': +// $fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? ''); +// break; +// case 'Testo': +// case 'VARCHAR': +// default: +// $fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? ''); +// break; +// } +// } else { // Campi manuali +// $fieldValue = $mapping['manual_default'] ?? ''; +// if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') { +// $fieldValue = date('Y-m-d'); +// } +// } +// if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) { +// error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']); +// } +// error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Excel Column: " . ($mapping['excel_column'] ?? 'N/A') . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A')); +// $stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)"); +// $stmt->execute([$iddatadb, $mapping['id'], $fieldValue]); +// error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true)); +// } +//} + +$insertedIds = $_POST['inserted_ids'] ?? $_SESSION['inserted_ids']; + // Recupera i dati appena inseriti con i nomi degli utenti $stmt = $pdo->prepare(" SELECT d.*, CONCAT(u.first_name, ' ', u.last_name) AS user_name @@ -221,7 +232,8 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { .grid-header, .grid-cell { flex: 1; - min-width: 100px; + min-width: 70px; + /* Ridotto da 100px per compatibilità con pulsanti */ padding: 12px 15px; border-right: 1px solid #dee2e6; overflow: hidden; @@ -397,6 +409,25 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { border-color: #80bdff; box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); } + + /* Sovrascrivi min-width per le celle dei pulsanti */ + .grid-cell.button-cell, + .grid-header.button-header { + min-width: 70px !important; + flex: 0 0 70px !important; + } + + /* Stile per l'header dei pulsanti */ + .button-header { + min-height: 48px; + /* Altezza minima per uniformare */ + padding: 12px 0; + /* Centra verticalmente, no padding orizzontale */ + background-color: #e9ecef !important; + /* Grigio uniforme */ + border-right: 1px solid #dee2e6 !important; + /* Bordo destro coerente */ + } Edit Imported Data - <?= htmlspecialchars($titlewebsite, ENT_QUOTES, 'UTF-8'); ?> @@ -407,13 +438,21 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
- +
Modifica Dati Importati
+
@@ -422,19 +461,46 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
-
-
-
+
+
+
+ +
+ "; + echo ""; + echo ""; + echo ""; + } elseif ($mainFieldMapping['data_type'] === 'DATE') { + echo ""; + echo ""; + } elseif ($mainFieldMapping['data_type'] === 'INT') { + echo ""; + echo ""; + } else { + echo ""; + echo ""; + } + ?> +
+
"; } - // Campi automatici (is_manual = 0) - Solo SceltaMultipla ha campo e propagazione + // Campi automatici (is_manual = 0) escluso main_field $autoIndex = 0; foreach ($allMappings as $mapping) { - if (!$mapping['is_manual']) { + if (!$mapping['is_manual'] && $mapping['main_field'] != 1) { $inputClass = 'auto-input'; if ($mapping['is_required']) $inputClass .= ' required-input'; if ($mapping['data_type'] === 'SceltaMultipla') { @@ -445,15 +511,15 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { echo ""; echo "
"; } else { - echo "
"; // Nessun input per altri tipi + echo "
"; } $autoIndex++; } } - // Campi manuali (is_manual = 1) con propagate-btn - Rimane invariato + // Campi manuali (is_manual = 1) escluso main_field $manualIndex = 0; foreach ($allMappings as $mapping) { - if ($mapping['is_manual']) { + 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'); @@ -465,7 +531,6 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { echo ""; - echo ""; } elseif ($mapping['data_type'] === 'DATE') { echo ""; } elseif ($mapping['data_type'] === 'INT') { @@ -485,26 +550,32 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
-
Save
-
Photos
-
Parts
-
Import Reference Code
+
+
+
+ +
+ +
+
+ +
Import Reference Code
$displayName
"; $headerIndex++; } foreach ($allMappings as $mapping) { - if (!$mapping['is_manual']) { + if (!$mapping['is_manual'] && $mapping['main_field'] != 1) { echo "
" . htmlspecialchars($mapping['field_label']) . "
"; $headerIndex++; } } foreach ($allMappings as $mapping) { - if ($mapping['is_manual']) { + if ($mapping['is_manual'] && $mapping['main_field'] != 1) { echo "
" . htmlspecialchars($mapping['field_label']) . "
"; $headerIndex++; } @@ -517,22 +588,47 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $row): ?>
-
- +
+
-
- +
+
-
- +
+ +
+ + $d['mapping_id'] == $mainFieldMapping['id'] && $d['datadb_id'] == $row['iddatadb']); + $detail = reset($detail) ?: ['field_value' => $mainFieldMapping['manual_default']]; + $fieldValue = $detail['field_value'] ?? $mainFieldMapping['manual_default'] ?? ''; + if ($mainFieldMapping['data_type'] === 'DATE' && $mainFieldMapping['manual_default'] === 'today' && empty($fieldValue)) { + $fieldValue = date('Y-m-d'); + } + $requiredClass = ($mainFieldMapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) ? 'missing-required' : ''; + $inputClass = $mainFieldMapping['is_manual'] ? 'manual-input' : 'auto-input'; + if ($mainFieldMapping['is_required']) $inputClass .= ' required-input'; + ?> +
+ + + + > + + > + + > + +
+ +
+ +
"; - echo "" . htmlspecialchars($row['importreferencecode']) . ""; - echo ""; - echo "
"; - $cellIndex++; + $cellIndex = $mainFieldMapping ? 5 : 4; foreach ($fixedColumns as $col) { $value = $row[$col] ?? ''; echo "
"; @@ -552,7 +648,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $rowDetails = array_filter($manualDetails, fn($d) => $d['datadb_id'] == $row['iddatadb']); $autoIndex = 0; 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 = reset($detail) ?: ['field_value' => $mapping['manual_default']]; $fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? ''; @@ -578,7 +674,7 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { } $manualIndex = 0; 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 = reset($detail) ?: ['field_value' => $mapping['manual_default']]; $fieldValue = $detail['field_value'] ?? $mapping['manual_default'] ?? ''; @@ -640,6 +736,38 @@ foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { + + - + + + - + --> - \ No newline at end of file + diff --git a/public/userarea/import_insert.php b/public/userarea/import_insert.php new file mode 100644 index 0000000..7a8d012 --- /dev/null +++ b/public/userarea/import_insert.php @@ -0,0 +1,157 @@ +getConnection(); + +// Genera un UUID univoco per importreferencecode +$importReferenceCode = date('YmdHis') . '-' . uniqid(); + +// Recupera tutti i mapping dal template +$stmt = $pdo->prepare("SELECT id, excel_column, data_type, is_required, manual_default, is_manual, field_label, field_id, main_field FROM template_mapping WHERE template_id = ?"); +$stmt->execute([$template_id]); +$allMappings = $stmt->fetchAll(PDO::FETCH_ASSOC); + +if (empty($allMappings)) { + header("Location: import_xls.php?id=$template_id&status=error&message=" . urlencode("Nessun mapping trovato per il template")); + exit; +} + +// Trova il campo main_field +$mainFieldMapping = null; +foreach ($allMappings as $mapping) { + if ($mapping['main_field'] == 1) { + $mainFieldMapping = $mapping; + break; + } +} + +// Inserisci le righe selezionate in datadb (solo campi generici con templateid) +$insertedIds = []; +foreach ($selected_rows as $rowIndex) { + $row = $rows[$rowIndex]; + $values = [ + $template_id, // templateid + $importReferenceCode, // importreferencecode + $newFilename, // filename_import + 'i', // status + $user_id, // user_id + null, // limscode + date('Y-m-d') // importdate + ]; + $sql = "INSERT INTO datadb (templateid, importreferencecode, filename_import, status, user_id, limscode, importdate) VALUES (?, ?, ?, ?, ?, ?, ?)"; + $stmt = $pdo->prepare($sql); + $stmt->execute($values); + + $iddatadb = $pdo->lastInsertId(); + $insertedIds[] = $iddatadb; + + // Inserisci tutti i campi (automatici e manuali) in import_data_details + foreach ($allMappings as $mapping) { + $fieldValue = null; + if (!$mapping['is_manual']) { // Campi automatici dall'XLS + $excelColumn = trim($mapping['excel_column']); + $excelColumnIndex = array_search($excelColumn, array_map('trim', $columns)); + if ($excelColumnIndex !== false && isset($row[$excelColumnIndex]) && $row[$excelColumnIndex] !== '') { + $fieldValue = $row[$excelColumnIndex]; + error_log("Found Excel column '$excelColumn' at index $excelColumnIndex, value: " . var_export($fieldValue, true)); + } else { + $fieldValue = $mapping['manual_default'] ?? ''; + error_log("Excel column '$excelColumn' not found or empty, using default: " . var_export($fieldValue, true)); + } + switch ($mapping['data_type']) { + case 'INT': + $fieldValue = is_numeric($fieldValue) ? (int)$fieldValue : ($mapping['manual_default'] ?? 0); + break; + case 'DATE': + $fieldValue = !empty($fieldValue) ? date('Y-m-d', strtotime($fieldValue)) : ($mapping['manual_default'] === 'today' ? date('Y-m-d') : ($mapping['manual_default'] ?? '')); + break; + case 'CHAR': + $fieldValue = !empty($fieldValue) ? substr((string)$fieldValue, 0, 1) : ($mapping['manual_default'] ?? ''); + break; + case 'Testo': + case 'VARCHAR': + default: + $fieldValue = !empty($fieldValue) ? htmlspecialchars((string)$fieldValue) : ($mapping['manual_default'] ?? ''); + break; + } + } else { // Campi manuali + $fieldValue = $mapping['manual_default'] ?? ''; + if ($mapping['data_type'] === 'DATE' && $mapping['manual_default'] === 'today') { + $fieldValue = date('Y-m-d'); + } + } + if ($mapping['is_required'] && (is_null($fieldValue) || $fieldValue === '')) { + error_log("Required field missing for mapping ID: " . $mapping['id'] . ", field: " . $mapping['field_label']); + } + error_log("Inserting into import_data_details - Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true) . ", Is Manual: " . $mapping['is_manual'] . ", Excel Column: " . ($mapping['excel_column'] ?? 'N/A') . ", Manual Default: " . ($mapping['manual_default'] ?? 'N/A')); + $stmt = $pdo->prepare("INSERT INTO import_data_details (id, mapping_id, field_value) VALUES (?, ?, ?)"); + $stmt->execute([$iddatadb, $mapping['id'], $fieldValue]); + error_log("Inserted into import_data_details for ID $iddatadb, Mapping ID: " . $mapping['id'] . ", Field Value: " . var_export($fieldValue, true)); + } +} + +$_SESSION['inserted_ids'] = $insertedIds; + +$params = [ + 'template_id' => $template_id, + 'filename' => $newFilename, +]; + +?> +
+ + + + + + + + + + + + + +
+ + - - @@ -205,7 +205,7 @@ error_log("Loaded template: " . print_r($template, true)); errorContainer.style.display = 'block'; } else { let html = ` -
+ @@ -326,4 +326,4 @@ error_log("Loaded template: " . print_r($template, true)); - \ No newline at end of file + diff --git a/public/userarea/load_photo.php b/public/userarea/load_photo.php index 34ca8e2..f3ac03b 100644 --- a/public/userarea/load_photo.php +++ b/public/userarea/load_photo.php @@ -14,13 +14,18 @@ if (!$iddatadb) { } try { - $stmt = $pdo->prepare("SELECT file_path FROM datadb_photos WHERE iddatadb = :iddatadb LIMIT 1"); + // Adjust the query to select all photo paths for the given iddatadb + $stmt = $pdo->prepare("SELECT file_path FROM datadb_photos WHERE iddatadb = :iddatadb"); $stmt->execute([':iddatadb' => $iddatadb]); - $photo = $stmt->fetch(PDO::FETCH_ASSOC); + $photos = $stmt->fetchAll(PDO::FETCH_ASSOC); - if ($photo && $photo['file_path']) { - $fullPath = '../photostrf/' . $photo['file_path']; // Assumi che le foto siano nella cartella photostrf - echo json_encode(['success' => true, 'file_path' => $fullPath]); + if ($photos && count($photos) > 0) { + // Prepare an array of full file paths + $photoPaths = array_map(function($photo) { + return '../photostrf/' . $photo['file_path']; // Assuming the photos are stored in the "photostrf" folder + }, $photos); + + echo json_encode(['success' => true, 'photos' => $photoPaths]); // Return an array of photo paths } else { echo json_encode(['success' => false, 'message' => 'Nessuna foto trovata']); } diff --git a/public/userarea/modal_parts.php b/public/userarea/modal_parts.php index b1e00cd..de85c1a 100644 --- a/public/userarea/modal_parts.php +++ b/public/userarea/modal_parts.php @@ -13,29 +13,32 @@
    - - - - - + + + + + - - - - - + + + + +
    Num. ParteDescrizione ParteAzioni
    Num. ParteDescrizione ParteAzioni
    - - - - - -
    + + + + + +
    Foto del Campione
    +
    Foto del campione @@ -142,4 +145,24 @@ padding: 0.1rem 0.3rem; font-size: 0.8rem; } - \ No newline at end of file + + /* ნორმალური Save ღილაკი */ + #savePhotoBtn { + transition: all 0.3s ease-in-out; + } + + /* დაუმახსოვრებელი ცვლილებები */ + #savePhotoBtn.unsaved { + background-color: #dc3545 !important; /* წითელი */ + border-color: #dc3545 !important; + color: white !important; + animation: pulse 1.2s infinite; + } + + /* ლამაზი პულსაცია */ + @keyframes pulse { + 0% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.7); } + 70% { box-shadow: 0 0 10px 15px rgba(220, 53, 69, 0); } + 100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); } + } + diff --git a/public/userarea/parts.js b/public/userarea/parts.js index 3b5690c..a3267e8 100644 --- a/public/userarea/parts.js +++ b/public/userarea/parts.js @@ -1,7 +1,28 @@ $(document).ready(function () { console.log("parts.js caricato correttamente"); - // Gestione del popup per le parti + // =================== + // GLOBAL STATE (NEW) + // =================== + let photoData = { + naturalWidth: 0, + naturalHeight: 0, + displayWidth: 0, + displayHeight: 0, + scale: 1, + }; + + // markers keyed by photo src => [{ partNumber, x, y } using NATURAL coords] + let photoMarkers = {}; + + // selection & descriptions + let selectedPartNumber = null; + let descriptionPosition = {x: 10, y: 10}; // NATURAL coords + let hasDescriptions = false; + + // =================== + // POPUP HANDLING + // =================== const partsButtons = document.querySelectorAll(".parts-btn"); const partsModal = document.getElementById("partsModal"); const closeBtn = document.querySelector("#partsModal .close-btn"); @@ -12,14 +33,8 @@ $(document).ready(function () { console.log("Pulsante Parts cliccato"); const iddatadb = $(this).data("iddatadb"); const rowIndex = $(this).data("row"); - const importRef = $("table tbody tr") - .eq(rowIndex) - .find("td") - .eq(1) - .text(); - const description = - $("table tbody tr").eq(rowIndex).find("td").eq(2).text() || - "Sconosciuto"; + const importRef = $("table tbody tr").eq(rowIndex).find("td").eq(1).text(); + const description = $("table tbody tr").eq(rowIndex).find("td").eq(2).text() || "Sconosciuto"; $("#trfHeader").text(`${iddatadb} - ${importRef} - ${description}`); $("#partsModal").data("iddatadb", iddatadb); @@ -36,7 +51,6 @@ $(document).ready(function () { }); }); - // Gestione della chiusura del modal Parts if (closeBtn) { closeBtn.addEventListener("click", function () { partsModal.style.display = "none"; @@ -55,41 +69,26 @@ $(document).ready(function () { }); } + // =================== + // PHOTO LOADERS + // =================== function loadPhoto(iddatadb) { $.ajax({ url: "load_photo.php", method: "GET", - data: { iddatadb: iddatadb }, + data: {iddatadb: iddatadb}, success: function (response) { - if (response.success && response.file_path) { - const img = $("#samplePhoto"); - img.attr("src", response.file_path); - img.on("load", function () { - const container = img.parent(); - const canvas = document.getElementById("photoCanvas"); - const containerWidth = container.width(); - const containerHeight = container.height(); - const scaleX = containerWidth / img[0].naturalWidth; - const scaleY = containerHeight / img[0].naturalHeight; - const scale = Math.min(scaleX, scaleY); - canvas.width = img[0].naturalWidth * scale; - canvas.height = img[0].naturalHeight * scale; - canvas.style.width = `${containerWidth}px`; - canvas.style.height = `${containerHeight}px`; - const ctx = canvas.getContext("2d"); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage( - img.get(0), - 0, - 0, - canvas.width, - canvas.height, - ); - updateMarkers(); - }); + if (response.success) { + if (response.photos && response.photos.length > 1) { + showPhotoSelector(response.photos); + } else if (response.photos && response.photos.length === 1) { + loadSinglePhoto(response.photos[0]); + } else { + $("#samplePhoto").attr("src", ""); + alert("Nessuna foto trovata per questo TRF."); + } } else { - $("#samplePhoto").attr("src", ""); - alert("Nessuna foto trovata per questo TRF."); + alert(response.message || "Errore nel caricamento della foto."); } }, error: function (xhr, status, error) { @@ -98,10 +97,89 @@ $(document).ready(function () { }); } + function showPhotoSelector(photos) { + const selectorContainer = $("#photoSelectorContainer"); + selectorContainer.empty(); + + const selector = $(''); + photos.forEach((photo, index) => { + const option = $('').val(photo).text(`Photo ${index + 1}`); + // display option with photo name if available + if (photo.includes("/")) { + const photoName = photo.split("/").pop(); + option.text(`Photo ${index + 1} - ${photoName}`); + } + selector.append(option); + }); + + selector.on("change", function () { + const selectedPhoto = $(this).val(); + loadSinglePhoto(selectedPhoto); + }); + + selectorContainer.append(selector); + selectorContainer.show(); + + if (photos.length > 0) { + selector.val(photos[0]); + loadSinglePhoto(photos[0]); + } + } + + function loadSinglePhoto(photoPath) { + const img = $("#samplePhoto"); + img.off("load"); // avoid stacking multiple handlers + img.attr("src", photoPath); + + img.on("load", function () { + const canvas = document.getElementById("photoCanvas"); + const ctx = canvas.getContext("2d"); + + // Real image size + const naturalWidth = img[0].naturalWidth; + const naturalHeight = img[0].naturalHeight; + + // Compute scale to FIT inside its parent without distorting aspect ratio + const parent = $(canvas).parent(); + const maxW = parent.width(); + const maxH = parent.height(); + const scale = Math.min(maxW / naturalWidth, maxH / naturalHeight); + + // Display size on screen + const displayWidth = Math.max(1, Math.round(naturalWidth * scale)); + const displayHeight = Math.max(1, Math.round(naturalHeight * scale)); + + // Save globally + photoData = {naturalWidth, naturalHeight, displayWidth, displayHeight, scale}; + + // Canvas in REAL size (so saving uses natural coords 1:1) + canvas.width = naturalWidth; + canvas.height = naturalHeight; + + // Visual size on screen + canvas.style.width = `${displayWidth}px`; + canvas.style.height = `${displayHeight}px`; + + // Also size/align the overlay containers to match the canvas + $("#markerContainer").css({width: `${displayWidth}px`, height: `${displayHeight}px`}); + $("#descriptionList").css({maxWidth: `${Math.max(200, Math.round(displayWidth * 0.35))}px`}); + + // Draw fresh image at full resolution + ctx.clearRect(0, 0, naturalWidth, naturalHeight); + ctx.drawImage(img.get(0), 0, 0, naturalWidth, naturalHeight); + + updateMarkers(); + if (hasDescriptions) drawDescriptions(descriptionPosition.x, descriptionPosition.y); + }); + } + + // =================== + // PARTS TABLE + // =================== function addNewRow(nextPartNumber, isMix = false) { const description = isMix ? "Mix" : ""; const newRow = ` - + @@ -111,33 +189,25 @@ $(document).ready(function () { - - `; + `; $("#partsTableBody").append(newRow); updateRowButtons(); } function updateRowButtons() { const rowCount = $("#partsTableBody tr").length; - $("#partsTableBody tr").each(function (index) { + $("#partsTableBody tr").each(function () { const $removeBtn = $(this).find(".remove-row"); - if (rowCount > 1) { - $removeBtn.show(); - } else { - $removeBtn.hide(); - } + if (rowCount > 1) $removeBtn.show(); else $removeBtn.hide(); }); } $(document).on("click", ".add-row", function (e) { e.preventDefault(); - console.log("Pulsante Aggiungi riga cliccato"); const maxPartNumber = Math.max( - ...$("#partsTableBody tr") - .map(function () { - return parseInt($(this).find(".part-number").val()) || 0; - }) - .get(), + ...$("#partsTableBody tr").map(function () { + return parseInt($(this).find(".part-number").val()) || 0; + }).get(), ); addNewRow(maxPartNumber + 1); updatePartsList(); @@ -145,13 +215,10 @@ $(document).ready(function () { $(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(), + ...$("#partsTableBody tr").map(function () { + return parseInt($(this).find(".part-number").val()) || 0; + }).get(), ); addNewRow(maxPartNumber + 1, true); updatePartsList(); @@ -159,26 +226,16 @@ $(document).ready(function () { $(document).on("click", ".remove-row", function (e) { e.preventDefault(); - console.log("Pulsante Rimuovi riga cliccato"); const $row = $(this).closest("tr"); const partId = $row.data("part-id"); - console.log("ID parte da eliminare:", partId); if (partId !== "new" && partId !== undefined && partId !== null) { - console.log("Procedo con la cancellazione dal database"); $.ajax({ url: "delete_part.php", method: "POST", - data: JSON.stringify({ part_id: partId }), + data: JSON.stringify({part_id: partId}), contentType: "application/json", - beforeSend: function () { - console.log( - "Invio richiesta AJAX a delete_part.php con part_id:", - partId, - ); - }, success: function (response) { - console.log("Risposta da delete_part.php:", response); if (response.success) { $row.remove(); updateRowButtons(); @@ -189,21 +246,10 @@ $(document).ready(function () { } }, error: function (xhr, status, error) { - console.log("Errore AJAX:", status, error); - alert( - "Errore nell'eliminazione: " + - error + - ". Stato: " + - xhr.status + - " - " + - xhr.responseText, - ); + alert("Errore nell'eliminazione: " + error + ". Stato: " + xhr.status + " - " + xhr.responseText); }, }); } else { - console.log( - 'Riga non salvata nel database (partId = "new" o non definito), rimuovo solo visivamente', - ); $row.remove(); updateRowButtons(); updatePartsList(); @@ -220,11 +266,8 @@ $(document).ready(function () { const iddatadb = $("#partsModal").data("iddatadb"); const isMix = partDescription.startsWith("Mix") ? "Y" : "N"; - console.log("Evento blur su input:", { - partNumber, - partDescription, - isMix, - }); + // არსებული part-id row-დან (თუ უკვე არსებობს) + const partId = $row.data("part-id") || null; if (partDescription && iddatadb) { $saveLoading.show(); @@ -237,6 +280,7 @@ $(document).ready(function () { iddatadb: iddatadb, parts: [ { + id: partId, // გავგზავნე part-ის ID (თუ არის) part_number: partNumber, part_description: partDescription, mix: isMix, @@ -246,16 +290,14 @@ $(document).ready(function () { contentType: "application/json", success: function (response) { if (response.success) { - if (response.part_id) { - $row.data("part-id", response.part_id); - console.log( - "Aggiornato partId della riga:", - response.part_id, - ); - } $saveLoading.hide(); $saveStatus.show(); updatePartsList(); + // თუ ახალია, backend-მა მოგვცა ახალი ID + if (response.part_id) { + $row.attr("data-part-id", response.part_id); + $row.data("part-id", response.part_id); + } setTimeout(() => $saveStatus.hide(), 2000); } else { alert("Errore nel salvataggio: " + response.message); @@ -274,7 +316,7 @@ $(document).ready(function () { $.ajax({ url: "load_parts.php", method: "GET", - data: { iddatadb: iddatadb }, + data: {iddatadb: iddatadb}, success: function (response) { if (response.success) { $("#partsTableBody").empty(); @@ -291,8 +333,7 @@ $(document).ready(function () { - - `; + `; $("#partsTableBody").append(newRow); }); } else { @@ -301,10 +342,7 @@ $(document).ready(function () { updateRowButtons(); updatePartsList(); } else { - alert( - "Errore nel caricamento delle parti: " + - response.message, - ); + alert("Errore nel caricamento delle parti: " + response.message); addNewRow(1); } }, @@ -320,11 +358,7 @@ $(document).ready(function () { $("#partsTableBody tr").each(function () { const partNumber = $(this).find(".part-number").val(); const partDescription = $(this).find(".part-description").val(); - if ( - partNumber && - partDescription && - !partDescription.startsWith("Mix") - ) { + if (partNumber && partDescription && !partDescription.startsWith("Mix")) { const listItem = `
  • ${partNumber} - ${partDescription} @@ -337,15 +371,10 @@ $(document).ready(function () { $(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(); + const partDescription = $listItem.text().split(" - ")[1].trim(); + 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'."); @@ -360,167 +389,131 @@ $(document).ready(function () { } else if (!currentDescription.includes(partDescription)) { currentDescription += ` + ${partDescription}`; } else { - return; // Parte già presente, non aggiungerla + return; } $descriptionInput.val(currentDescription); - $descriptionInput.trigger("blur"); // Attiva il salvataggio + $descriptionInput.trigger("blur"); updatePartsList(); }); - let selectedPartNumber = null; - let markers = []; - let descriptionPosition = { x: 10, y: 10 }; - let hasDescriptions = false; - $("#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"); }); + // =================== + // MARKERS & DESCRIPTIONS + // =================== const canvas = document.getElementById("photoCanvas"); const ctx = canvas.getContext("2d"); $("#markerContainer").on("click", function (e) { - console.log("Click sul markerContainer rilevato"); - if (selectedPartNumber !== null) { - const img = $("#samplePhoto"); - const canvas = document.getElementById("photoCanvas"); - const rect = canvas.getBoundingClientRect(); - const container = img.parent(); - const containerWidth = container.width(); - const containerHeight = container.height(); - const scaleX = containerWidth / img.get(0).naturalWidth; - const scaleY = containerHeight / img.get(0).naturalHeight; - const scale = Math.min(scaleX, scaleY); - const x = (e.clientX - rect.left) / scale; - const y = (e.clientY - rect.top) / scale; + if (selectedPartNumber === null) return; - console.log("Coordinate cliccate (x, y):", x, y); + const rect = canvas.getBoundingClientRect(); + const clickX = e.clientX - rect.left; + const clickY = e.clientY - rect.top; - const existingMarker = markers.find( - (m) => m.partNumber == selectedPartNumber, - ); - if (existingMarker) { - existingMarker.x = x; - existingMarker.y = y; - } else { - markers.push({ partNumber: selectedPartNumber, x, y }); - } - console.log("Markers aggiornati:", markers); - updateMarkers(); - if (hasDescriptions) { - drawDescriptions(descriptionPosition.x, descriptionPosition.y); - } - selectedPartNumber = null; - $("#partsList li").removeClass("active"); + const x = clickX / photoData.scale; // convert to NATURAL coords + const y = clickY / photoData.scale; + + const currentPhoto = $("#samplePhoto").attr("src"); + if (!photoMarkers[currentPhoto]) photoMarkers[currentPhoto] = []; + + const existingMarker = photoMarkers[currentPhoto].find(m => m.partNumber == selectedPartNumber); + if (existingMarker) { + existingMarker.x = x; + existingMarker.y = y; } else { - console.log("Nessun part number selezionato"); + photoMarkers[currentPhoto].push({partNumber: selectedPartNumber, x, y}); } + + updateMarkers(); + if (hasDescriptions) drawDescriptions(descriptionPosition.x, descriptionPosition.y); + + selectedPartNumber = null; + $("#partsList li").removeClass("active"); }); function updateMarkers() { - const img = $("#samplePhoto"); - const container = img.parent(); - const containerWidth = container.width(); - const containerHeight = container.height(); - const scaleX = containerWidth / img.get(0).naturalWidth; - const scaleY = containerHeight / img.get(0).naturalHeight; - const scale = Math.min(scaleX, scaleY); - const markerContainer = $("#markerContainer"); markerContainer.empty(); + // keep overlay sized to canvas display + markerContainer.css({width: `${photoData.displayWidth}px`, height: `${photoData.displayHeight}px`}); + + const currentPhoto = $("#samplePhoto").attr("src"); + const markers = photoMarkers[currentPhoto] || []; + markers.forEach((marker) => { - const scaledX = marker.x * scale; - const scaledY = marker.y * scale; - console.log( - "Aggiungo marker:", - marker.partNumber, - "a posizione (scaledX, scaledY):", - scaledX, - scaledY, - ); - const $marker = $( - `
    ${marker.partNumber}
    `, - ).css({ + const scaledX = marker.x * photoData.scale; + const scaledY = marker.y * photoData.scale; + + const $marker = $(`
    ${marker.partNumber}
    `).css({ left: scaledX - 8 + "px", top: scaledY - 8 + "px", }); markerContainer.append($marker); - makeDraggable($marker, marker, scale); + makeDraggable($marker, marker); }); } - function makeDraggable($element, item, scale) { + function makeDraggable($element, item) { let isDragging = false; - let currentX = parseFloat($element.css("left")) || 0; - let currentY = parseFloat($element.css("top")) || 0; - let initialX, initialY; + let startLeft = 0; + let startTop = 0; + let initialX = 0; + let initialY = 0; $element.on("mousedown", function (e) { e.preventDefault(); isDragging = true; - initialX = e.clientX - currentX; - initialY = e.clientY - currentY; + startLeft = parseFloat($element.css("left")) || 0; + startTop = parseFloat($element.css("top")) || 0; + initialX = e.clientX - startLeft; + initialY = e.clientY - startTop; $element.css("z-index", 1001); }); - $(document).on("mousemove", function (e) { - if (isDragging) { - e.preventDefault(); - currentX = e.clientX - initialX; - currentY = e.clientY - initialY; - const container = $("#photoCanvas").parent(); - const containerWidth = container.width(); - const containerHeight = container.height(); - const maxX = containerWidth - $element.width(); - const maxY = containerHeight - $element.height(); + $(document).on("mousemove.dragMarker", function (e) { + if (!isDragging) return; + let currentX = e.clientX - initialX; + let currentY = e.clientY - initialY; - currentX = Math.max(0, Math.min(currentX, maxX)); - currentY = Math.max(0, Math.min(currentY, maxY)); + const maxX = photoData.displayWidth - $element.width(); + const maxY = photoData.displayHeight - $element.height(); - $element.css({ - left: currentX + "px", - top: currentY + "px", - }); + currentX = Math.max(0, Math.min(currentX, maxX)); + currentY = Math.max(0, Math.min(currentY, maxY)); - if (item.partNumber) { - item.x = (currentX + 8) / scale; - item.y = (currentY + 8) / scale; - } else { - descriptionPosition.x = (currentX + 5) / scale; - descriptionPosition.y = (currentY + 5) / scale; - } + $element.css({left: currentX + "px", top: currentY + "px"}); + + if (item && item.partNumber) { + item.x = (currentX + 8) / photoData.scale; + item.y = (currentY + 8) / photoData.scale; + } else { + // draggable description panel + descriptionPosition.x = (currentX + 5) / photoData.scale; + descriptionPosition.y = (currentY + 5) / photoData.scale; } }); - $(document).on("mouseup", function () { + $(document).on("mouseup.dragMarker", function () { + if (!isDragging) return; isDragging = false; $element.css("z-index", 1000); + $(document).off("mousemove.dragMarker mouseup.dragMarker"); }); } function drawDescriptions(x, y) { - const img = $("#samplePhoto"); - const container = img.parent(); - const containerWidth = container.width(); - const containerHeight = container.height(); - const scaleX = containerWidth / img.get(0).naturalWidth; - const scaleY = containerHeight / img.get(0).naturalHeight; - const scale = Math.min(scaleX, scaleY); - const partsList = []; $("#partsTableBody tr").each(function () { const partNumber = $(this).find(".part-number").val(); const partDescription = $(this).find(".part-description").val(); - if ( - partNumber && - partDescription && - !partDescription.startsWith("Mix") - ) { + if (partNumber && partDescription && !partDescription.startsWith("Mix")) { partsList.push(`${partNumber} ${partDescription}`); } }); @@ -529,148 +522,223 @@ $(document).ready(function () { descriptionList.empty(); descriptionList.css({ display: "block", - top: y * scale + "px", - left: x * scale + "px", - width: "200px", - }); - partsList.forEach((part) => { - descriptionList.append(`
    ${part}
    `); + top: y * photoData.scale + "px", + left: x * photoData.scale + "px", }); + partsList.forEach((part) => descriptionList.append(`
    ${part}
    `)); updateMarkers(); } function clearCanvasMarkers() { - markers = []; + const currentPhoto = $("#samplePhoto").attr("src"); + photoMarkers[currentPhoto] = []; hasDescriptions = false; $("#descriptionList").css("display", "none"); $("#markerContainer").empty(); - const canvas = document.getElementById("photoCanvas"); - const img = $("#samplePhoto"); - const ctx = canvas.getContext("2d"); - const container = img.parent(); - const containerWidth = container.width(); - const containerHeight = container.height(); - const scaleX = containerWidth / img.get(0).naturalWidth; - const scaleY = containerHeight / img.get(0).naturalHeight; - const scale = Math.min(scaleX, scaleY); - canvas.width = img.get(0).naturalWidth * scale; - canvas.height = img.get(0).naturalHeight * scale; + const canvas = document.getElementById("photoCanvas"); + const ctx = canvas.getContext("2d"); + + // reset canvas to current image (keeps proportions) + canvas.width = photoData.naturalWidth; + canvas.height = photoData.naturalHeight; + canvas.style.width = `${photoData.displayWidth}px`; + canvas.style.height = `${photoData.displayHeight}px`; + + const img = $("#samplePhoto"); ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(img.get(0), 0, 0, canvas.width, canvas.height); + if (img[0].naturalWidth) { + ctx.drawImage(img.get(0), 0, 0, canvas.width, canvas.height); + } } $("#addDescriptionsBtn").on("click", function () { hasDescriptions = true; - descriptionPosition = { x: 10, y: 10 }; + descriptionPosition = {x: 10, y: 10}; drawDescriptions(descriptionPosition.x, descriptionPosition.y); - makeDraggable( - $("#descriptionList"), - descriptionPosition, - Math.min( - $("#photoCanvas").parent().width() / - $("#samplePhoto").get(0).naturalWidth, - $("#photoCanvas").parent().height() / - $("#samplePhoto").get(0).naturalHeight, - ), - ); + makeDraggable($("#descriptionList")); }); $("#removeAnnotationsBtn").on("click", function () { clearCanvasMarkers(); }); + let unsavedChanges = false; + +// --- helper functions --- + function markUnsaved() { + if (!unsavedChanges) { + unsavedChanges = true; + $("#savePhotoBtn").addClass("unsaved").text("⚠️ Salva Modifiche"); + } + } + + function clearUnsaved() { + unsavedChanges = false; + $("#savePhotoBtn").removeClass("unsaved").text("Salva Foto con Nome"); + } + +// --- event listeners --- +// როცა ვცვლით input-ს ცხრილში + $(document).on("input change", "#partsTableBody input", markUnsaved); + +// როცა ვამატებთ/ვშლით რიგს + $(document).on("click", ".add-row, .add-mix-row, .remove-row", markUnsaved); + +// თუ გაქვს draggable marker ან description list + $(document).on("markerChanged descriptionChanged", markUnsaved); + +// --- modal close protection --- + $('#partsModal').on('hide.bs.modal', function (e) { + if (unsavedChanges) { + if (!confirm("Hai modifiche non salvate. Vuoi davvero uscire?")) { + e.preventDefault(); + } + } + }); + +// --- SAVE BUTTON --- $("#savePhotoBtn").on("click", function () { const canvas = document.getElementById("photoCanvas"); - const img = $("#samplePhoto"); const ctx = canvas.getContext("2d"); + const img = $("#samplePhoto"); - canvas.width = img.get(0).naturalWidth; - canvas.height = img.get(0).naturalHeight; - ctx.drawImage(img.get(0), 0, 0); + // Ensure canvas is real size + const naturalWidth = img.get(0).naturalWidth; + const naturalHeight = img.get(0).naturalHeight; + canvas.width = naturalWidth; + canvas.height = naturalHeight; + // Redraw base image + ctx.drawImage(img.get(0), 0, 0, naturalWidth, naturalHeight); + + // Descriptions box const partsList = []; $("#partsTableBody tr").each(function () { const partNumber = $(this).find(".part-number").val(); const partDescription = $(this).find(".part-description").val(); - if ( - partNumber && - partDescription && - !partDescription.startsWith("Mix") - ) { + if (partNumber && partDescription && !partDescription.startsWith("Mix")) { partsList.push(`${partNumber} ${partDescription}`); } }); - if (hasDescriptions) { - ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; - ctx.fillRect( - descriptionPosition.x, - descriptionPosition.y, - 200, - partsList.length * 12 + 10, - ); - ctx.fillStyle = "#000000"; - ctx.font = "10px Arial"; + if (hasDescriptions && partsList.length > 0) { + const fontSize = Math.round(naturalWidth * 0.02); + ctx.font = fontSize + "px Arial"; + const textHeight = fontSize + 8; + const boxWidth = Math.round(naturalWidth * 0.28); + const boxHeight = partsList.length * textHeight + 25; + + const x = descriptionPosition.x; + const y = descriptionPosition.y; + + // ჩრდილი + ctx.save(); + ctx.shadowColor = "rgba(0,0,0,0.3)"; + ctx.shadowBlur = 8; + ctx.shadowOffsetX = 3; + ctx.shadowOffsetY = 3; + + // ლამაზი ბექგრაუნდი + ctx.fillStyle = "rgba(255, 255, 255, 0.9)"; + ctx.beginPath(); + ctx.roundRect(x, y, boxWidth, boxHeight, 12); + ctx.fill(); + + ctx.restore(); + + // ტექსტი + ctx.fillStyle = "#111111"; partsList.forEach((part, index) => { - ctx.fillText( - part, - descriptionPosition.x + 5, - descriptionPosition.y + 12 + index * 12, - ); + const domWidth = $("#samplePhoto").width(); + const domHeight = $("#samplePhoto").height(); + + // NATURAL ზომა (ფაილის რეალური ზომა) + const naturalWidth = photoData.naturalWidth; + const naturalHeight = photoData.naturalHeight; + + // მასშტაბები + const scaleX = naturalWidth / domWidth; + const scaleY = naturalHeight / domHeight; + + // გადაყვანილი კოორდინატები + const x = descriptionPosition.x * scaleX; + const y = descriptionPosition.y * scaleY; + + ctx.fillText(part, x + 15, y + 35 + index * textHeight); }); } + // Markers + const currentPhoto = $("#samplePhoto").attr("src"); + const markers = photoMarkers[currentPhoto] || []; markers.forEach((marker) => { + const x = marker.x; // already NATURAL coords + const y = marker.y; + const radius = Math.max(5, Math.round(naturalWidth * 0.025)); + const fontSize = Math.max(8, Math.round(radius * 0.9)); + ctx.beginPath(); - ctx.arc(marker.x, marker.y, 8, 0, 2 * Math.PI); - ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; + ctx.arc(x, y, radius, 0, 2 * Math.PI); + ctx.fillStyle = "rgba(255,0,0,0.85)"; ctx.fill(); - ctx.strokeStyle = "#ff0000"; - ctx.lineWidth = 1; + + ctx.lineWidth = 3; + ctx.strokeStyle = "#ffffff"; ctx.stroke(); + ctx.fillStyle = "#ffffff"; - ctx.font = "bold 8px Arial"; + ctx.font = `bold ${fontSize}px Arial`; ctx.textAlign = "center"; ctx.textBaseline = "middle"; - ctx.fillText(marker.partNumber, marker.x, marker.y); + ctx.fillText(marker.partNumber || "", x, y); }); const dataURL = canvas.toDataURL("image/png"); const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); - const defaultName = `photo_${$("#partsModal").data("iddatadb")}_${timestamp}.png`; - const newName = prompt( - "Inserisci il nome del file (senza estensione):", - defaultName.split(".png")[0], - ); + const iddatadb = $("#partsModal").data("iddatadb"); + const defaultName = `photo_${iddatadb}_${timestamp}.png`; + + const newName = prompt("Inserisci il nome del file (senza estensione):", defaultName.split(".png")[0]); + if (newName) { const finalName = newName + "_" + timestamp + ".png"; $.ajax({ url: "save_annotated_photo.php", method: "POST", - data: { dataURL: dataURL, filename: finalName }, + data: { + dataURL: dataURL, + filename: finalName, + iddatadb: iddatadb + }, success: function (response) { if (response.success) { - alert( - "Foto salvata con successo: " + response.file_path, - ); + alert("Foto salvata con successo: " + response.file_path); + $("#samplePhoto").attr("src", response.file_path); + loadPhoto(iddatadb); + clearCanvasMarkers(); + + clearUnsaved(); // ✅ reset unsaved status } else { - alert("Errore nel salvataggio: " + response.message); + alert("Errore: " + response.message); } }, error: function (xhr, status, error) { - alert("Errore nel salvataggio della foto: " + error); + alert("Errore Ajax: " + error); }, }); } }); + // =================== + // DEBUG HOVER LOGS + // =================== $(document).on("mouseenter", "tr", function () { - console.log("Mouse entrato su riga"); + // console.log("Mouse entrato su riga"); }); $(document).on("mouseleave", "tr", function () { - console.log("Mouse uscito da riga"); + // console.log("Mouse uscito da riga"); }); }); diff --git a/public/userarea/photos_popup.php b/public/userarea/photos_popup.php index f9d6a93..63d92c8 100644 --- a/public/userarea/photos_popup.php +++ b/public/userarea/photos_popup.php @@ -44,7 +44,7 @@ $photos = $stmt->fetchAll(PDO::FETCH_ASSOC); $photoBasePath = '../photostrf/'; // Genera l'URL per il QR code -$baseUrl = "http://localhost/trf_certest/public/userarea/"; // Sostituisci con il tuo dominio +$baseUrl = "http://localhost:8000/userarea/"; // Sostituisci con il tuo dominio $uploadUrl = $baseUrl . "upload_photos_mobile.php?iddatadb=" . $iddatadb; // Genera il QR code con endroid/qr-code 6.0.6 @@ -224,4 +224,4 @@ $result->saveToFile($qrCodeFile); font-size: 16px; color: white; } - \ No newline at end of file + diff --git a/public/userarea/save_annotated_photo.php b/public/userarea/save_annotated_photo.php index 244d36b..3745b08 100644 --- a/public/userarea/save_annotated_photo.php +++ b/public/userarea/save_annotated_photo.php @@ -1,25 +1,53 @@ false, 'message' => 'Dati mancanti']); exit; } try { + // --- ფაილის შენახვა --- $data = explode(',', $dataURL)[1]; $decodedData = base64_decode($data); - $filePath = '../photostrf/annotated/' . $filename; // Crea una sottocartella 'annotated' per le foto modificate - if (!file_exists('../photostrf/annotated')) { - mkdir('../photostrf/annotated', 0777, true); + + $dirPath = '../photostrf/annotated'; + if (!file_exists($dirPath)) { + mkdir($dirPath, 0777, true); } + + $filePath = $dirPath . '/' . $filename; file_put_contents($filePath, $decodedData); - echo json_encode(['success' => true, 'file_path' => $filePath, 'message' => 'Foto salvata con successo']); + + $db = DBHandlerSelect::getInstance(); + $pdo = $db->getConnection(); + + // --- ბაზაში ჩაწერა --- + $stmt = $pdo->prepare(" + INSERT INTO datadb_photos (iddatadb, file_path, file_name, uploaded_at, uploaded_by) + VALUES (:iddatadb, :file_path, :file_name, NOW(), :uploaded_by) + "); + $stmt->execute([ + ':iddatadb' => $iddatadb, + ':file_path' => $filePath, + ':file_name' => $filename, + ':uploaded_by'=> $iduserlogin + ]); + + echo json_encode([ + 'success' => true, + 'file_path' => $filePath, + 'message' => 'Foto salvata con successo e registrata nel DB' + ]); + } catch (Exception $e) { - echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]); + echo json_encode(['success' => false, 'message' => 'Errore: ' . $e->getMessage()]); } diff --git a/public/userarea/save_edited_row.php b/public/userarea/save_edited_row.php index e395bed..fa8df22 100644 --- a/public/userarea/save_edited_row.php +++ b/public/userarea/save_edited_row.php @@ -14,28 +14,64 @@ try { $db = DBHandlerSelect::getInstance(); $pdo = $db->getConnection(); - // Prepara i dati da aggiornare - $updates = []; - $values = []; - foreach ($_POST as $key => $value) { - if ($key !== 'iddatadb') { - $updates[] = "$key = ?"; - $values[] = htmlspecialchars($value); + $data = $_POST; + $details = []; + + // 1. POST-დან ამოვიღოთ მხოლოდ details + foreach ($data as $key => $value) { + if (preg_match('/^details(\d+)field_value$/', $key, $matches)) { + $id = $matches[1]; + $details[$id] = $value; } } - $values[] = $iddatadb; - if (empty($updates)) { - throw new Exception('Nessun dato da aggiornare'); + // 2. DB-დან წამოვიღოთ არსებული მნიშვნელობები + $stmt = $pdo->prepare("SELECT mapping_id, field_value FROM import_data_details WHERE id = ?"); + $stmt->execute([$iddatadb]); + + $currentValues = []; + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $currentValues[$row['mapping_id']] = $row['field_value']; } - $sql = "UPDATE datadb SET " . implode(', ', $updates) . " WHERE iddatadb = ?"; - $stmt = $pdo->prepare($sql); - $stmt->execute($values); + // 3. შევადაროთ POST-ს და DB-ს + $changed = []; + foreach ($details as $id => $newValue) { + $oldValue = $currentValues[$id] ?? null; + if ($oldValue !== $newValue) { + $changed[$id] = [ + 'old' => $oldValue, + 'new' => $newValue + ]; + } + } + + // 4. თუ არის ცვლილებები → UPDATE + if (!empty($changed)) { + $updateStmt = $pdo->prepare(" + UPDATE import_data_details + SET field_value = :newValue + WHERE id = :iddatadb AND mapping_id = :mappingId + "); + + foreach ($changed as $mappingId => $values) { + $updateStmt->execute([ + ':newValue' => $values['new'], + ':iddatadb' => $iddatadb, + ':mappingId' => $mappingId + ]); + } + + $response['success'] = true; + $response['message'] = "Updated successfully"; + $response['changed'] = $changed; // Debug / optional + } else { + $response['success'] = true; + $response['message'] = "No changes found"; + } - $response['success'] = true; - $response['message'] = 'Riga aggiornata con successo'; } catch (Exception $e) { + $response['success'] = false; $response['message'] = $e->getMessage(); error_log("Errore in save_edited_row.php: " . $e->getMessage()); } diff --git a/public/userarea/save_parts.php b/public/userarea/save_parts.php index f489ed6..65e07cc 100644 --- a/public/userarea/save_parts.php +++ b/public/userarea/save_parts.php @@ -1,6 +1,5 @@ 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, - ':mix' => $mix - ]); - echo json_encode(['success' => true, 'message' => 'Parte salvata con successo']); + if ($partId) { + // UPDATE თუ უკვე არსებობს part + $stmt = $pdo->prepare("UPDATE identification_parts + SET part_number = :part_number, + part_description = :part_description, + mix = :mix, + updated_at = NOW() + WHERE id = :id"); + $stmt->execute([ + ':id' => $partId, + ':part_number' => $partNumber, + ':part_description' => $partDescription, + ':mix' => $mix + ]); + echo json_encode(['success' => true, 'part_id' => $partId, 'part_number'=>$partNumber, 'message' => 'Parte aggiornata con successo']); + } else { + // INSERT თუ ახალია + $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, + ':mix' => $mix + ]); + $newId = $pdo->lastInsertId(); + echo json_encode(['success' => true, 'part_id' => $newId, 'part_number'=>$partNumber, 'message' => 'Parte salvata con successo']); + } } catch (PDOException $e) { echo json_encode(['success' => false, 'message' => 'Errore nel salvataggio: ' . $e->getMessage()]); } diff --git a/public/userarea/upload_photos_mobile.php b/public/userarea/upload_photos_mobile.php index 946708f..e16d421 100644 --- a/public/userarea/upload_photos_mobile.php +++ b/public/userarea/upload_photos_mobile.php @@ -142,4 +142,4 @@ $sampleCode = $row['sample_code'] ?? 'Non disponibile'; - \ No newline at end of file + diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 1fa6f66..341dde0 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -42,6 +42,7 @@ + @yield('scripts') @hook('app:scripts') diff --git a/routes/web.php b/routes/web.php index 1db981a..078d859 100644 --- a/routes/web.php +++ b/routes/web.php @@ -188,3 +188,11 @@ Route::group(['prefix' => 'install'], function () { Route::get('complete', 'InstallController@complete')->name('install.complete'); Route::get('error', 'InstallController@error')->name('install.error'); }); + +use App\Vanguard\Http\Controllers\Userarea\UploadPhotosMobileController; + +Route::get('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'index']) + ->name('userarea.upload-photos-mobile.index'); + +Route::post('/userarea/upload-photos-mobile', [UploadPhotosMobileController::class, 'upload']) + ->name('userarea.upload-photos-mobile.upload');