/** * CSV Manager - CRUD operations for CSV files * Handles reading, parsing, editing, and saving CSV data */ /** * Parse CSV text to array of objects * @param {string} csvText - CSV content * @returns {Array} Parsed data */ export function parseCSV(csvText) { const lines = csvText.trim().split('\n'); if (lines.length === 0) return []; // Get headers const headers = lines[0].split(',').map(h => h.trim()); // Parse rows const data = []; for (let i = 1; i < lines.length; i++) { const values = lines[i].split(',').map(v => v.trim()); const row = {}; headers.forEach((header, index) => { row[header] = values[index] || ''; }); data.push(row); } return data; } /** * Convert array of objects to CSV text * @param {Array} data - Data array * @returns {string} CSV text */ export function toCSV(data) { if (data.length === 0) return ''; // Get headers from first object const headers = Object.keys(data[0]); // Create CSV lines const lines = [headers.join(',')]; data.forEach(row => { const values = headers.map(header => { const value = row[header] || ''; // Escape commas and quotes if (value.includes(',') || value.includes('"')) { return `"${value.replace(/"/g, '""')}"`; } return value; }); lines.push(values.join(',')); }); return lines.join('\n'); } /** * Load CSV file * @param {string} filename - CSV filename * @returns {Promise>} Parsed data */ export async function loadCSV(filename) { try { const response = await fetch(`BD/${filename}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const text = await response.text(); return parseCSV(text); } catch (error) { console.error(`Erro ao carregar ${filename}:`, error); throw error; } } /** * Download CSV file * @param {string} filename - Filename * @param {string} csvText - CSV content */ export function downloadCSV(filename, csvText) { const blob = new Blob([csvText], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', filename); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url); } /** * Get available CSV files * @returns {Array} List of CSV files with metadata */ export function getAvailableCSVFiles() { return [ { id: 'perfis_w', name: 'Perfis W', filename: 'perfis_w.csv', description: 'Perfis de aço tipo W (vigas)', icon: '🏗️' }, { id: 'perfis_i', name: 'Perfis I', filename: 'perfis_i.csv', description: 'Perfis de aço tipo I', icon: '🏗️' }, { id: 'cantoneiras', name: 'Cantoneiras', filename: 'cantoneiras.csv', description: 'Cantoneiras de aço', icon: '📐' }, { id: 'tubos_circulares', name: 'Tubos Circulares', filename: 'tubos_circulares.csv', description: 'Tubos de seção circular', icon: '⭕' }, { id: 'tubos_rhs', name: 'Tubos RHS', filename: 'tubos_rhs.csv', description: 'Tubos retangulares/quadrados', icon: '⬜' }, { id: 'chapas', name: 'Chapas', filename: 'chapas.csv', description: 'Chapas de aço', icon: '📄' }, { id: 'barras', name: 'Barras', filename: 'barras.csv', description: 'Barras redondas', icon: '➖' }, { id: 'eletrodos', name: 'Eletrodos', filename: 'eletrodos.csv', description: 'Eletrodos de soldagem', icon: '⚡' }, { id: 'parafusos', name: 'Parafusos', filename: 'parafusos.csv', description: 'Parafusos estruturais', icon: '🔩' }, { id: 'tintas', name: 'Tintas', filename: 'tintas.csv', description: 'Tintas e revestimentos', icon: '🎨' }, { id: 'acos_soldagem', name: 'Aços - Soldagem', filename: 'Tabela_Acos_Soldagem_Consumiveis.csv', description: 'Relação aços e consumíveis', icon: '🔥' }, { id: 'acos_pintura', name: 'Aços - Pintura', filename: 'Tabela_Acos_Pintura_Tintas.csv', description: 'Relação aços e tintas', icon: '🎨' } ]; } /** * Validate CSV data * @param {Array} data - Data to validate * @returns {object} Validation result */ export function validateCSVData(data) { const errors = []; if (!Array.isArray(data) || data.length === 0) { errors.push('Dados vazios ou inválidos'); return { valid: false, errors }; } // Check if all rows have same keys const firstKeys = Object.keys(data[0]).sort(); for (let i = 1; i < data.length; i++) { const keys = Object.keys(data[i]).sort(); if (JSON.stringify(keys) !== JSON.stringify(firstKeys)) { errors.push(`Linha ${i + 1}: Colunas inconsistentes`); } } // Check for empty required fields (id, nome) data.forEach((row, index) => { if (!row.id || row.id.trim() === '') { errors.push(`Linha ${index + 2}: Campo 'id' vazio`); } if (!row.nome || row.nome.trim() === '') { errors.push(`Linha ${index + 2}: Campo 'nome' vazio`); } }); return { valid: errors.length === 0, errors }; }