docs: implement Antigravity global rules

This commit is contained in:
2026-04-03 21:11:04 +00:00
parent 57ba9d1c5f
commit e8972e7107
83 changed files with 31408 additions and 31386 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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));

View File

@@ -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

View File

@@ -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');

View File

@@ -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');