Fix script paths and move assets to public/ folder for Vite build compatibility
This commit is contained in:
230
public/js/utils/csv-manager.js
Normal file
230
public/js/utils/csv-manager.js
Normal file
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* 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<object>} 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<object>} 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<Array<object>>} 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<object>} 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<object>} 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user