docs: implement Antigravity global rules
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,324 +1,324 @@
|
||||
/**
|
||||
* CARREGADOR UNIVERSAL DE PERFIS
|
||||
* Sistema que carrega automaticamente TODOS os tipos de perfis
|
||||
* usando o banco de dados embutido
|
||||
*/
|
||||
|
||||
// Configuração de mapeamento de tipos
|
||||
const MAPEAMENTO_PERFIS = {
|
||||
'cantoneiras': {
|
||||
tbodyId: 'cantoneiras-tbody',
|
||||
totalId: 'cant-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'lado_mm', label: 'Lado (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_redondas': {
|
||||
tbodyId: 'barras_redondas-tbody',
|
||||
totalId: 'barras_redondas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'diametro_mm', label: 'Diâmetro (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 3 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'tubos_circulares': {
|
||||
tbodyId: 'tubos_circulares-tbody',
|
||||
totalId: 'tubos_circulares-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'diametro_mm', label: 'Ø Externo (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_i': {
|
||||
tbodyId: 'perfis_i-tbody',
|
||||
totalId: 'perfis_i-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)' },
|
||||
{ key: 'espessura_mesa_mm', label: 'Esp. Mesa (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_w': {
|
||||
tbodyId: 'perfis_w-tbody',
|
||||
totalId: 'perfis_w-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)' },
|
||||
{ key: 'espessura_mesa_mm', label: 'Esp. Mesa (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'tubos_rhs': {
|
||||
tbodyId: 'tubos_rhs-tbody',
|
||||
totalId: 'tubos_rhs-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'chapas': {
|
||||
tbodyId: 'chapas-tbody',
|
||||
totalId: 'chapas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m2', label: 'Peso (kg/m²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_hp': {
|
||||
tbodyId: 'perfis_hp-tbody',
|
||||
totalId: 'perfis_hp-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'aba_mm', label: 'Aba (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)', decimals: 1 },
|
||||
{ key: 'espessura_aba_mm', label: 'Esp. Aba (mm)', decimals: 1 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 1 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 1 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_roscadas': {
|
||||
tbodyId: 'barras_roscadas-tbody',
|
||||
totalId: 'barras_roscadas-total',
|
||||
colunas: [
|
||||
{ key: 'tipo_rosca', label: 'Tipo', badge: true },
|
||||
{ key: 'diametro_nominal_mm', label: 'Diâmetro (mm)', decimals: 2 },
|
||||
{ key: 'passo_mm', label: 'Passo (mm)', decimals: 2 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tamanho', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_chatas': {
|
||||
tbodyId: 'barras_chatas-tbody',
|
||||
totalId: 'barras_chatas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)', decimals: 1 },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)', decimals: 1 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tamanho', label: 'Categoria', badge: true }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Carrega dados de um tipo específico de perfil
|
||||
*/
|
||||
function carregarPerfilUniversal(tipo) {
|
||||
console.log(`🚀 Carregando perfil: ${tipo}`);
|
||||
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
if (!config) {
|
||||
console.error(`❌ Configuração não encontrada para: ${tipo}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
if (!tbody) {
|
||||
console.warn(`⚠️ Elemento ${config.tbodyId} não encontrado`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Obter dados do banco
|
||||
const dados = window.BANCO_DADOS_PERFIS?.[tipo];
|
||||
if (!dados || dados.length === 0) {
|
||||
console.error(`❌ Dados não encontrados para: ${tipo}`);
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="${config.colunas.length + 1}" style="text-align: center; padding: 40px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">❌</div>
|
||||
<div style="font-size: 18px; font-weight: bold; color: #ef4444;">Dados não encontrados</div>
|
||||
<div style="font-size: 14px; color: #666; margin-top: 8px;">Tipo: ${tipo}</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gerar HTML da tabela
|
||||
const html = dados.map(item => {
|
||||
const colunas = config.colunas.map(col => {
|
||||
let valor = item[col.key];
|
||||
|
||||
// Formatação
|
||||
if (col.decimals && typeof valor === 'number') {
|
||||
valor = valor.toFixed(col.decimals);
|
||||
}
|
||||
|
||||
// Estilo
|
||||
if (col.bold) {
|
||||
return `<td><strong>${valor}</strong></td>`;
|
||||
} else if (col.badge) {
|
||||
return `<td><span class="badge badge-info">${valor}</span></td>`;
|
||||
} else {
|
||||
return `<td>${valor}</td>`;
|
||||
}
|
||||
}).join('');
|
||||
|
||||
return `<tr>${colunas}<td><button class="btn btn-sm btn-primary">👁️ Ver</button></td></tr>`;
|
||||
}).join('');
|
||||
|
||||
tbody.innerHTML = html;
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById(config.totalId);
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
// Armazenar globalmente
|
||||
window[`${tipo}Data`] = dados;
|
||||
|
||||
console.log(`✅ ${tipo}: ${dados.length} itens carregados`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer universal que detecta qualquer tabela de perfil
|
||||
*/
|
||||
function iniciarObserverUniversal() {
|
||||
console.log('👁️ Iniciando observer universal para todos os perfis');
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
// Verificar cada tipo de perfil
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
|
||||
if (tbody) {
|
||||
// Verificar se está vazio
|
||||
const conteudo = tbody.textContent.trim();
|
||||
const estaVazio = tbody.children.length === 0 ||
|
||||
conteudo.includes('Será preenchido') ||
|
||||
conteudo.includes('preenchido via JavaScript') ||
|
||||
(tbody.children.length === 1 && tbody.children[0].children.length === 1);
|
||||
|
||||
if (estaVazio) {
|
||||
console.log(`🎯 Tabela vazia detectada: ${tipo}`);
|
||||
|
||||
// Aguardar um pouco e carregar
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
console.log(`✅ Auto-carregamento concluído: ${tipo}`);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Observar mudanças no body
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Tentar carregar imediatamente também
|
||||
setTimeout(() => {
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
if (tbody) {
|
||||
carregarPerfilUniversal(tipo);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
console.log('✅ Observer universal ativo para todos os perfis');
|
||||
}
|
||||
|
||||
// Gerar funções de carregamento forçado para cada tipo
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const funcName = `forcarCarregamento${tipo.split('_').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join('')}`;
|
||||
|
||||
window[funcName] = function() {
|
||||
console.log(`🚨 Carregamento forçado: ${tipo}`);
|
||||
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
|
||||
if (!tbody) {
|
||||
alert(`❌ Erro: Tabela não encontrada para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar loading
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="${config.colunas.length + 1}" style="text-align: center; padding: 40px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">⏳</div>
|
||||
<div style="font-size: 18px; font-weight: bold;">Carregando ${tipo}...</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
// Carregar após delay
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
const dados = window.BANCO_DADOS_PERFIS[tipo];
|
||||
alert(`✅ ${dados.length} ${tipo} carregados com sucesso!`);
|
||||
} else {
|
||||
alert(`❌ Erro ao carregar ${tipo}`);
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
console.log(`✅ Função criada: ${funcName}`);
|
||||
});
|
||||
|
||||
// Inicializar quando DOM estiver pronto
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', iniciarObserverUniversal);
|
||||
} else {
|
||||
iniciarObserverUniversal();
|
||||
}
|
||||
|
||||
// Exportar funções
|
||||
window.carregarPerfilUniversal = carregarPerfilUniversal;
|
||||
window.MAPEAMENTO_PERFIS = MAPEAMENTO_PERFIS;
|
||||
|
||||
console.log('✅ Carregador universal configurado para todos os perfis');
|
||||
console.log('📊 Perfis suportados:', Object.keys(MAPEAMENTO_PERFIS));
|
||||
/**
|
||||
* CARREGADOR UNIVERSAL DE PERFIS
|
||||
* Sistema que carrega automaticamente TODOS os tipos de perfis
|
||||
* usando o banco de dados embutido
|
||||
*/
|
||||
|
||||
// Configuração de mapeamento de tipos
|
||||
const MAPEAMENTO_PERFIS = {
|
||||
'cantoneiras': {
|
||||
tbodyId: 'cantoneiras-tbody',
|
||||
totalId: 'cant-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'lado_mm', label: 'Lado (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_redondas': {
|
||||
tbodyId: 'barras_redondas-tbody',
|
||||
totalId: 'barras_redondas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'diametro_mm', label: 'Diâmetro (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 3 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'tubos_circulares': {
|
||||
tbodyId: 'tubos_circulares-tbody',
|
||||
totalId: 'tubos_circulares-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'diametro_mm', label: 'Ø Externo (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'momento_inercia_cm4', label: 'Momento Inércia (cm⁴)', decimals: 2 },
|
||||
{ key: 'raio_giracao_cm', label: 'Raio Giração (cm)', decimals: 2 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_i': {
|
||||
tbodyId: 'perfis_i-tbody',
|
||||
totalId: 'perfis_i-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)' },
|
||||
{ key: 'espessura_mesa_mm', label: 'Esp. Mesa (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_w': {
|
||||
tbodyId: 'perfis_w-tbody',
|
||||
totalId: 'perfis_w-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)' },
|
||||
{ key: 'espessura_mesa_mm', label: 'Esp. Mesa (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'tubos_rhs': {
|
||||
tbodyId: 'tubos_rhs-tbody',
|
||||
totalId: 'tubos_rhs-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)' },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 2 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'chapas': {
|
||||
tbodyId: 'chapas-tbody',
|
||||
totalId: 'chapas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)' },
|
||||
{ key: 'peso_kg_m2', label: 'Peso (kg/m²)', decimals: 2 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'perfis_hp': {
|
||||
tbodyId: 'perfis_hp-tbody',
|
||||
totalId: 'perfis_hp-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'altura_mm', label: 'Altura (mm)' },
|
||||
{ key: 'aba_mm', label: 'Aba (mm)' },
|
||||
{ key: 'espessura_alma_mm', label: 'Esp. Alma (mm)', decimals: 1 },
|
||||
{ key: 'espessura_aba_mm', label: 'Esp. Aba (mm)', decimals: 1 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 1 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 1 },
|
||||
{ key: 'tipo', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_roscadas': {
|
||||
tbodyId: 'barras_roscadas-tbody',
|
||||
totalId: 'barras_roscadas-total',
|
||||
colunas: [
|
||||
{ key: 'tipo_rosca', label: 'Tipo', badge: true },
|
||||
{ key: 'diametro_nominal_mm', label: 'Diâmetro (mm)', decimals: 2 },
|
||||
{ key: 'passo_mm', label: 'Passo (mm)', decimals: 2 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'aplicacao', label: 'Aplicação' },
|
||||
{ key: 'tamanho', label: 'Categoria', badge: true }
|
||||
]
|
||||
},
|
||||
'barras_chatas': {
|
||||
tbodyId: 'barras_chatas-tbody',
|
||||
totalId: 'barras_chatas-total',
|
||||
colunas: [
|
||||
{ key: 'nome', label: 'Designação', bold: true },
|
||||
{ key: 'largura_mm', label: 'Largura (mm)', decimals: 1 },
|
||||
{ key: 'espessura_mm', label: 'Espessura (mm)', decimals: 1 },
|
||||
{ key: 'peso_kg_m', label: 'Peso (kg/m)', decimals: 3 },
|
||||
{ key: 'area_cm2', label: 'Área (cm²)', decimals: 2 },
|
||||
{ key: 'tamanho', label: 'Categoria', badge: true }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Carrega dados de um tipo específico de perfil
|
||||
*/
|
||||
function carregarPerfilUniversal(tipo) {
|
||||
console.log(`🚀 Carregando perfil: ${tipo}`);
|
||||
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
if (!config) {
|
||||
console.error(`❌ Configuração não encontrada para: ${tipo}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
if (!tbody) {
|
||||
console.warn(`⚠️ Elemento ${config.tbodyId} não encontrado`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Obter dados do banco
|
||||
const dados = window.BANCO_DADOS_PERFIS?.[tipo];
|
||||
if (!dados || dados.length === 0) {
|
||||
console.error(`❌ Dados não encontrados para: ${tipo}`);
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="${config.colunas.length + 1}" style="text-align: center; padding: 40px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">❌</div>
|
||||
<div style="font-size: 18px; font-weight: bold; color: #ef4444;">Dados não encontrados</div>
|
||||
<div style="font-size: 14px; color: #666; margin-top: 8px;">Tipo: ${tipo}</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gerar HTML da tabela
|
||||
const html = dados.map(item => {
|
||||
const colunas = config.colunas.map(col => {
|
||||
let valor = item[col.key];
|
||||
|
||||
// Formatação
|
||||
if (col.decimals && typeof valor === 'number') {
|
||||
valor = valor.toFixed(col.decimals);
|
||||
}
|
||||
|
||||
// Estilo
|
||||
if (col.bold) {
|
||||
return `<td><strong>${valor}</strong></td>`;
|
||||
} else if (col.badge) {
|
||||
return `<td><span class="badge badge-info">${valor}</span></td>`;
|
||||
} else {
|
||||
return `<td>${valor}</td>`;
|
||||
}
|
||||
}).join('');
|
||||
|
||||
return `<tr>${colunas}<td><button class="btn btn-sm btn-primary">👁️ Ver</button></td></tr>`;
|
||||
}).join('');
|
||||
|
||||
tbody.innerHTML = html;
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById(config.totalId);
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
// Armazenar globalmente
|
||||
window[`${tipo}Data`] = dados;
|
||||
|
||||
console.log(`✅ ${tipo}: ${dados.length} itens carregados`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer universal que detecta qualquer tabela de perfil
|
||||
*/
|
||||
function iniciarObserverUniversal() {
|
||||
console.log('👁️ Iniciando observer universal para todos os perfis');
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
// Verificar cada tipo de perfil
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
|
||||
if (tbody) {
|
||||
// Verificar se está vazio
|
||||
const conteudo = tbody.textContent.trim();
|
||||
const estaVazio = tbody.children.length === 0 ||
|
||||
conteudo.includes('Será preenchido') ||
|
||||
conteudo.includes('preenchido via JavaScript') ||
|
||||
(tbody.children.length === 1 && tbody.children[0].children.length === 1);
|
||||
|
||||
if (estaVazio) {
|
||||
console.log(`🎯 Tabela vazia detectada: ${tipo}`);
|
||||
|
||||
// Aguardar um pouco e carregar
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
console.log(`✅ Auto-carregamento concluído: ${tipo}`);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Observar mudanças no body
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Tentar carregar imediatamente também
|
||||
setTimeout(() => {
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
if (tbody) {
|
||||
carregarPerfilUniversal(tipo);
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
console.log('✅ Observer universal ativo para todos os perfis');
|
||||
}
|
||||
|
||||
// Gerar funções de carregamento forçado para cada tipo
|
||||
Object.keys(MAPEAMENTO_PERFIS).forEach(tipo => {
|
||||
const funcName = `forcarCarregamento${tipo.split('_').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join('')}`;
|
||||
|
||||
window[funcName] = function() {
|
||||
console.log(`🚨 Carregamento forçado: ${tipo}`);
|
||||
|
||||
const config = MAPEAMENTO_PERFIS[tipo];
|
||||
const tbody = document.getElementById(config.tbodyId);
|
||||
|
||||
if (!tbody) {
|
||||
alert(`❌ Erro: Tabela não encontrada para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar loading
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="${config.colunas.length + 1}" style="text-align: center; padding: 40px;">
|
||||
<div style="font-size: 48px; margin-bottom: 16px;">⏳</div>
|
||||
<div style="font-size: 18px; font-weight: bold;">Carregando ${tipo}...</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
// Carregar após delay
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
const dados = window.BANCO_DADOS_PERFIS[tipo];
|
||||
alert(`✅ ${dados.length} ${tipo} carregados com sucesso!`);
|
||||
} else {
|
||||
alert(`❌ Erro ao carregar ${tipo}`);
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
console.log(`✅ Função criada: ${funcName}`);
|
||||
});
|
||||
|
||||
// Inicializar quando DOM estiver pronto
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', iniciarObserverUniversal);
|
||||
} else {
|
||||
iniciarObserverUniversal();
|
||||
}
|
||||
|
||||
// Exportar funções
|
||||
window.carregarPerfilUniversal = carregarPerfilUniversal;
|
||||
window.MAPEAMENTO_PERFIS = MAPEAMENTO_PERFIS;
|
||||
|
||||
console.log('✅ Carregador universal configurado para todos os perfis');
|
||||
console.log('📊 Perfis suportados:', Object.keys(MAPEAMENTO_PERFIS));
|
||||
|
||||
@@ -1,177 +1,177 @@
|
||||
/**
|
||||
* DADOS EMBUTIDOS - Todos os perfis em JavaScript
|
||||
* Solução autônoma que funciona sem servidor e sem CSVs
|
||||
* Pronto para desktop, mobile e deploy
|
||||
*/
|
||||
|
||||
const DADOS_PERFIS = {
|
||||
cantoneiras: [
|
||||
{id: 'l25_25_3', nome: 'L25x25x3', lado_mm: 25, espessura_mm: 3, peso_kg_m: 1.12, area_cm2: 1.43, momento_inercia_cm4: 0.38, raio_giracao_cm: 0.52, tipo: 'Pequena'},
|
||||
{id: 'l25_25_4', nome: 'L25x25x4', lado_mm: 25, espessura_mm: 4, peso_kg_m: 1.47, area_cm2: 1.87, momento_inercia_cm4: 0.47, raio_giracao_cm: 0.5, tipo: 'Pequena'},
|
||||
{id: 'l32_32_3', nome: 'L32x32x3', lado_mm: 32, espessura_mm: 3, peso_kg_m: 1.45, area_cm2: 1.85, momento_inercia_cm4: 0.69, raio_giracao_cm: 0.61, tipo: 'Pequena'},
|
||||
{id: 'l32_32_4', nome: 'L32x32x4', lado_mm: 32, espessura_mm: 4, peso_kg_m: 1.91, area_cm2: 2.43, momento_inercia_cm4: 0.86, raio_giracao_cm: 0.59, tipo: 'Pequena'},
|
||||
{id: 'l40_40_3', nome: 'L40x40x3', lado_mm: 40, espessura_mm: 3, peso_kg_m: 1.86, area_cm2: 2.37, momento_inercia_cm4: 1.4, raio_giracao_cm: 0.77, tipo: 'Pequena'},
|
||||
{id: 'l40_40_4', nome: 'L40x40x4', lado_mm: 40, espessura_mm: 4, peso_kg_m: 2.46, area_cm2: 3.13, momento_inercia_cm4: 1.74, raio_giracao_cm: 0.75, tipo: 'Pequena'},
|
||||
{id: 'l40_40_5', nome: 'L40x40x5', lado_mm: 40, espessura_mm: 5, peso_kg_m: 3.03, area_cm2: 3.86, momento_inercia_cm4: 2.06, raio_giracao_cm: 0.73, tipo: 'Pequena'},
|
||||
{id: 'l50_50_3', nome: 'L50x50x3', lado_mm: 50, espessura_mm: 3, peso_kg_m: 2.36, area_cm2: 3.0, momento_inercia_cm4: 2.7, raio_giracao_cm: 0.95, tipo: 'Pequena'},
|
||||
{id: 'l50_50_4', nome: 'L50x50x4', lado_mm: 50, espessura_mm: 4, peso_kg_m: 3.14, area_cm2: 4.0, momento_inercia_cm4: 3.5, raio_giracao_cm: 0.93, tipo: 'Pequena'},
|
||||
{id: 'l50_50_5', nome: 'L50x50x5', lado_mm: 50, espessura_mm: 5, peso_kg_m: 3.89, area_cm2: 4.96, momento_inercia_cm4: 4.25, raio_giracao_cm: 0.93, tipo: 'Pequena'},
|
||||
{id: 'l50_50_6', nome: 'L50x50x6', lado_mm: 50, espessura_mm: 6, peso_kg_m: 4.62, area_cm2: 5.89, momento_inercia_cm4: 4.95, raio_giracao_cm: 0.92, tipo: 'Pequena'},
|
||||
{id: 'l63_63_5', nome: 'L63x63x5', lado_mm: 63, espessura_mm: 5, peso_kg_m: 4.96, area_cm2: 6.31, momento_inercia_cm4: 8.47, raio_giracao_cm: 1.16, tipo: 'Média'},
|
||||
{id: 'l63_63_6', nome: 'L63x63x6', lado_mm: 63, espessura_mm: 6, peso_kg_m: 5.91, area_cm2: 7.53, momento_inercia_cm4: 9.9, raio_giracao_cm: 1.15, tipo: 'Média'},
|
||||
{id: 'l63_63_8', nome: 'L63x63x8', lado_mm: 63, espessura_mm: 8, peso_kg_m: 7.73, area_cm2: 9.85, momento_inercia_cm4: 12.6, raio_giracao_cm: 1.13, tipo: 'Média'},
|
||||
{id: 'l75_75_5', nome: 'L75x75x5', lado_mm: 75, espessura_mm: 5, peso_kg_m: 5.91, area_cm2: 7.53, momento_inercia_cm4: 13.5, raio_giracao_cm: 1.34, tipo: 'Média'},
|
||||
{id: 'l75_75_6', nome: 'L75x75x6', lado_mm: 75, espessura_mm: 6, peso_kg_m: 7.05, area_cm2: 8.98, momento_inercia_cm4: 15.8, raio_giracao_cm: 1.33, tipo: 'Média'},
|
||||
{id: 'l75_75_7', nome: 'L75x75x7', lado_mm: 75, espessura_mm: 7, peso_kg_m: 8.17, area_cm2: 10.4, momento_inercia_cm4: 18.0, raio_giracao_cm: 1.32, tipo: 'Média'},
|
||||
{id: 'l75_75_8', nome: 'L75x75x8', lado_mm: 75, espessura_mm: 8, peso_kg_m: 9.27, area_cm2: 11.8, momento_inercia_cm4: 20.1, raio_giracao_cm: 1.31, tipo: 'Média'},
|
||||
{id: 'l100_100_6', nome: 'L100x100x6', lado_mm: 100, espessura_mm: 6, peso_kg_m: 9.46, area_cm2: 12.1, momento_inercia_cm4: 37.4, raio_giracao_cm: 1.76, tipo: 'Grande'},
|
||||
{id: 'l100_100_8', nome: 'L100x100x8', lado_mm: 100, espessura_mm: 8, peso_kg_m: 12.5, area_cm2: 15.9, momento_inercia_cm4: 48.8, raio_giracao_cm: 1.75, tipo: 'Grande'},
|
||||
{id: 'l100_100_10', nome: 'L100x100x10', lado_mm: 100, espessura_mm: 10, peso_kg_m: 15.4, area_cm2: 19.6, momento_inercia_cm4: 59.5, raio_giracao_cm: 1.74, tipo: 'Grande'},
|
||||
{id: 'l100_100_12', nome: 'L100x100x12', lado_mm: 100, espessura_mm: 12, peso_kg_m: 18.2, area_cm2: 23.2, momento_inercia_cm4: 69.5, raio_giracao_cm: 1.73, tipo: 'Grande'},
|
||||
{id: 'l125_125_8', nome: 'L125x125x8', lado_mm: 125, espessura_mm: 8, peso_kg_m: 15.7, area_cm2: 20.0, momento_inercia_cm4: 95.3, raio_giracao_cm: 2.18, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_10', nome: 'L125x125x10', lado_mm: 125, espessura_mm: 10, peso_kg_m: 19.5, area_cm2: 24.8, momento_inercia_cm4: 117, raio_giracao_cm: 2.17, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_12', nome: 'L125x125x12', lado_mm: 125, espessura_mm: 12, peso_kg_m: 23.2, area_cm2: 29.5, momento_inercia_cm4: 137, raio_giracao_cm: 2.16, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_16', nome: 'L125x125x16', lado_mm: 125, espessura_mm: 16, peso_kg_m: 30.3, area_cm2: 38.6, momento_inercia_cm4: 175, raio_giracao_cm: 2.13, tipo: 'Muito Grande'},
|
||||
{id: 'l150_150_10', nome: 'L150x150x10', lado_mm: 150, espessura_mm: 10, peso_kg_m: 23.6, area_cm2: 30.1, momento_inercia_cm4: 201, raio_giracao_cm: 2.59, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_12', nome: 'L150x150x12', lado_mm: 150, espessura_mm: 12, peso_kg_m: 28.1, area_cm2: 35.8, momento_inercia_cm4: 237, raio_giracao_cm: 2.57, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_15', nome: 'L150x150x15', lado_mm: 150, espessura_mm: 15, peso_kg_m: 34.8, area_cm2: 44.3, momento_inercia_cm4: 289, raio_giracao_cm: 2.56, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_20', nome: 'L150x150x20', lado_mm: 150, espessura_mm: 20, peso_kg_m: 45.6, area_cm2: 58.1, momento_inercia_cm4: 371, raio_giracao_cm: 2.53, tipo: 'Extra-Grande'},
|
||||
{id: 'l200_200_16', nome: 'L200x200x16', lado_mm: 200, espessura_mm: 16, peso_kg_m: 50.3, area_cm2: 64.1, momento_inercia_cm4: 712, raio_giracao_cm: 3.33, tipo: 'Massiva'},
|
||||
{id: 'l200_200_20', nome: 'L200x200x20', lado_mm: 200, espessura_mm: 20, peso_kg_m: 62.4, area_cm2: 79.5, momento_inercia_cm4: 873, raio_giracao_cm: 3.31, tipo: 'Massiva'},
|
||||
{id: 'l200_200_25', nome: 'L200x200x25', lado_mm: 200, espessura_mm: 25, peso_kg_m: 77.3, area_cm2: 98.5, momento_inercia_cm4: 1060, raio_giracao_cm: 3.28, tipo: 'Massiva'}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Função para obter dados de um tipo de perfil
|
||||
*/
|
||||
function obterDadosPerfil(tipo) {
|
||||
console.log(`📊 Obtendo dados embutidos: ${tipo}`);
|
||||
const dados = DADOS_PERFIS[tipo];
|
||||
|
||||
if (!dados) {
|
||||
console.error(`❌ Tipo de perfil não encontrado: ${tipo}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log(`✅ ${dados.length} itens encontrados para ${tipo}`);
|
||||
return dados;
|
||||
}
|
||||
|
||||
/**
|
||||
* Carrega dados automaticamente para cantoneiras
|
||||
*/
|
||||
function carregarCantoneirasAutomatico() {
|
||||
console.log('🚀 Carregamento automático de cantoneiras (dados embutidos)');
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.warn('⚠️ Elemento tbody não encontrado ainda');
|
||||
return false;
|
||||
}
|
||||
|
||||
const dados = obterDadosPerfil('cantoneiras');
|
||||
|
||||
if (dados.length === 0) {
|
||||
console.error('❌ Nenhum dado encontrado');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exibir na tabela
|
||||
tbody.innerHTML = dados.map(item => `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge badge-info">${item.tipo}</span></td>
|
||||
<td><button class="btn btn-sm btn-primary">👁️ Ver</button></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
// Armazenar globalmente
|
||||
window.cantoneirasData = dados;
|
||||
|
||||
console.log(`✅ ${dados.length} cantoneiras carregadas automaticamente!`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exportar para uso global
|
||||
window.DADOS_PERFIS = DADOS_PERFIS;
|
||||
window.obterDadosPerfil = obterDadosPerfil;
|
||||
window.carregarCantoneirasAutomatico = carregarCantoneirasAutomatico;
|
||||
|
||||
console.log('✅ Dados embutidos carregados - 33 cantoneiras disponíveis');
|
||||
|
||||
|
||||
// ========================================
|
||||
// AUTO-CARREGAMENTO ROBUSTO
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Observer que detecta quando a tabela de cantoneiras aparece
|
||||
* e carrega os dados automaticamente
|
||||
*/
|
||||
function iniciarAutoCarregamentoRobusto() {
|
||||
console.log('👁️ Iniciando observer robusto para auto-carregamento');
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
|
||||
if (tbody) {
|
||||
// Verificar se está vazio ou com placeholder
|
||||
const conteudo = tbody.textContent.trim();
|
||||
const estaVazio = tbody.children.length === 0 ||
|
||||
conteudo.includes('Será preenchido') ||
|
||||
conteudo.includes('preenchido via JavaScript') ||
|
||||
tbody.children.length === 1 && tbody.children[0].children.length === 1;
|
||||
|
||||
if (estaVazio) {
|
||||
console.log('🎯 Tabela vazia detectada - carregando automaticamente...');
|
||||
|
||||
// Aguardar um pouco e carregar
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarCantoneirasAutomatico();
|
||||
if (sucesso) {
|
||||
console.log('✅ Auto-carregamento concluído com sucesso!');
|
||||
observer.disconnect(); // Parar de observar
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Observar mudanças no body
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Tentar carregar imediatamente também
|
||||
setTimeout(() => {
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
carregarCantoneirasAutomatico();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
console.log('✅ Observer robusto ativo');
|
||||
}
|
||||
|
||||
// Iniciar quando o DOM estiver pronto
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', iniciarAutoCarregamentoRobusto);
|
||||
} else {
|
||||
iniciarAutoCarregamentoRobusto();
|
||||
}
|
||||
|
||||
console.log('✅ Sistema de auto-carregamento robusto configurado');
|
||||
/**
|
||||
* DADOS EMBUTIDOS - Todos os perfis em JavaScript
|
||||
* Solução autônoma que funciona sem servidor e sem CSVs
|
||||
* Pronto para desktop, mobile e deploy
|
||||
*/
|
||||
|
||||
const DADOS_PERFIS = {
|
||||
cantoneiras: [
|
||||
{id: 'l25_25_3', nome: 'L25x25x3', lado_mm: 25, espessura_mm: 3, peso_kg_m: 1.12, area_cm2: 1.43, momento_inercia_cm4: 0.38, raio_giracao_cm: 0.52, tipo: 'Pequena'},
|
||||
{id: 'l25_25_4', nome: 'L25x25x4', lado_mm: 25, espessura_mm: 4, peso_kg_m: 1.47, area_cm2: 1.87, momento_inercia_cm4: 0.47, raio_giracao_cm: 0.5, tipo: 'Pequena'},
|
||||
{id: 'l32_32_3', nome: 'L32x32x3', lado_mm: 32, espessura_mm: 3, peso_kg_m: 1.45, area_cm2: 1.85, momento_inercia_cm4: 0.69, raio_giracao_cm: 0.61, tipo: 'Pequena'},
|
||||
{id: 'l32_32_4', nome: 'L32x32x4', lado_mm: 32, espessura_mm: 4, peso_kg_m: 1.91, area_cm2: 2.43, momento_inercia_cm4: 0.86, raio_giracao_cm: 0.59, tipo: 'Pequena'},
|
||||
{id: 'l40_40_3', nome: 'L40x40x3', lado_mm: 40, espessura_mm: 3, peso_kg_m: 1.86, area_cm2: 2.37, momento_inercia_cm4: 1.4, raio_giracao_cm: 0.77, tipo: 'Pequena'},
|
||||
{id: 'l40_40_4', nome: 'L40x40x4', lado_mm: 40, espessura_mm: 4, peso_kg_m: 2.46, area_cm2: 3.13, momento_inercia_cm4: 1.74, raio_giracao_cm: 0.75, tipo: 'Pequena'},
|
||||
{id: 'l40_40_5', nome: 'L40x40x5', lado_mm: 40, espessura_mm: 5, peso_kg_m: 3.03, area_cm2: 3.86, momento_inercia_cm4: 2.06, raio_giracao_cm: 0.73, tipo: 'Pequena'},
|
||||
{id: 'l50_50_3', nome: 'L50x50x3', lado_mm: 50, espessura_mm: 3, peso_kg_m: 2.36, area_cm2: 3.0, momento_inercia_cm4: 2.7, raio_giracao_cm: 0.95, tipo: 'Pequena'},
|
||||
{id: 'l50_50_4', nome: 'L50x50x4', lado_mm: 50, espessura_mm: 4, peso_kg_m: 3.14, area_cm2: 4.0, momento_inercia_cm4: 3.5, raio_giracao_cm: 0.93, tipo: 'Pequena'},
|
||||
{id: 'l50_50_5', nome: 'L50x50x5', lado_mm: 50, espessura_mm: 5, peso_kg_m: 3.89, area_cm2: 4.96, momento_inercia_cm4: 4.25, raio_giracao_cm: 0.93, tipo: 'Pequena'},
|
||||
{id: 'l50_50_6', nome: 'L50x50x6', lado_mm: 50, espessura_mm: 6, peso_kg_m: 4.62, area_cm2: 5.89, momento_inercia_cm4: 4.95, raio_giracao_cm: 0.92, tipo: 'Pequena'},
|
||||
{id: 'l63_63_5', nome: 'L63x63x5', lado_mm: 63, espessura_mm: 5, peso_kg_m: 4.96, area_cm2: 6.31, momento_inercia_cm4: 8.47, raio_giracao_cm: 1.16, tipo: 'Média'},
|
||||
{id: 'l63_63_6', nome: 'L63x63x6', lado_mm: 63, espessura_mm: 6, peso_kg_m: 5.91, area_cm2: 7.53, momento_inercia_cm4: 9.9, raio_giracao_cm: 1.15, tipo: 'Média'},
|
||||
{id: 'l63_63_8', nome: 'L63x63x8', lado_mm: 63, espessura_mm: 8, peso_kg_m: 7.73, area_cm2: 9.85, momento_inercia_cm4: 12.6, raio_giracao_cm: 1.13, tipo: 'Média'},
|
||||
{id: 'l75_75_5', nome: 'L75x75x5', lado_mm: 75, espessura_mm: 5, peso_kg_m: 5.91, area_cm2: 7.53, momento_inercia_cm4: 13.5, raio_giracao_cm: 1.34, tipo: 'Média'},
|
||||
{id: 'l75_75_6', nome: 'L75x75x6', lado_mm: 75, espessura_mm: 6, peso_kg_m: 7.05, area_cm2: 8.98, momento_inercia_cm4: 15.8, raio_giracao_cm: 1.33, tipo: 'Média'},
|
||||
{id: 'l75_75_7', nome: 'L75x75x7', lado_mm: 75, espessura_mm: 7, peso_kg_m: 8.17, area_cm2: 10.4, momento_inercia_cm4: 18.0, raio_giracao_cm: 1.32, tipo: 'Média'},
|
||||
{id: 'l75_75_8', nome: 'L75x75x8', lado_mm: 75, espessura_mm: 8, peso_kg_m: 9.27, area_cm2: 11.8, momento_inercia_cm4: 20.1, raio_giracao_cm: 1.31, tipo: 'Média'},
|
||||
{id: 'l100_100_6', nome: 'L100x100x6', lado_mm: 100, espessura_mm: 6, peso_kg_m: 9.46, area_cm2: 12.1, momento_inercia_cm4: 37.4, raio_giracao_cm: 1.76, tipo: 'Grande'},
|
||||
{id: 'l100_100_8', nome: 'L100x100x8', lado_mm: 100, espessura_mm: 8, peso_kg_m: 12.5, area_cm2: 15.9, momento_inercia_cm4: 48.8, raio_giracao_cm: 1.75, tipo: 'Grande'},
|
||||
{id: 'l100_100_10', nome: 'L100x100x10', lado_mm: 100, espessura_mm: 10, peso_kg_m: 15.4, area_cm2: 19.6, momento_inercia_cm4: 59.5, raio_giracao_cm: 1.74, tipo: 'Grande'},
|
||||
{id: 'l100_100_12', nome: 'L100x100x12', lado_mm: 100, espessura_mm: 12, peso_kg_m: 18.2, area_cm2: 23.2, momento_inercia_cm4: 69.5, raio_giracao_cm: 1.73, tipo: 'Grande'},
|
||||
{id: 'l125_125_8', nome: 'L125x125x8', lado_mm: 125, espessura_mm: 8, peso_kg_m: 15.7, area_cm2: 20.0, momento_inercia_cm4: 95.3, raio_giracao_cm: 2.18, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_10', nome: 'L125x125x10', lado_mm: 125, espessura_mm: 10, peso_kg_m: 19.5, area_cm2: 24.8, momento_inercia_cm4: 117, raio_giracao_cm: 2.17, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_12', nome: 'L125x125x12', lado_mm: 125, espessura_mm: 12, peso_kg_m: 23.2, area_cm2: 29.5, momento_inercia_cm4: 137, raio_giracao_cm: 2.16, tipo: 'Muito Grande'},
|
||||
{id: 'l125_125_16', nome: 'L125x125x16', lado_mm: 125, espessura_mm: 16, peso_kg_m: 30.3, area_cm2: 38.6, momento_inercia_cm4: 175, raio_giracao_cm: 2.13, tipo: 'Muito Grande'},
|
||||
{id: 'l150_150_10', nome: 'L150x150x10', lado_mm: 150, espessura_mm: 10, peso_kg_m: 23.6, area_cm2: 30.1, momento_inercia_cm4: 201, raio_giracao_cm: 2.59, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_12', nome: 'L150x150x12', lado_mm: 150, espessura_mm: 12, peso_kg_m: 28.1, area_cm2: 35.8, momento_inercia_cm4: 237, raio_giracao_cm: 2.57, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_15', nome: 'L150x150x15', lado_mm: 150, espessura_mm: 15, peso_kg_m: 34.8, area_cm2: 44.3, momento_inercia_cm4: 289, raio_giracao_cm: 2.56, tipo: 'Extra-Grande'},
|
||||
{id: 'l150_150_20', nome: 'L150x150x20', lado_mm: 150, espessura_mm: 20, peso_kg_m: 45.6, area_cm2: 58.1, momento_inercia_cm4: 371, raio_giracao_cm: 2.53, tipo: 'Extra-Grande'},
|
||||
{id: 'l200_200_16', nome: 'L200x200x16', lado_mm: 200, espessura_mm: 16, peso_kg_m: 50.3, area_cm2: 64.1, momento_inercia_cm4: 712, raio_giracao_cm: 3.33, tipo: 'Massiva'},
|
||||
{id: 'l200_200_20', nome: 'L200x200x20', lado_mm: 200, espessura_mm: 20, peso_kg_m: 62.4, area_cm2: 79.5, momento_inercia_cm4: 873, raio_giracao_cm: 3.31, tipo: 'Massiva'},
|
||||
{id: 'l200_200_25', nome: 'L200x200x25', lado_mm: 200, espessura_mm: 25, peso_kg_m: 77.3, area_cm2: 98.5, momento_inercia_cm4: 1060, raio_giracao_cm: 3.28, tipo: 'Massiva'}
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Função para obter dados de um tipo de perfil
|
||||
*/
|
||||
function obterDadosPerfil(tipo) {
|
||||
console.log(`📊 Obtendo dados embutidos: ${tipo}`);
|
||||
const dados = DADOS_PERFIS[tipo];
|
||||
|
||||
if (!dados) {
|
||||
console.error(`❌ Tipo de perfil não encontrado: ${tipo}`);
|
||||
return [];
|
||||
}
|
||||
|
||||
console.log(`✅ ${dados.length} itens encontrados para ${tipo}`);
|
||||
return dados;
|
||||
}
|
||||
|
||||
/**
|
||||
* Carrega dados automaticamente para cantoneiras
|
||||
*/
|
||||
function carregarCantoneirasAutomatico() {
|
||||
console.log('🚀 Carregamento automático de cantoneiras (dados embutidos)');
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.warn('⚠️ Elemento tbody não encontrado ainda');
|
||||
return false;
|
||||
}
|
||||
|
||||
const dados = obterDadosPerfil('cantoneiras');
|
||||
|
||||
if (dados.length === 0) {
|
||||
console.error('❌ Nenhum dado encontrado');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exibir na tabela
|
||||
tbody.innerHTML = dados.map(item => `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge badge-info">${item.tipo}</span></td>
|
||||
<td><button class="btn btn-sm btn-primary">👁️ Ver</button></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
// Armazenar globalmente
|
||||
window.cantoneirasData = dados;
|
||||
|
||||
console.log(`✅ ${dados.length} cantoneiras carregadas automaticamente!`);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exportar para uso global
|
||||
window.DADOS_PERFIS = DADOS_PERFIS;
|
||||
window.obterDadosPerfil = obterDadosPerfil;
|
||||
window.carregarCantoneirasAutomatico = carregarCantoneirasAutomatico;
|
||||
|
||||
console.log('✅ Dados embutidos carregados - 33 cantoneiras disponíveis');
|
||||
|
||||
|
||||
// ========================================
|
||||
// AUTO-CARREGAMENTO ROBUSTO
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Observer que detecta quando a tabela de cantoneiras aparece
|
||||
* e carrega os dados automaticamente
|
||||
*/
|
||||
function iniciarAutoCarregamentoRobusto() {
|
||||
console.log('👁️ Iniciando observer robusto para auto-carregamento');
|
||||
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
|
||||
if (tbody) {
|
||||
// Verificar se está vazio ou com placeholder
|
||||
const conteudo = tbody.textContent.trim();
|
||||
const estaVazio = tbody.children.length === 0 ||
|
||||
conteudo.includes('Será preenchido') ||
|
||||
conteudo.includes('preenchido via JavaScript') ||
|
||||
tbody.children.length === 1 && tbody.children[0].children.length === 1;
|
||||
|
||||
if (estaVazio) {
|
||||
console.log('🎯 Tabela vazia detectada - carregando automaticamente...');
|
||||
|
||||
// Aguardar um pouco e carregar
|
||||
setTimeout(() => {
|
||||
const sucesso = carregarCantoneirasAutomatico();
|
||||
if (sucesso) {
|
||||
console.log('✅ Auto-carregamento concluído com sucesso!');
|
||||
observer.disconnect(); // Parar de observar
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Observar mudanças no body
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
// Tentar carregar imediatamente também
|
||||
setTimeout(() => {
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
carregarCantoneirasAutomatico();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
console.log('✅ Observer robusto ativo');
|
||||
}
|
||||
|
||||
// Iniciar quando o DOM estiver pronto
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', iniciarAutoCarregamentoRobusto);
|
||||
} else {
|
||||
iniciarAutoCarregamentoRobusto();
|
||||
}
|
||||
|
||||
console.log('✅ Sistema de auto-carregamento robusto configurado');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,342 +1,342 @@
|
||||
/**
|
||||
* IMPORTADOR DE CSV - Ferramenta de Atualização do BD Interno
|
||||
* Permite carregar CSVs externos e atualizar o banco de dados interno
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abre modal de importação de CSV
|
||||
*/
|
||||
function abrirImportadorCSV() {
|
||||
console.log('📥 Abrindo importador de CSV');
|
||||
|
||||
const modalHTML = `
|
||||
<div class="modal active" id="modal-importador-csv" onclick="fecharImportadorCSV(event)">
|
||||
<div class="modal-content" onclick="event.stopPropagation()" style="max-width: 900px;">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">📥 Importador de CSV - Atualizar BD Interno</div>
|
||||
<button class="close-btn" onclick="fecharImportadorCSV()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Instruções -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📋 Como Usar</h3>
|
||||
<ol style="margin: 0; padding-left: 20px;">
|
||||
<li>Selecione o tipo de perfil que deseja atualizar</li>
|
||||
<li>Escolha o arquivo CSV com os novos dados</li>
|
||||
<li>Clique em "Importar" para atualizar o BD interno</li>
|
||||
<li>Os dados serão salvos no localStorage e usados imediatamente</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- Seleção de Tipo -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">🎯 Selecionar Tipo de Perfil</h3>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Tipo de Perfil:</label>
|
||||
<select class="form-control" id="tipo-perfil-importar">
|
||||
<option value="">Selecione um tipo...</option>
|
||||
<option value="cantoneiras">Cantoneiras</option>
|
||||
<option value="barras_redondas">Barras Redondas</option>
|
||||
<option value="tubos_circulares">Tubos Circulares</option>
|
||||
<option value="perfis_i">Perfis I (IPE)</option>
|
||||
<option value="perfis_w">Perfis W</option>
|
||||
<option value="tubos_rhs">Tubos RHS</option>
|
||||
<option value="chapas">Chapas</option>
|
||||
<option value="perfis_hp">Perfis HP</option>
|
||||
<option value="barras_roscadas">Barras Roscadas</option>
|
||||
<option value="barras_chatas">Barras Chatas</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload de Arquivo -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📁 Selecionar Arquivo CSV</h3>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Arquivo CSV:</label>
|
||||
<input type="file" class="form-control" id="arquivo-csv" accept=".csv" onchange="visualizarCSV()">
|
||||
<small style="color: var(--color-text-secondary); margin-top: 8px; display: block;">
|
||||
Selecione um arquivo CSV com os dados dos perfis
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Preview do CSV -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px; display: none;" id="preview-csv">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">👁️ Preview do Arquivo</h3>
|
||||
<div id="preview-conteudo" style="max-height: 300px; overflow: auto;"></div>
|
||||
<div id="preview-stats" style="margin-top: 12px; padding: 12px; background: var(--color-bg-2); border-radius: 6px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Log de Importação -->
|
||||
<div class="card" style="background: var(--color-bg-1); display: none;" id="log-importacao">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📝 Log de Importação</h3>
|
||||
<div id="log-conteudo" style="background: #000; color: #0f0; padding: 16px; border-radius: 8px; font-family: monospace; font-size: 12px; max-height: 200px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="fecharImportadorCSV()">Cancelar</button>
|
||||
<button class="btn btn-primary" onclick="executarImportacao()" id="btn-importar" disabled>
|
||||
📥 Importar Dados
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Remover modal existente
|
||||
const existingModal = document.getElementById('modal-importador-csv');
|
||||
if (existingModal) {
|
||||
existingModal.remove();
|
||||
}
|
||||
|
||||
// Adicionar novo modal
|
||||
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fecha o importador de CSV
|
||||
*/
|
||||
function fecharImportadorCSV(event) {
|
||||
if (event && event.target !== event.currentTarget) return;
|
||||
|
||||
const modal = document.getElementById('modal-importador-csv');
|
||||
if (modal) {
|
||||
modal.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualiza o conteúdo do CSV selecionado
|
||||
*/
|
||||
function visualizarCSV() {
|
||||
const arquivo = document.getElementById('arquivo-csv').files[0];
|
||||
const tipoSelecionado = document.getElementById('tipo-perfil-importar').value;
|
||||
|
||||
if (!arquivo) {
|
||||
document.getElementById('preview-csv').style.display = 'none';
|
||||
document.getElementById('btn-importar').disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tipoSelecionado) {
|
||||
alert('⚠️ Selecione o tipo de perfil primeiro!');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const csvText = e.target.result;
|
||||
const linhas = csvText.trim().split('\n');
|
||||
|
||||
// Mostrar preview
|
||||
const previewDiv = document.getElementById('preview-conteudo');
|
||||
const statsDiv = document.getElementById('preview-stats');
|
||||
|
||||
// Primeiras 5 linhas
|
||||
const preview = linhas.slice(0, 6).map((linha, index) => {
|
||||
const colunas = linha.split(',');
|
||||
const isHeader = index === 0;
|
||||
return `
|
||||
<div style="padding: 8px; background: ${isHeader ? 'var(--color-primary)' : 'var(--color-bg-2)'};
|
||||
color: ${isHeader ? 'white' : 'inherit'}; margin-bottom: 2px; border-radius: 4px;">
|
||||
<strong>${isHeader ? 'CABEÇALHO:' : `Linha ${index}:`}</strong>
|
||||
${colunas.join(' | ')}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
previewDiv.innerHTML = preview;
|
||||
|
||||
// Estatísticas
|
||||
statsDiv.innerHTML = `
|
||||
<strong>📊 Estatísticas:</strong><br>
|
||||
• Total de linhas: ${linhas.length}<br>
|
||||
• Linhas de dados: ${linhas.length - 1}<br>
|
||||
• Colunas: ${linhas[0] ? linhas[0].split(',').length : 0}<br>
|
||||
• Tamanho: ${(csvText.length / 1024).toFixed(2)} KB
|
||||
`;
|
||||
|
||||
// Mostrar preview
|
||||
document.getElementById('preview-csv').style.display = 'block';
|
||||
document.getElementById('btn-importar').disabled = false;
|
||||
};
|
||||
|
||||
reader.readAsText(arquivo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executa a importação do CSV
|
||||
*/
|
||||
function executarImportacao() {
|
||||
const arquivo = document.getElementById('arquivo-csv').files[0];
|
||||
const tipo = document.getElementById('tipo-perfil-importar').value;
|
||||
|
||||
if (!arquivo || !tipo) {
|
||||
alert('⚠️ Selecione o tipo de perfil e o arquivo CSV!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar log
|
||||
document.getElementById('log-importacao').style.display = 'block';
|
||||
const logDiv = document.getElementById('log-conteudo');
|
||||
|
||||
function log(msg) {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
logDiv.innerHTML += `<div>[${time}] ${msg}</div>`;
|
||||
logDiv.scrollTop = logDiv.scrollHeight;
|
||||
}
|
||||
|
||||
log('🚀 Iniciando importação...');
|
||||
log(`📊 Tipo: ${tipo}`);
|
||||
log(`📁 Arquivo: ${arquivo.name}`);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
const csvText = e.target.result;
|
||||
const linhas = csvText.trim().split('\n');
|
||||
|
||||
log(`📄 Arquivo lido: ${linhas.length} linhas`);
|
||||
|
||||
if (linhas.length < 2) {
|
||||
throw new Error('Arquivo CSV deve ter pelo menos cabeçalho + 1 linha de dados');
|
||||
}
|
||||
|
||||
// Processar dados
|
||||
const cabecalho = linhas[0].split(',').map(h => h.trim().replace(/"/g, ''));
|
||||
log(`📋 Cabeçalho: ${cabecalho.join(', ')}`);
|
||||
|
||||
const dados = [];
|
||||
for (let i = 1; i < linhas.length; i++) {
|
||||
const linha = linhas[i].trim();
|
||||
if (!linha) continue;
|
||||
|
||||
const valores = linha.split(',').map(v => v.trim().replace(/"/g, ''));
|
||||
if (valores.length < cabecalho.length) continue;
|
||||
|
||||
const item = {};
|
||||
cabecalho.forEach((col, index) => {
|
||||
let valor = valores[index] || '';
|
||||
|
||||
// Converter números
|
||||
if (col.includes('_mm') || col.includes('_kg') || col.includes('_cm') || col.includes('_m2')) {
|
||||
valor = parseFloat(valor) || 0;
|
||||
}
|
||||
|
||||
item[col] = valor;
|
||||
});
|
||||
|
||||
dados.push(item);
|
||||
}
|
||||
|
||||
log(`✅ Processados: ${dados.length} itens`);
|
||||
|
||||
if (dados.length === 0) {
|
||||
throw new Error('Nenhum dado válido encontrado no CSV');
|
||||
}
|
||||
|
||||
// Atualizar banco de dados interno
|
||||
if (!window.BANCO_DADOS_PERFIS) {
|
||||
window.BANCO_DADOS_PERFIS = {};
|
||||
}
|
||||
|
||||
window.BANCO_DADOS_PERFIS[tipo] = dados;
|
||||
|
||||
// Salvar no localStorage
|
||||
const chaveCache = `acoCalcPro_dados_${tipo}`;
|
||||
localStorage.setItem(chaveCache, JSON.stringify(dados));
|
||||
|
||||
log(`💾 Dados salvos no localStorage: ${chaveCache}`);
|
||||
|
||||
// Atualizar metadata
|
||||
const metadata = {
|
||||
tipo: tipo,
|
||||
arquivo: arquivo.name,
|
||||
dataImportacao: new Date().toISOString(),
|
||||
totalItens: dados.length,
|
||||
colunas: cabecalho
|
||||
};
|
||||
|
||||
localStorage.setItem(`acoCalcPro_metadata_${tipo}`, JSON.stringify(metadata));
|
||||
|
||||
log(`📊 Metadata salvo`);
|
||||
|
||||
// Recarregar dados na tabela se estiver visível
|
||||
if (typeof carregarPerfilUniversal === 'function') {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
log(`🔄 Tabela atualizada automaticamente`);
|
||||
}
|
||||
}
|
||||
|
||||
log(`🎉 IMPORTAÇÃO CONCLUÍDA COM SUCESSO!`);
|
||||
|
||||
// Notificar usuário
|
||||
setTimeout(() => {
|
||||
alert(`✅ Importação concluída!\n\n📊 ${dados.length} itens de ${tipo} importados\n💾 Dados salvos no BD interno\n🔄 Tabela atualizada`);
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
log(`❌ ERRO: ${error.message}`);
|
||||
alert(`❌ Erro na importação: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(arquivo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta dados atuais para CSV
|
||||
*/
|
||||
function exportarDadosCSV(tipo) {
|
||||
if (!window.BANCO_DADOS_PERFIS || !window.BANCO_DADOS_PERFIS[tipo]) {
|
||||
alert(`❌ Nenhum dado encontrado para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const dados = window.BANCO_DADOS_PERFIS[tipo];
|
||||
if (dados.length === 0) {
|
||||
alert(`❌ Dados vazios para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Gerar CSV
|
||||
const cabecalho = Object.keys(dados[0]);
|
||||
const linhas = [cabecalho.join(',')];
|
||||
|
||||
dados.forEach(item => {
|
||||
const linha = cabecalho.map(col => {
|
||||
let valor = item[col];
|
||||
if (typeof valor === 'string' && valor.includes(',')) {
|
||||
valor = `"${valor}"`;
|
||||
}
|
||||
return valor;
|
||||
}).join(',');
|
||||
linhas.push(linha);
|
||||
});
|
||||
|
||||
const csvContent = linhas.join('\n');
|
||||
|
||||
// Download
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${tipo}_${new Date().toISOString().split('T')[0]}.csv`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
console.log(`✅ Dados de ${tipo} exportados para CSV`);
|
||||
}
|
||||
|
||||
// Exportar funções
|
||||
window.abrirImportadorCSV = abrirImportadorCSV;
|
||||
window.fecharImportadorCSV = fecharImportadorCSV;
|
||||
window.visualizarCSV = visualizarCSV;
|
||||
window.executarImportacao = executarImportacao;
|
||||
window.exportarDadosCSV = exportarDadosCSV;
|
||||
|
||||
console.log('✅ Importador de CSV carregado');
|
||||
/**
|
||||
* IMPORTADOR DE CSV - Ferramenta de Atualização do BD Interno
|
||||
* Permite carregar CSVs externos e atualizar o banco de dados interno
|
||||
*/
|
||||
|
||||
/**
|
||||
* Abre modal de importação de CSV
|
||||
*/
|
||||
function abrirImportadorCSV() {
|
||||
console.log('📥 Abrindo importador de CSV');
|
||||
|
||||
const modalHTML = `
|
||||
<div class="modal active" id="modal-importador-csv" onclick="fecharImportadorCSV(event)">
|
||||
<div class="modal-content" onclick="event.stopPropagation()" style="max-width: 900px;">
|
||||
<div class="modal-header">
|
||||
<div class="modal-title">📥 Importador de CSV - Atualizar BD Interno</div>
|
||||
<button class="close-btn" onclick="fecharImportadorCSV()">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<!-- Instruções -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📋 Como Usar</h3>
|
||||
<ol style="margin: 0; padding-left: 20px;">
|
||||
<li>Selecione o tipo de perfil que deseja atualizar</li>
|
||||
<li>Escolha o arquivo CSV com os novos dados</li>
|
||||
<li>Clique em "Importar" para atualizar o BD interno</li>
|
||||
<li>Os dados serão salvos no localStorage e usados imediatamente</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- Seleção de Tipo -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">🎯 Selecionar Tipo de Perfil</h3>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Tipo de Perfil:</label>
|
||||
<select class="form-control" id="tipo-perfil-importar">
|
||||
<option value="">Selecione um tipo...</option>
|
||||
<option value="cantoneiras">Cantoneiras</option>
|
||||
<option value="barras_redondas">Barras Redondas</option>
|
||||
<option value="tubos_circulares">Tubos Circulares</option>
|
||||
<option value="perfis_i">Perfis I (IPE)</option>
|
||||
<option value="perfis_w">Perfis W</option>
|
||||
<option value="tubos_rhs">Tubos RHS</option>
|
||||
<option value="chapas">Chapas</option>
|
||||
<option value="perfis_hp">Perfis HP</option>
|
||||
<option value="barras_roscadas">Barras Roscadas</option>
|
||||
<option value="barras_chatas">Barras Chatas</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload de Arquivo -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px;">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📁 Selecionar Arquivo CSV</h3>
|
||||
<div class="form-group">
|
||||
<label class="form-label">Arquivo CSV:</label>
|
||||
<input type="file" class="form-control" id="arquivo-csv" accept=".csv" onchange="visualizarCSV()">
|
||||
<small style="color: var(--color-text-secondary); margin-top: 8px; display: block;">
|
||||
Selecione um arquivo CSV com os dados dos perfis
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Preview do CSV -->
|
||||
<div class="card" style="background: var(--color-bg-1); margin-bottom: 20px; display: none;" id="preview-csv">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">👁️ Preview do Arquivo</h3>
|
||||
<div id="preview-conteudo" style="max-height: 300px; overflow: auto;"></div>
|
||||
<div id="preview-stats" style="margin-top: 12px; padding: 12px; background: var(--color-bg-2); border-radius: 6px;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Log de Importação -->
|
||||
<div class="card" style="background: var(--color-bg-1); display: none;" id="log-importacao">
|
||||
<h3 style="color: var(--color-primary); margin: 0 0 16px 0;">📝 Log de Importação</h3>
|
||||
<div id="log-conteudo" style="background: #000; color: #0f0; padding: 16px; border-radius: 8px; font-family: monospace; font-size: 12px; max-height: 200px; overflow-y: auto;"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick="fecharImportadorCSV()">Cancelar</button>
|
||||
<button class="btn btn-primary" onclick="executarImportacao()" id="btn-importar" disabled>
|
||||
📥 Importar Dados
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Remover modal existente
|
||||
const existingModal = document.getElementById('modal-importador-csv');
|
||||
if (existingModal) {
|
||||
existingModal.remove();
|
||||
}
|
||||
|
||||
// Adicionar novo modal
|
||||
document.body.insertAdjacentHTML('beforeend', modalHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fecha o importador de CSV
|
||||
*/
|
||||
function fecharImportadorCSV(event) {
|
||||
if (event && event.target !== event.currentTarget) return;
|
||||
|
||||
const modal = document.getElementById('modal-importador-csv');
|
||||
if (modal) {
|
||||
modal.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visualiza o conteúdo do CSV selecionado
|
||||
*/
|
||||
function visualizarCSV() {
|
||||
const arquivo = document.getElementById('arquivo-csv').files[0];
|
||||
const tipoSelecionado = document.getElementById('tipo-perfil-importar').value;
|
||||
|
||||
if (!arquivo) {
|
||||
document.getElementById('preview-csv').style.display = 'none';
|
||||
document.getElementById('btn-importar').disabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tipoSelecionado) {
|
||||
alert('⚠️ Selecione o tipo de perfil primeiro!');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
const csvText = e.target.result;
|
||||
const linhas = csvText.trim().split('\n');
|
||||
|
||||
// Mostrar preview
|
||||
const previewDiv = document.getElementById('preview-conteudo');
|
||||
const statsDiv = document.getElementById('preview-stats');
|
||||
|
||||
// Primeiras 5 linhas
|
||||
const preview = linhas.slice(0, 6).map((linha, index) => {
|
||||
const colunas = linha.split(',');
|
||||
const isHeader = index === 0;
|
||||
return `
|
||||
<div style="padding: 8px; background: ${isHeader ? 'var(--color-primary)' : 'var(--color-bg-2)'};
|
||||
color: ${isHeader ? 'white' : 'inherit'}; margin-bottom: 2px; border-radius: 4px;">
|
||||
<strong>${isHeader ? 'CABEÇALHO:' : `Linha ${index}:`}</strong>
|
||||
${colunas.join(' | ')}
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
previewDiv.innerHTML = preview;
|
||||
|
||||
// Estatísticas
|
||||
statsDiv.innerHTML = `
|
||||
<strong>📊 Estatísticas:</strong><br>
|
||||
• Total de linhas: ${linhas.length}<br>
|
||||
• Linhas de dados: ${linhas.length - 1}<br>
|
||||
• Colunas: ${linhas[0] ? linhas[0].split(',').length : 0}<br>
|
||||
• Tamanho: ${(csvText.length / 1024).toFixed(2)} KB
|
||||
`;
|
||||
|
||||
// Mostrar preview
|
||||
document.getElementById('preview-csv').style.display = 'block';
|
||||
document.getElementById('btn-importar').disabled = false;
|
||||
};
|
||||
|
||||
reader.readAsText(arquivo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executa a importação do CSV
|
||||
*/
|
||||
function executarImportacao() {
|
||||
const arquivo = document.getElementById('arquivo-csv').files[0];
|
||||
const tipo = document.getElementById('tipo-perfil-importar').value;
|
||||
|
||||
if (!arquivo || !tipo) {
|
||||
alert('⚠️ Selecione o tipo de perfil e o arquivo CSV!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Mostrar log
|
||||
document.getElementById('log-importacao').style.display = 'block';
|
||||
const logDiv = document.getElementById('log-conteudo');
|
||||
|
||||
function log(msg) {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
logDiv.innerHTML += `<div>[${time}] ${msg}</div>`;
|
||||
logDiv.scrollTop = logDiv.scrollHeight;
|
||||
}
|
||||
|
||||
log('🚀 Iniciando importação...');
|
||||
log(`📊 Tipo: ${tipo}`);
|
||||
log(`📁 Arquivo: ${arquivo.name}`);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
const csvText = e.target.result;
|
||||
const linhas = csvText.trim().split('\n');
|
||||
|
||||
log(`📄 Arquivo lido: ${linhas.length} linhas`);
|
||||
|
||||
if (linhas.length < 2) {
|
||||
throw new Error('Arquivo CSV deve ter pelo menos cabeçalho + 1 linha de dados');
|
||||
}
|
||||
|
||||
// Processar dados
|
||||
const cabecalho = linhas[0].split(',').map(h => h.trim().replace(/"/g, ''));
|
||||
log(`📋 Cabeçalho: ${cabecalho.join(', ')}`);
|
||||
|
||||
const dados = [];
|
||||
for (let i = 1; i < linhas.length; i++) {
|
||||
const linha = linhas[i].trim();
|
||||
if (!linha) continue;
|
||||
|
||||
const valores = linha.split(',').map(v => v.trim().replace(/"/g, ''));
|
||||
if (valores.length < cabecalho.length) continue;
|
||||
|
||||
const item = {};
|
||||
cabecalho.forEach((col, index) => {
|
||||
let valor = valores[index] || '';
|
||||
|
||||
// Converter números
|
||||
if (col.includes('_mm') || col.includes('_kg') || col.includes('_cm') || col.includes('_m2')) {
|
||||
valor = parseFloat(valor) || 0;
|
||||
}
|
||||
|
||||
item[col] = valor;
|
||||
});
|
||||
|
||||
dados.push(item);
|
||||
}
|
||||
|
||||
log(`✅ Processados: ${dados.length} itens`);
|
||||
|
||||
if (dados.length === 0) {
|
||||
throw new Error('Nenhum dado válido encontrado no CSV');
|
||||
}
|
||||
|
||||
// Atualizar banco de dados interno
|
||||
if (!window.BANCO_DADOS_PERFIS) {
|
||||
window.BANCO_DADOS_PERFIS = {};
|
||||
}
|
||||
|
||||
window.BANCO_DADOS_PERFIS[tipo] = dados;
|
||||
|
||||
// Salvar no localStorage
|
||||
const chaveCache = `acoCalcPro_dados_${tipo}`;
|
||||
localStorage.setItem(chaveCache, JSON.stringify(dados));
|
||||
|
||||
log(`💾 Dados salvos no localStorage: ${chaveCache}`);
|
||||
|
||||
// Atualizar metadata
|
||||
const metadata = {
|
||||
tipo: tipo,
|
||||
arquivo: arquivo.name,
|
||||
dataImportacao: new Date().toISOString(),
|
||||
totalItens: dados.length,
|
||||
colunas: cabecalho
|
||||
};
|
||||
|
||||
localStorage.setItem(`acoCalcPro_metadata_${tipo}`, JSON.stringify(metadata));
|
||||
|
||||
log(`📊 Metadata salvo`);
|
||||
|
||||
// Recarregar dados na tabela se estiver visível
|
||||
if (typeof carregarPerfilUniversal === 'function') {
|
||||
const sucesso = carregarPerfilUniversal(tipo);
|
||||
if (sucesso) {
|
||||
log(`🔄 Tabela atualizada automaticamente`);
|
||||
}
|
||||
}
|
||||
|
||||
log(`🎉 IMPORTAÇÃO CONCLUÍDA COM SUCESSO!`);
|
||||
|
||||
// Notificar usuário
|
||||
setTimeout(() => {
|
||||
alert(`✅ Importação concluída!\n\n📊 ${dados.length} itens de ${tipo} importados\n💾 Dados salvos no BD interno\n🔄 Tabela atualizada`);
|
||||
}, 1000);
|
||||
|
||||
} catch (error) {
|
||||
log(`❌ ERRO: ${error.message}`);
|
||||
alert(`❌ Erro na importação: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
reader.readAsText(arquivo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporta dados atuais para CSV
|
||||
*/
|
||||
function exportarDadosCSV(tipo) {
|
||||
if (!window.BANCO_DADOS_PERFIS || !window.BANCO_DADOS_PERFIS[tipo]) {
|
||||
alert(`❌ Nenhum dado encontrado para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const dados = window.BANCO_DADOS_PERFIS[tipo];
|
||||
if (dados.length === 0) {
|
||||
alert(`❌ Dados vazios para ${tipo}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Gerar CSV
|
||||
const cabecalho = Object.keys(dados[0]);
|
||||
const linhas = [cabecalho.join(',')];
|
||||
|
||||
dados.forEach(item => {
|
||||
const linha = cabecalho.map(col => {
|
||||
let valor = item[col];
|
||||
if (typeof valor === 'string' && valor.includes(',')) {
|
||||
valor = `"${valor}"`;
|
||||
}
|
||||
return valor;
|
||||
}).join(',');
|
||||
linhas.push(linha);
|
||||
});
|
||||
|
||||
const csvContent = linhas.join('\n');
|
||||
|
||||
// Download
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${tipo}_${new Date().toISOString().split('T')[0]}.csv`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
console.log(`✅ Dados de ${tipo} exportados para CSV`);
|
||||
}
|
||||
|
||||
// Exportar funções
|
||||
window.abrirImportadorCSV = abrirImportadorCSV;
|
||||
window.fecharImportadorCSV = fecharImportadorCSV;
|
||||
window.visualizarCSV = visualizarCSV;
|
||||
window.executarImportacao = executarImportacao;
|
||||
window.exportarDadosCSV = exportarDadosCSV;
|
||||
|
||||
console.log('✅ Importador de CSV carregado');
|
||||
|
||||
@@ -1,330 +1,330 @@
|
||||
/**
|
||||
* CARREGADOR DE PERFIS - Usando Data Manager
|
||||
*
|
||||
* Funções específicas para carregar e exibir dados dos perfis
|
||||
* usando o sistema de cache inteligente.
|
||||
*/
|
||||
|
||||
// ========================================
|
||||
// CANTONEIRAS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Carrega dados das cantoneiras usando o Data Manager
|
||||
*/
|
||||
async function carregarCantoneirasV2() {
|
||||
console.log('🔧 carregarCantoneirasV2() - Nova versão com Data Manager');
|
||||
|
||||
try {
|
||||
// Verificar se o elemento existe
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.error('❌ Elemento cantoneiras-tbody não encontrado!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ Elemento tbody encontrado');
|
||||
|
||||
// Mostrar loading
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px;">
|
||||
<div style="display: flex; align-items: center; justify-content: center; gap: 10px;">
|
||||
<div class="spinner"></div>
|
||||
📊 Carregando cantoneiras do banco de dados...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
// Carregar dados via Data Manager
|
||||
const dados = await window.dataManager.getData('cantoneiras');
|
||||
|
||||
if (!dados || dados.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px; color: var(--color-error);">
|
||||
❌ Nenhuma cantoneira encontrada no banco de dados.
|
||||
<br><br>
|
||||
<button class="btn btn-primary" onclick="atualizarDadosCantoneiras()">
|
||||
🔄 Atualizar Dados
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`✅ ${dados.length} cantoneiras carregadas do Data Manager`);
|
||||
console.log('🔍 Primeiro item:', dados[0]);
|
||||
|
||||
// Armazenar globalmente para filtros
|
||||
window.cantoneirasData = dados;
|
||||
console.log('💾 Dados armazenados em window.cantoneirasData');
|
||||
|
||||
// Exibir na tabela
|
||||
console.log('🎨 Chamando exibirCantoneirasV2...');
|
||||
console.log('🔍 Tipo de exibirCantoneirasV2:', typeof exibirCantoneirasV2);
|
||||
|
||||
if (typeof exibirCantoneirasV2 === 'function') {
|
||||
exibirCantoneirasV2(dados);
|
||||
} else {
|
||||
console.error('❌ exibirCantoneirasV2 não é uma função!');
|
||||
// Fallback: exibir diretamente
|
||||
console.log('🔄 Usando fallback para exibir dados...');
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = dados.map(item => `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge">${item.tipo}</span></td>
|
||||
<td><button class="btn btn-sm">Ver</button></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
console.log('✅ Tabela preenchida via fallback!');
|
||||
} else {
|
||||
console.error('❌ Elemento tbody não encontrado no fallback!');
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao carregar cantoneiras:', error);
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px; color: var(--color-error);">
|
||||
❌ Erro ao carregar dados: ${error.message}
|
||||
<br><br>
|
||||
<button class="btn btn-primary" onclick="atualizarDadosCantoneiras()">
|
||||
🔄 Tentar Novamente
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exibe cantoneiras na tabela (versão otimizada)
|
||||
*/
|
||||
function exibirCantoneirasV2(dados) {
|
||||
console.log(`📋 Exibindo ${dados.length} cantoneiras na tabela`);
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.error('❌ Elemento tbody não encontrado');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dados || dados.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px;">
|
||||
Nenhuma cantoneira encontrada
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Gerar HTML otimizado
|
||||
const html = dados.map(item => {
|
||||
const badgeColor = getBadgeColorV2(item.tipo);
|
||||
return `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge badge-${badgeColor}">${item.tipo}</span></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" onclick="verDetalhesCantoneira('${item.id}')">
|
||||
👁️ Ver
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
tbody.innerHTML = html;
|
||||
console.log('✅ Tabela atualizada com sucesso');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtra cantoneiras usando Data Manager
|
||||
*/
|
||||
function filtrarCantoneirasV2() {
|
||||
if (!window.cantoneirasData) {
|
||||
console.warn('⚠️ Dados não carregados ainda');
|
||||
return;
|
||||
}
|
||||
|
||||
// Obter filtros
|
||||
const tamanho = document.getElementById('cant-tamanho')?.value || '';
|
||||
const pesoMax = parseFloat(document.getElementById('cant-peso-max')?.value) || Infinity;
|
||||
const busca = document.getElementById('cant-busca')?.value || '';
|
||||
|
||||
console.log('🔍 Aplicando filtros:', { tamanho, pesoMax, busca });
|
||||
|
||||
// Aplicar filtros usando Data Manager
|
||||
let filtrados = window.cantoneirasData;
|
||||
|
||||
// Filtro por tipo/tamanho
|
||||
if (tamanho) {
|
||||
filtrados = window.dataManager.filterData(filtrados, { tipo: tamanho });
|
||||
}
|
||||
|
||||
// Filtro por peso máximo
|
||||
if (pesoMax < Infinity) {
|
||||
filtrados = window.dataManager.filterData(filtrados, { peso_kg_m: { max: pesoMax } });
|
||||
}
|
||||
|
||||
// Busca por nome
|
||||
if (busca) {
|
||||
filtrados = window.dataManager.searchData(filtrados, busca, ['nome', 'id']);
|
||||
}
|
||||
|
||||
console.log(`🎯 Filtrados: ${filtrados.length} de ${window.cantoneirasData.length}`);
|
||||
|
||||
// Exibir resultados
|
||||
exibirCantoneirasV2(filtrados);
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = filtrados.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa filtros das cantoneiras
|
||||
*/
|
||||
function limparFiltrosCantoneirasV2() {
|
||||
console.log('🧹 Limpando filtros');
|
||||
|
||||
// Limpar campos
|
||||
const tamanhoEl = document.getElementById('cant-tamanho');
|
||||
const pesoEl = document.getElementById('cant-peso-max');
|
||||
const buscaEl = document.getElementById('cant-busca');
|
||||
|
||||
if (tamanhoEl) tamanhoEl.value = '';
|
||||
if (pesoEl) pesoEl.value = '';
|
||||
if (buscaEl) buscaEl.value = '';
|
||||
|
||||
// Exibir todos os dados
|
||||
if (window.cantoneirasData) {
|
||||
exibirCantoneirasV2(window.cantoneirasData);
|
||||
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = window.cantoneirasData.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Força atualização dos dados das cantoneiras
|
||||
*/
|
||||
async function atualizarDadosCantoneiras() {
|
||||
console.log('🔄 Forçando atualização dos dados das cantoneiras...');
|
||||
|
||||
try {
|
||||
// Limpar cache específico
|
||||
localStorage.removeItem('acoCalcPro_cache_cantoneiras');
|
||||
|
||||
// Recarregar
|
||||
await carregarCantoneirasV2();
|
||||
|
||||
// Notificar sucesso
|
||||
alert('✅ Dados das cantoneiras atualizados com sucesso!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao atualizar dados:', error);
|
||||
alert('❌ Erro ao atualizar dados: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna cor do badge (versão otimizada)
|
||||
*/
|
||||
function getBadgeColorV2(tipo) {
|
||||
const cores = {
|
||||
'Pequena': 'info',
|
||||
'Média': 'success',
|
||||
'Grande': 'warning',
|
||||
'Muito Grande': 'warning',
|
||||
'Extra-Grande': 'error',
|
||||
'Massiva': 'error'
|
||||
};
|
||||
return cores[tipo] || 'info';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ver detalhes de uma cantoneira específica
|
||||
*/
|
||||
function verDetalhesCantoneira(id) {
|
||||
if (!window.cantoneirasData) {
|
||||
alert('❌ Dados não carregados');
|
||||
return;
|
||||
}
|
||||
|
||||
const item = window.cantoneirasData.find(c => c.id === id);
|
||||
if (!item) {
|
||||
alert('❌ Cantoneira não encontrada');
|
||||
return;
|
||||
}
|
||||
|
||||
alert(`
|
||||
📐 ${item.nome}
|
||||
|
||||
Lado: ${item.lado_mm} mm
|
||||
Espessura: ${item.espessura_mm} mm
|
||||
Peso: ${item.peso_kg_m.toFixed(2)} kg/m
|
||||
Área: ${item.area_cm2.toFixed(2)} cm²
|
||||
Momento de Inércia: ${item.momento_inercia_cm4.toFixed(2)} cm⁴
|
||||
Raio de Giração: ${item.raio_giracao_cm.toFixed(2)} cm
|
||||
Tipo: ${item.tipo}
|
||||
`);
|
||||
}
|
||||
|
||||
// Adicionar CSS para spinner
|
||||
if (!document.getElementById('spinner-styles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'spinner-styles';
|
||||
style.textContent = `
|
||||
.spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid var(--color-border);
|
||||
border-top: 2px solid var(--color-primary);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
console.log('✅ Perfis Loader V2 carregado com Data Manager');
|
||||
/**
|
||||
* CARREGADOR DE PERFIS - Usando Data Manager
|
||||
*
|
||||
* Funções específicas para carregar e exibir dados dos perfis
|
||||
* usando o sistema de cache inteligente.
|
||||
*/
|
||||
|
||||
// ========================================
|
||||
// CANTONEIRAS
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Carrega dados das cantoneiras usando o Data Manager
|
||||
*/
|
||||
async function carregarCantoneirasV2() {
|
||||
console.log('🔧 carregarCantoneirasV2() - Nova versão com Data Manager');
|
||||
|
||||
try {
|
||||
// Verificar se o elemento existe
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.error('❌ Elemento cantoneiras-tbody não encontrado!');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('✅ Elemento tbody encontrado');
|
||||
|
||||
// Mostrar loading
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px;">
|
||||
<div style="display: flex; align-items: center; justify-content: center; gap: 10px;">
|
||||
<div class="spinner"></div>
|
||||
📊 Carregando cantoneiras do banco de dados...
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
// Carregar dados via Data Manager
|
||||
const dados = await window.dataManager.getData('cantoneiras');
|
||||
|
||||
if (!dados || dados.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px; color: var(--color-error);">
|
||||
❌ Nenhuma cantoneira encontrada no banco de dados.
|
||||
<br><br>
|
||||
<button class="btn btn-primary" onclick="atualizarDadosCantoneiras()">
|
||||
🔄 Atualizar Dados
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`✅ ${dados.length} cantoneiras carregadas do Data Manager`);
|
||||
console.log('🔍 Primeiro item:', dados[0]);
|
||||
|
||||
// Armazenar globalmente para filtros
|
||||
window.cantoneirasData = dados;
|
||||
console.log('💾 Dados armazenados em window.cantoneirasData');
|
||||
|
||||
// Exibir na tabela
|
||||
console.log('🎨 Chamando exibirCantoneirasV2...');
|
||||
console.log('🔍 Tipo de exibirCantoneirasV2:', typeof exibirCantoneirasV2);
|
||||
|
||||
if (typeof exibirCantoneirasV2 === 'function') {
|
||||
exibirCantoneirasV2(dados);
|
||||
} else {
|
||||
console.error('❌ exibirCantoneirasV2 não é uma função!');
|
||||
// Fallback: exibir diretamente
|
||||
console.log('🔄 Usando fallback para exibir dados...');
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = dados.map(item => `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge">${item.tipo}</span></td>
|
||||
<td><button class="btn btn-sm">Ver</button></td>
|
||||
</tr>
|
||||
`).join('');
|
||||
console.log('✅ Tabela preenchida via fallback!');
|
||||
} else {
|
||||
console.error('❌ Elemento tbody não encontrado no fallback!');
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = dados.length;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao carregar cantoneiras:', error);
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (tbody) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px; color: var(--color-error);">
|
||||
❌ Erro ao carregar dados: ${error.message}
|
||||
<br><br>
|
||||
<button class="btn btn-primary" onclick="atualizarDadosCantoneiras()">
|
||||
🔄 Tentar Novamente
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exibe cantoneiras na tabela (versão otimizada)
|
||||
*/
|
||||
function exibirCantoneirasV2(dados) {
|
||||
console.log(`📋 Exibindo ${dados.length} cantoneiras na tabela`);
|
||||
|
||||
const tbody = document.getElementById('cantoneiras-tbody');
|
||||
if (!tbody) {
|
||||
console.error('❌ Elemento tbody não encontrado');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dados || dados.length === 0) {
|
||||
tbody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="9" style="text-align: center; padding: 20px;">
|
||||
Nenhuma cantoneira encontrada
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// Gerar HTML otimizado
|
||||
const html = dados.map(item => {
|
||||
const badgeColor = getBadgeColorV2(item.tipo);
|
||||
return `
|
||||
<tr>
|
||||
<td><strong>${item.nome}</strong></td>
|
||||
<td>${item.lado_mm}</td>
|
||||
<td>${item.espessura_mm}</td>
|
||||
<td>${item.peso_kg_m.toFixed(2)}</td>
|
||||
<td>${item.area_cm2.toFixed(2)}</td>
|
||||
<td>${item.momento_inercia_cm4.toFixed(2)}</td>
|
||||
<td>${item.raio_giracao_cm.toFixed(2)}</td>
|
||||
<td><span class="badge badge-${badgeColor}">${item.tipo}</span></td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-primary" onclick="verDetalhesCantoneira('${item.id}')">
|
||||
👁️ Ver
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
tbody.innerHTML = html;
|
||||
console.log('✅ Tabela atualizada com sucesso');
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtra cantoneiras usando Data Manager
|
||||
*/
|
||||
function filtrarCantoneirasV2() {
|
||||
if (!window.cantoneirasData) {
|
||||
console.warn('⚠️ Dados não carregados ainda');
|
||||
return;
|
||||
}
|
||||
|
||||
// Obter filtros
|
||||
const tamanho = document.getElementById('cant-tamanho')?.value || '';
|
||||
const pesoMax = parseFloat(document.getElementById('cant-peso-max')?.value) || Infinity;
|
||||
const busca = document.getElementById('cant-busca')?.value || '';
|
||||
|
||||
console.log('🔍 Aplicando filtros:', { tamanho, pesoMax, busca });
|
||||
|
||||
// Aplicar filtros usando Data Manager
|
||||
let filtrados = window.cantoneirasData;
|
||||
|
||||
// Filtro por tipo/tamanho
|
||||
if (tamanho) {
|
||||
filtrados = window.dataManager.filterData(filtrados, { tipo: tamanho });
|
||||
}
|
||||
|
||||
// Filtro por peso máximo
|
||||
if (pesoMax < Infinity) {
|
||||
filtrados = window.dataManager.filterData(filtrados, { peso_kg_m: { max: pesoMax } });
|
||||
}
|
||||
|
||||
// Busca por nome
|
||||
if (busca) {
|
||||
filtrados = window.dataManager.searchData(filtrados, busca, ['nome', 'id']);
|
||||
}
|
||||
|
||||
console.log(`🎯 Filtrados: ${filtrados.length} de ${window.cantoneirasData.length}`);
|
||||
|
||||
// Exibir resultados
|
||||
exibirCantoneirasV2(filtrados);
|
||||
|
||||
// Atualizar contador
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = filtrados.length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Limpa filtros das cantoneiras
|
||||
*/
|
||||
function limparFiltrosCantoneirasV2() {
|
||||
console.log('🧹 Limpando filtros');
|
||||
|
||||
// Limpar campos
|
||||
const tamanhoEl = document.getElementById('cant-tamanho');
|
||||
const pesoEl = document.getElementById('cant-peso-max');
|
||||
const buscaEl = document.getElementById('cant-busca');
|
||||
|
||||
if (tamanhoEl) tamanhoEl.value = '';
|
||||
if (pesoEl) pesoEl.value = '';
|
||||
if (buscaEl) buscaEl.value = '';
|
||||
|
||||
// Exibir todos os dados
|
||||
if (window.cantoneirasData) {
|
||||
exibirCantoneirasV2(window.cantoneirasData);
|
||||
|
||||
const totalEl = document.getElementById('cant-total');
|
||||
if (totalEl) {
|
||||
totalEl.textContent = window.cantoneirasData.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Força atualização dos dados das cantoneiras
|
||||
*/
|
||||
async function atualizarDadosCantoneiras() {
|
||||
console.log('🔄 Forçando atualização dos dados das cantoneiras...');
|
||||
|
||||
try {
|
||||
// Limpar cache específico
|
||||
localStorage.removeItem('acoCalcPro_cache_cantoneiras');
|
||||
|
||||
// Recarregar
|
||||
await carregarCantoneirasV2();
|
||||
|
||||
// Notificar sucesso
|
||||
alert('✅ Dados das cantoneiras atualizados com sucesso!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao atualizar dados:', error);
|
||||
alert('❌ Erro ao atualizar dados: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna cor do badge (versão otimizada)
|
||||
*/
|
||||
function getBadgeColorV2(tipo) {
|
||||
const cores = {
|
||||
'Pequena': 'info',
|
||||
'Média': 'success',
|
||||
'Grande': 'warning',
|
||||
'Muito Grande': 'warning',
|
||||
'Extra-Grande': 'error',
|
||||
'Massiva': 'error'
|
||||
};
|
||||
return cores[tipo] || 'info';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ver detalhes de uma cantoneira específica
|
||||
*/
|
||||
function verDetalhesCantoneira(id) {
|
||||
if (!window.cantoneirasData) {
|
||||
alert('❌ Dados não carregados');
|
||||
return;
|
||||
}
|
||||
|
||||
const item = window.cantoneirasData.find(c => c.id === id);
|
||||
if (!item) {
|
||||
alert('❌ Cantoneira não encontrada');
|
||||
return;
|
||||
}
|
||||
|
||||
alert(`
|
||||
📐 ${item.nome}
|
||||
|
||||
Lado: ${item.lado_mm} mm
|
||||
Espessura: ${item.espessura_mm} mm
|
||||
Peso: ${item.peso_kg_m.toFixed(2)} kg/m
|
||||
Área: ${item.area_cm2.toFixed(2)} cm²
|
||||
Momento de Inércia: ${item.momento_inercia_cm4.toFixed(2)} cm⁴
|
||||
Raio de Giração: ${item.raio_giracao_cm.toFixed(2)} cm
|
||||
Tipo: ${item.tipo}
|
||||
`);
|
||||
}
|
||||
|
||||
// Adicionar CSS para spinner
|
||||
if (!document.getElementById('spinner-styles')) {
|
||||
const style = document.createElement('style');
|
||||
style.id = 'spinner-styles';
|
||||
style.textContent = `
|
||||
.spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid var(--color-border);
|
||||
border-top: 2px solid var(--color-primary);
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
console.log('✅ Perfis Loader V2 carregado com Data Manager');
|
||||
|
||||
Reference in New Issue
Block a user