From d983659000c3cd2189ef09890fc8ab4ced03e935 Mon Sep 17 00:00:00 2001 From: "r.mubarakzyanov" Date: Tue, 31 Mar 2026 13:41:31 +0300 Subject: [PATCH] transfer auto-detect header --- .../userarea/mapping_template_xls_scheme2.php | 145 ++++++++++++++++-- public/userarea/process_import_xls2.php | 46 ------ public/userarea/update_xls_headers.php | 21 ++- 3 files changed, 151 insertions(+), 61 deletions(-) diff --git a/public/userarea/mapping_template_xls_scheme2.php b/public/userarea/mapping_template_xls_scheme2.php index b7ddbc7..6523bce 100644 --- a/public/userarea/mapping_template_xls_scheme2.php +++ b/public/userarea/mapping_template_xls_scheme2.php @@ -198,7 +198,13 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t
- +
+ + +
✅ Current file: @@ -508,8 +514,6 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t type: 'array' }); let sheet = workbook.Sheets[workbook.SheetNames[0]]; - let rowIndex = parseInt(document.getElementById('headerRow').textContent) || 1; - let startColumn = parseInt(document.getElementById('startColumn').textContent) || 1; let sheetData = XLSX.utils.sheet_to_json(sheet, { header: 1, @@ -517,37 +521,152 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t raw: false, range: 0 }); - console.log("Dati della riga " + rowIndex + ":", sheetData[rowIndex - 1]); - if (!sheetData[rowIndex - 1]) { + + const useAutoDetect = document.getElementById('autoDetectHeader').checked; + + if (!useAutoDetect) { + // Use values from template settings + let rowIndex = parseInt(document.getElementById('headerRow').textContent) || 1; + let startColumn = parseInt(document.getElementById('startColumn').textContent) || 1; + console.log(`Manual mode: row ${rowIndex}, startCol ${startColumn}`); + + if (!sheetData[rowIndex - 1]) { + document.getElementById('schemaFieldsBody').querySelectorAll('select.xls-columns').forEach(select => { + select.innerHTML = ''; + }); + return; + } + + let headers = sheetData[rowIndex - 1].slice(startColumn - 1).map(header => header === undefined ? "" : String(header).trim()); + console.log("Intestazioni estratte (manual):", headers); + availableXlsColumns = [...headers]; + usedColumnsFromDB = []; + saveXlsHeaders(headers, rowIndex, startColumn); + updateXlsDropdowns(); + return; + } + + // Collect field_label titles from the schema table + const knownLabels = []; + document.querySelectorAll('.title-col').forEach(td => { + const v = (td.textContent || '').trim().toLowerCase().replace(/\s*required\s*$/i, '').trim(); + if (v && v !== 'n/a') knownLabels.push(v); + }); + const uniqueLabels = [...new Set(knownLabels)]; + + console.group('🔍 Auto-detect header row'); + console.log('Sheet name:', workbook.SheetNames[0]); + console.log('Total rows in sheet:', sheetData.length); + console.log('Labels from schema field titles:', knownLabels); + console.log('Unique labels to match against:', uniqueLabels); + + // Auto-detect: find the row with most matches, fallback to most non-empty unique text cells + let bestRow = 0; + let bestScore = 0; + let bestStartCol = 0; + let fallbackRow = 0; + let fallbackScore = 0; + let fallbackStartCol = 0; + const scanLimit = Math.min(sheetData.length, 50); + const rowScores = []; + + for (let r = 0; r < scanLimit; r++) { + const row = sheetData[r] || []; + let score = 0; + let firstNonEmpty = -1; + let nonEmptyCount = 0; + const matched = []; + const cellValues = []; + const seen = new Set(); + for (let c = 0; c < row.length; c++) { + const cellVal = String(row[c] || '').trim(); + const cellLower = cellVal.toLowerCase(); + if (cellVal) { + cellValues.push(`[${c}]="${cellVal}"`); + if (firstNonEmpty < 0) firstNonEmpty = c; + // Count unique short text cells (likely headers, not data/descriptions) + if (cellVal.length < 80 && !seen.has(cellLower)) { + nonEmptyCount++; + seen.add(cellLower); + } + } + if (cellLower && uniqueLabels.includes(cellLower)) { + score++; + matched.push(cellVal); + } + } + rowScores.push({ row: r + 1, score, nonEmpty: nonEmptyCount, matched, firstNonEmpty: firstNonEmpty + 1, cells: cellValues }); + if (score > bestScore) { + bestScore = score; + bestRow = r; + bestStartCol = firstNonEmpty >= 0 ? firstNonEmpty : 0; + } + // Fallback: row with most unique short text cells (likely header row) + if (nonEmptyCount > fallbackScore) { + fallbackScore = nonEmptyCount; + fallbackRow = r; + fallbackStartCol = firstNonEmpty >= 0 ? firstNonEmpty : 0; + } + } + + // If no label matches, use fallback (most populated row) + if (bestScore === 0 && fallbackScore > 0) { + bestRow = fallbackRow; + bestStartCol = fallbackStartCol; + console.log(`⚠️ No label matches found. Using fallback: row with most headers (${fallbackScore} unique cells)`); + } + + console.log('All rows scanned:'); + console.table(rowScores.filter(r => r.nonEmpty > 0).map(r => ({ + row: r.row, + labelMatches: r.score, + uniqueCells: r.nonEmpty, + matched: r.matched.join(', '), + firstCol: r.firstNonEmpty + }))); + console.log(`✅ Result: row ${bestRow + 1}, startCol ${bestStartCol + 1}, labelScore ${bestScore}/${uniqueLabels.length}, fallbackScore ${fallbackScore}`); + console.log('Selected row raw data:', sheetData[bestRow]); + console.groupEnd(); + + // Update display + document.getElementById('headerRow').textContent = bestRow + 1; + document.getElementById('startColumn').textContent = bestStartCol + 1; + + if (!sheetData[bestRow]) { document.getElementById('schemaFieldsBody').querySelectorAll('select.xls-columns').forEach(select => { select.innerHTML = ''; }); return; } - let headers = sheetData[rowIndex - 1].slice(startColumn - 1).map(header => header === undefined ? "" : header); + let headers = sheetData[bestRow].slice(bestStartCol).map(header => header === undefined ? "" : String(header).trim()); console.log("Intestazioni estratte:", headers); availableXlsColumns = [...headers]; usedColumnsFromDB = []; - saveXlsHeaders(headers); + saveXlsHeaders(headers, bestRow + 1, bestStartCol + 1); updateXlsDropdowns(); }; reader.readAsArrayBuffer(file); } - function saveXlsHeaders(headers) { + function saveXlsHeaders(headers, headerRow, startColumn) { + const payload = { + template_id: , + xls_headers: JSON.stringify(headers) + }; + if (headerRow !== undefined) payload.header_row = headerRow; + if (startColumn !== undefined) payload.start_column = startColumn; + fetch('update_xls_headers.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - template_id: , - xls_headers: JSON.stringify(headers) - }) + body: JSON.stringify(payload) }).then(response => response.json()) .then(data => { if (!data.success) console.error("❌ Error saving XLS headers:", data.message); + else console.log("✅ Saved headers, header_row:", headerRow, "start_column:", startColumn); }) .catch(error => console.error("❌ Fetch error:", error)); } @@ -1582,4 +1701,4 @@ $xlsHeaders = $template['xls_headers'] ? json_decode($template['xls_headers'], t - \ No newline at end of file + diff --git a/public/userarea/process_import_xls2.php b/public/userarea/process_import_xls2.php index 65ef60b..19e57d9 100644 --- a/public/userarea/process_import_xls2.php +++ b/public/userarea/process_import_xls2.php @@ -58,11 +58,6 @@ try { $stmt->execute([$template_id]); $mappings = $stmt->fetchAll(PDO::FETCH_ASSOC); - // Also fetch excel_column labels for auto-detect - $stmtLabels = $pdo->prepare("SELECT excel_column FROM template_mapping WHERE template_id = ? AND is_manual = 0 AND excel_column IS NOT NULL AND excel_column != ''"); - $stmtLabels->execute([$template_id]); - $templateLabels = array_map('trim', array_map('mb_strtolower', $stmtLabels->fetchAll(PDO::FETCH_COLUMN))); - // Debug dei mapping error_log("Mappings found for template_id $template_id: " . print_r($mappings, true)); @@ -76,47 +71,6 @@ try { $highestColumn = $worksheet->getHighestColumn(); $highestColumnIndex = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($highestColumn); - // ── Auto-detect header row and start column ── - // Scan all rows/columns to find the best match against template excel_column labels - if (!empty($templateLabels)) { - $bestRow = max(1, $header_row); - $bestCol = max(1, $start_column); - $bestScore = 0; - $scanLimit = min($highestRow, 50); - - for ($scanRow = 1; $scanRow <= $scanLimit; $scanRow++) { - $score = 0; - for ($col = 1; $col <= $highestColumnIndex; $col++) { - $colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col); - $cellVal = $worksheet->getCell($colLetter . $scanRow)->getCalculatedValue(); - $cellVal = mb_strtolower(trim((string)$cellVal)); - if ($cellVal !== '' && in_array($cellVal, $templateLabels, true)) { - $score++; - } - } - if ($score > $bestScore) { - $bestScore = $score; - $bestRow = $scanRow; - } - } - - $header_row = $bestRow; - - // Determine start_column: first non-empty cell in the detected header row - for ($col = 1; $col <= $highestColumnIndex; $col++) { - $colLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($col); - $cellVal = $worksheet->getCell($colLetter . $header_row)->getCalculatedValue(); - if (trim((string)$cellVal) !== '') { - $start_column = $col; - break; - } - } - error_log("Auto-detected header row: $header_row, start column: $start_column (score: $bestScore/" . count($templateLabels) . ")"); - $response['auto_header_row'] = $header_row; - $response['auto_header_score'] = $bestScore; - $response['auto_header_total'] = count($templateLabels); - } - $startRow = max(1, $header_row); $startColumn = max(1, $start_column); diff --git a/public/userarea/update_xls_headers.php b/public/userarea/update_xls_headers.php index 96e043a..752d9af 100644 --- a/public/userarea/update_xls_headers.php +++ b/public/userarea/update_xls_headers.php @@ -18,10 +18,27 @@ if (!$data || !isset($data['template_id'], $data['xls_headers'])) { $templateId = $data['template_id']; $xlsHeaders = $data['xls_headers']; +$headerRow = isset($data['header_row']) ? (int)$data['header_row'] : null; +$startColumn = isset($data['start_column']) ? (int)$data['start_column'] : null; try { - $stmt = $pdo->prepare("UPDATE excel_templates SET xls_headers = ? WHERE id = ?"); - $result = $stmt->execute([$xlsHeaders, $templateId]); + $sql = "UPDATE excel_templates SET xls_headers = ?"; + $params = [$xlsHeaders]; + + if ($headerRow !== null) { + $sql .= ", header_row = ?"; + $params[] = $headerRow; + } + if ($startColumn !== null) { + $sql .= ", start_column = ?"; + $params[] = $startColumn; + } + + $sql .= " WHERE id = ?"; + $params[] = $templateId; + + $stmt = $pdo->prepare($sql); + $result = $stmt->execute($params); if (!$result) { echo json_encode(["success" => false, "message" => "Database update failed"]);