1656 lines
73 KiB
HTML
1656 lines
73 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="pt-BR">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Gestor de Pintura Industrial - BrainSteel</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
:root {
|
||
--color-primary: #208c80;
|
||
--color-secondary: #f59e61;
|
||
--color-bg: #f5f5f5;
|
||
--color-surface: #ffffff;
|
||
--color-text: #1a1a1a;
|
||
--color-text-light: #666;
|
||
--color-border: #ddd;
|
||
--color-success: #4caf50;
|
||
--color-error: #f44336;
|
||
--color-warning: #ff9800;
|
||
--color-info: #2196f3;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||
background: var(--color-bg);
|
||
color: var(--color-text);
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
padding: 20px;
|
||
}
|
||
|
||
header {
|
||
background: var(--color-primary);
|
||
color: white;
|
||
padding: 30px 20px;
|
||
text-align: center;
|
||
margin-bottom: 30px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||
}
|
||
|
||
header h1 {
|
||
font-size: 2.2em;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
header p {
|
||
font-size: 0.95em;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.stage-tabs {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 30px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.stage-btn {
|
||
padding: 12px 24px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 1em;
|
||
font-weight: 500;
|
||
transition: all 0.3s ease;
|
||
background: white;
|
||
color: var(--color-primary);
|
||
border: 2px solid var(--color-primary);
|
||
}
|
||
|
||
.stage-btn.active {
|
||
background: var(--color-primary);
|
||
color: white;
|
||
}
|
||
|
||
.stage-btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||
}
|
||
|
||
.stage-content {
|
||
display: none;
|
||
animation: fadeIn 0.3s ease;
|
||
}
|
||
|
||
.stage-content.active {
|
||
display: block;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
.form-section {
|
||
background: white;
|
||
padding: 25px;
|
||
margin-bottom: 25px;
|
||
border-radius: 8px;
|
||
border-left: 5px solid var(--color-primary);
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
|
||
.form-section h2 {
|
||
color: var(--color-primary);
|
||
margin-bottom: 20px;
|
||
font-size: 1.4em;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.form-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||
gap: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.form-group {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
label {
|
||
margin-bottom: 8px;
|
||
font-weight: 500;
|
||
font-size: 0.95em;
|
||
color: var(--color-text);
|
||
}
|
||
|
||
input[type="text"],
|
||
input[type="number"],
|
||
input[type="date"],
|
||
select,
|
||
textarea {
|
||
padding: 12px;
|
||
border: 1px solid var(--color-border);
|
||
border-radius: 6px;
|
||
font-size: 1em;
|
||
font-family: inherit;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
input[type="text"]:focus,
|
||
input[type="number"]:focus,
|
||
input[type="date"]:focus,
|
||
select:focus,
|
||
textarea:focus {
|
||
outline: none;
|
||
border-color: var(--color-primary);
|
||
box-shadow: 0 0 0 3px rgba(32, 140, 128, 0.1);
|
||
}
|
||
|
||
textarea {
|
||
resize: vertical;
|
||
min-height: 80px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 12px 24px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
font-size: 1em;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--color-primary);
|
||
color: white;
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #1a6b60;
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(32, 140, 128, 0.3);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: var(--color-secondary);
|
||
color: white;
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
background: #e68c4a;
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.btn-success {
|
||
background: var(--color-success);
|
||
color: white;
|
||
}
|
||
|
||
.btn-success:hover {
|
||
background: #45a049;
|
||
}
|
||
|
||
.btn-small {
|
||
padding: 8px 16px;
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
.btn-group {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.table-responsive {
|
||
overflow-x: auto;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
background: white;
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
|
||
th {
|
||
background: var(--color-primary);
|
||
color: white;
|
||
padding: 15px;
|
||
text-align: left;
|
||
font-weight: 600;
|
||
}
|
||
|
||
td {
|
||
padding: 15px;
|
||
border-bottom: 1px solid var(--color-border);
|
||
}
|
||
|
||
tr:hover {
|
||
background: #f9f9f9;
|
||
}
|
||
|
||
.card {
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.card-header {
|
||
font-size: 1.1em;
|
||
font-weight: 600;
|
||
color: var(--color-primary);
|
||
margin-bottom: 15px;
|
||
border-bottom: 2px solid var(--color-border);
|
||
padding-bottom: 10px;
|
||
}
|
||
|
||
.metric-box {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 20px;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.metric {
|
||
background: linear-gradient(135deg, var(--color-primary), #1a6b60);
|
||
color: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
text-align: center;
|
||
}
|
||
|
||
.metric-value {
|
||
font-size: 2em;
|
||
font-weight: bold;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.metric-label {
|
||
font-size: 0.9em;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.alert {
|
||
padding: 15px;
|
||
border-radius: 6px;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.alert-success {
|
||
background: #c8e6c9;
|
||
color: #2e7d32;
|
||
border-left: 4px solid var(--color-success);
|
||
}
|
||
|
||
.alert-error {
|
||
background: #ffcdd2;
|
||
color: #c62828;
|
||
border-left: 4px solid var(--color-error);
|
||
}
|
||
|
||
.alert-warning {
|
||
background: #fff3cd;
|
||
color: #856404;
|
||
border-left: 4px solid var(--color-warning);
|
||
}
|
||
|
||
.alert-info {
|
||
background: #d1ecf1;
|
||
color: #0c5460;
|
||
border-left: 4px solid var(--color-info);
|
||
}
|
||
|
||
.add-row-btn {
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.row-actions {
|
||
display: flex;
|
||
gap: 10px;
|
||
}
|
||
|
||
.icon {
|
||
display: inline-block;
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.summary-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||
gap: 20px;
|
||
margin: 20px 0;
|
||
}
|
||
|
||
.summary-card {
|
||
background: white;
|
||
padding: 20px;
|
||
border-radius: 8px;
|
||
border: 2px solid var(--color-border);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.summary-card:hover {
|
||
border-color: var(--color-primary);
|
||
box-shadow: 0 4px 12px rgba(32, 140, 128, 0.15);
|
||
}
|
||
|
||
.summary-card h3 {
|
||
color: var(--color-primary);
|
||
margin-bottom: 15px;
|
||
font-size: 1.1em;
|
||
}
|
||
|
||
.summary-value {
|
||
font-size: 1.8em;
|
||
font-weight: bold;
|
||
color: var(--color-text);
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 0.85em;
|
||
color: var(--color-text-light);
|
||
}
|
||
|
||
.variance {
|
||
padding: 8px 12px;
|
||
border-radius: 4px;
|
||
font-size: 0.9em;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.variance-positive {
|
||
background: #c8e6c9;
|
||
color: #2e7d32;
|
||
}
|
||
|
||
.variance-negative {
|
||
background: #ffcdd2;
|
||
color: #c62828;
|
||
}
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 20px;
|
||
background: var(--color-border);
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: var(--color-primary);
|
||
transition: width 0.3s ease;
|
||
}
|
||
|
||
.page-break {
|
||
page-break-after: always;
|
||
margin: 40px 0;
|
||
border-top: 2px dashed var(--color-border);
|
||
padding-top: 20px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.form-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.stage-tabs {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.stage-btn {
|
||
width: 100%;
|
||
}
|
||
|
||
header h1 {
|
||
font-size: 1.6em;
|
||
}
|
||
|
||
.metric-box {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
@media print {
|
||
body {
|
||
background: white;
|
||
}
|
||
|
||
.stage-tabs,
|
||
.btn-group,
|
||
.no-print {
|
||
display: none !important;
|
||
}
|
||
|
||
.form-section,
|
||
.card,
|
||
table {
|
||
box-shadow: none;
|
||
page-break-inside: avoid;
|
||
}
|
||
|
||
header {
|
||
background: var(--color-primary) !important;
|
||
-webkit-print-color-adjust: exact;
|
||
print-color-adjust: exact;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header>
|
||
<h1>🎨 Gestor de Pintura Industrial</h1>
|
||
<p>Planejamento, Controle e Análise de Eficiência de Processos de Pintura</p>
|
||
</header>
|
||
|
||
<div class="stage-tabs no-print">
|
||
<button class="stage-btn active" onclick="switchStage(1)">📋 Etapa 1: Planejamento</button>
|
||
<button class="stage-btn" onclick="switchStage(2)">🔧 Etapa 2: Controle</button>
|
||
<button class="stage-btn" onclick="switchStage(3)">📊 Etapa 3: Análise</button>
|
||
</div>
|
||
|
||
<!-- ETAPA 1: PLANEJAMENTO -->
|
||
<div id="stage1" class="stage-content active">
|
||
<div class="form-section">
|
||
<h2>📌 Identificação do Projeto</h2>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Nome do Projeto</label>
|
||
<input type="text" id="projectName" placeholder="Ex: Estrutura Metálica Galpão A">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Cliente</label>
|
||
<input type="text" id="projectClient" placeholder="Ex: Empresa XYZ">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Data de Início Planejado</label>
|
||
<input type="date" id="projectStartDate">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Data de Conclusão Planejada</label>
|
||
<input type="date" id="projectEndDate">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Responsável Técnico</label>
|
||
<input type="text" id="projectTechnician" placeholder="Ex: Eng. João Silva">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Ambiente/Classe de Corrosividade</label>
|
||
<select id="projectEnvironment">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="C1">C1 - Muito Baixa</option>
|
||
<option value="C2">C2 - Baixa</option>
|
||
<option value="C3">C3 - Média</option>
|
||
<option value="C4">C4 - Alta</option>
|
||
<option value="C5">C5 - Muito Alta</option>
|
||
<option value="CX">CX - Extremamente Alta</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-section">
|
||
<h2>📐 Geometria e Dimensões das Peças</h2>
|
||
<div id="geometryContainer">
|
||
<div class="card">
|
||
<div class="card-header">Peça Metálica #1</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Descrição da Peça</label>
|
||
<input type="text" class="geom-description" placeholder="Ex: Pilar I-250, Viga Lateral">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Dimensões (L x A x P em mm)</label>
|
||
<input type="text" class="geom-dimensions" placeholder="Ex: 6000 x 250 x 150">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peso Unitário (Kgf)</label>
|
||
<input type="number" class="geom-weight" placeholder="Ex: 450">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Tipo de Geometria</label>
|
||
<select class="geom-type">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="plana">Plana</option>
|
||
<option value="tubular">Tubular</option>
|
||
<option value="complexa">Complexa (vários ângulos/junções)</option>
|
||
<option value="soldada">Soldada (com muitas junções)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Área de Superfície Estimada (m²)</label>
|
||
<input type="number" class="geom-area" step="0.01" placeholder="Ex: 12.50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Fator de Complexidade (1-5)</label>
|
||
<input type="number" class="geom-complexity" min="1" max="5" step="0.5" placeholder="1=simples, 5=muito complexa">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Quantidade de Peças</label>
|
||
<input type="number" class="geom-quantity" value="1" min="1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Observações</label>
|
||
<textarea class="geom-notes" placeholder="Furos, arredondados, cantos aguçados, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeGeometry(this)">❌ Remover Peça</button>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-primary add-row-btn" onclick="addGeometry()">➕ Adicionar Peça</button>
|
||
</div>
|
||
|
||
<div class="form-section">
|
||
<h2>🎯 Esquema de Pintura Especificado</h2>
|
||
<div id="paintingSchemeContainer">
|
||
<div class="card">
|
||
<div class="card-header">Demão #1</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Nome/Descrição da Tinta</label>
|
||
<input type="text" class="paint-name" placeholder="Ex: Primer Epóxi 2 componentes">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Tipo de Tinta</label>
|
||
<select class="paint-type">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="epoxy">Epóxi (bicomponente)</option>
|
||
<option value="polyurethane">Poliuretano (PU)</option>
|
||
<option value="silicate-zinc">Silicato Inorgânico de Zinco</option>
|
||
<option value="acrylic">Acrílica</option>
|
||
<option value="alkyd">Alquídica</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Sólidos por Volume (%)</label>
|
||
<input type="number" class="paint-sv" step="1" placeholder="Ex: 63">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Rendimento Teórico (m²/L)</label>
|
||
<input type="number" class="paint-yield" step="0.1" placeholder="Ex: 10.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura de Película Seca - Mín (μm)</label>
|
||
<input type="number" class="paint-eps-min" placeholder="Ex: 60">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura de Película Seca - Máx (μm)</label>
|
||
<input type="number" class="paint-eps-max" placeholder="Ex: 80">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Diluição Recomendada (%)</label>
|
||
<input type="number" class="paint-dilution" step="1" placeholder="Ex: 10">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Fabricante / Referência</label>
|
||
<input type="text" class="paint-manufacturer" placeholder="Ex: Sherwin-Williams / ProClassic">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Observações</label>
|
||
<textarea class="paint-notes" placeholder="Tempo de indução, cura, tempo entre demãos, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removePaintScheme(this)">❌ Remover Demão</button>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-primary add-row-btn" onclick="addPaintScheme()">➕ Adicionar Demão</button>
|
||
</div>
|
||
|
||
<div class="form-section">
|
||
<h2>📊 Cálculo do Plano Teórico</h2>
|
||
<button class="btn btn-primary" onclick="calculatePlan()">🧮 Calcular Plano de Pintura</button>
|
||
<div id="planResults" style="margin-top: 20px;"></div>
|
||
</div>
|
||
|
||
<div class="btn-group no-print">
|
||
<button class="btn btn-primary" onclick="savePlan()">💾 Salvar Planejamento</button>
|
||
<button class="btn btn-secondary" onclick="exportPlanPDF()">📄 Exportar Plano em PDF</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ETAPA 2: CONTROLE -->
|
||
<div id="stage2" class="stage-content">
|
||
<div class="form-section">
|
||
<h2>📝 Fichas de Controle de Aplicação</h2>
|
||
<p style="color: var(--color-text-light); margin-bottom: 15px;">Registro das condições reais e dados de aplicação durante o processo</p>
|
||
|
||
<div id="controlRecordsContainer">
|
||
<div class="card">
|
||
<div class="card-header">Registro de Aplicação #1</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Demão/Camada</label>
|
||
<select class="ctrl-coat">
|
||
<option value="primer">Primer</option>
|
||
<option value="coat-1">Demão 1</option>
|
||
<option value="coat-2">Demão 2</option>
|
||
<option value="coat-3">Demão 3</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peça/Lote Pintado</label>
|
||
<input type="text" class="ctrl-piece" placeholder="Ex: Pilar I-250 (4 un.)">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Data de Aplicação</label>
|
||
<input type="date" class="ctrl-date">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Operador</label>
|
||
<input type="text" class="ctrl-operator" placeholder="Ex: João da Silva">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>⚖️ Peso Real Pintado (Kgf)</label>
|
||
<input type="number" class="ctrl-weight-real" step="0.1" placeholder="Ex: 1800.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Volume de Tinta Utilizado (L)</label>
|
||
<input type="number" class="ctrl-volume" step="0.01" placeholder="Ex: 12.50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Área Pintada (m²)</label>
|
||
<input type="number" class="ctrl-area" step="0.01" placeholder="Ex: 125.00">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Úmida (μm) - Média</label>
|
||
<input type="number" class="ctrl-epu" placeholder="Ex: 576">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Calculada (μm)</label>
|
||
<input type="number" class="ctrl-eps-real" placeholder="Ex: 325">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Método Aplicação Real</label>
|
||
<select class="ctrl-method">
|
||
<option value="airless">Airless</option>
|
||
<option value="hvlp">HVLP</option>
|
||
<option value="roller">Rolo</option>
|
||
<option value="brush">Pincel</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Rendimento Real (m²/L)</label>
|
||
<input type="number" class="ctrl-real-yield" step="0.1" placeholder="Ex: 10.0">
|
||
</div>
|
||
<div class="form-group" style="grid-column: 1 / -1;">
|
||
<label>Observações / Incidências</label>
|
||
<textarea class="ctrl-notes" placeholder="Defeitos, retrabalho, problemas encontrados, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeControlRecord(this)">❌ Remover Registro</button>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-primary add-row-btn" onclick="addControlRecord()">➕ Adicionar Registro</button>
|
||
</div>
|
||
|
||
<div class="form-section">
|
||
<h2>✅ Inspeção de Conformidade</h2>
|
||
<div id="inspectionContainer">
|
||
<div class="card">
|
||
<div class="card-header">Inspeção #1</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Data da Inspeção</label>
|
||
<input type="date" class="insp-date">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Inspetor</label>
|
||
<input type="text" class="insp-inspector" placeholder="Ex: Eng. Marina Costa">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peça Inspecionada</label>
|
||
<input type="text" class="insp-piece" placeholder="Ex: Pilar I-250">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 1</label>
|
||
<input type="number" class="insp-eps-1" placeholder="Ex: 328">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 2</label>
|
||
<input type="number" class="insp-eps-2" placeholder="Ex: 331">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 3</label>
|
||
<input type="number" class="insp-eps-3" placeholder="Ex: 326">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Teste de Aderência (0-5B)</label>
|
||
<select class="insp-adhesion">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="5B">5B - Sem desprendimento</option>
|
||
<option value="4B">4B - Pequenos desprendimentos</option>
|
||
<option value="3B">3B - Desprendimento moderado</option>
|
||
<option value="2B">2B - Desprendimento significativo</option>
|
||
<option value="1B">1B - Desprendimento importante</option>
|
||
<option value="0B">0B - Completo desprendimento</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Aparência Visual</label>
|
||
<select class="insp-appearance">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="excellent">Excelente</option>
|
||
<option value="good">Boa</option>
|
||
<option value="acceptable">Aceitável</option>
|
||
<option value="deficient">Deficiente</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="grid-column: 1 / -1;">
|
||
<label>Defeitos Encontrados</label>
|
||
<textarea class="insp-defects" placeholder="Bolhas, trincas, corrosão, áreas descascadas, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeInspection(this)">❌ Remover Inspeção</button>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-primary add-row-btn" onclick="addInspection()">➕ Adicionar Inspeção</button>
|
||
</div>
|
||
|
||
<div class="btn-group no-print">
|
||
<button class="btn btn-primary" onclick="saveControlData()">💾 Salvar Controle</button>
|
||
<button class="btn btn-secondary" onclick="exportControlPDF()">📄 Exportar Fichas em PDF</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ETAPA 3: ANÁLISE -->
|
||
<div id="stage3" class="stage-content">
|
||
<div class="form-section">
|
||
<h2>📊 Análise Comparativa e Eficiência</h2>
|
||
<button class="btn btn-primary" onclick="generateAnalysis()">🔍 Gerar Análise de Eficiência</button>
|
||
<div id="analysisResults" style="margin-top: 20px;"></div>
|
||
</div>
|
||
|
||
<div class="btn-group no-print">
|
||
<button class="btn btn-primary" onclick="exportAnalysisPDF()">📄 Exportar Relatório Final em PDF</button>
|
||
<button class="btn btn-secondary" onclick="exportAllDataJSON()">📥 Exportar Dados Completos (JSON)</button>
|
||
<button class="btn btn-secondary" onclick="resetAll()">🔄 Reiniciar Aplicação</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// ========== VARIÁVEIS GLOBAIS ==========
|
||
let appData = {
|
||
plan: {},
|
||
control: [],
|
||
inspection: []
|
||
};
|
||
|
||
// ========== FUNÇÕES DE NAVEGAÇÃO ==========
|
||
function switchStage(stage) {
|
||
document.querySelectorAll('.stage-content').forEach(el => el.classList.remove('active'));
|
||
document.querySelectorAll('.stage-btn').forEach(el => el.classList.remove('active'));
|
||
|
||
document.getElementById(`stage${stage}`).classList.add('active');
|
||
document.querySelectorAll('.stage-btn')[stage - 1].classList.add('active');
|
||
}
|
||
|
||
// ========== FUNÇÕES DE GEOMETRIA ==========
|
||
function addGeometry() {
|
||
const container = document.getElementById('geometryContainer');
|
||
const count = container.children.length + 1;
|
||
const html = `
|
||
<div class="card">
|
||
<div class="card-header">Peça Metálica #${count}</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Descrição da Peça</label>
|
||
<input type="text" class="geom-description" placeholder="Ex: Pilar I-250, Viga Lateral">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Dimensões (L x A x P em mm)</label>
|
||
<input type="text" class="geom-dimensions" placeholder="Ex: 6000 x 250 x 150">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peso Unitário (Kgf)</label>
|
||
<input type="number" class="geom-weight" placeholder="Ex: 450">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Tipo de Geometria</label>
|
||
<select class="geom-type">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="plana">Plana</option>
|
||
<option value="tubular">Tubular</option>
|
||
<option value="complexa">Complexa (vários ângulos/junções)</option>
|
||
<option value="soldada">Soldada (com muitas junções)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Área de Superfície Estimada (m²)</label>
|
||
<input type="number" class="geom-area" step="0.01" placeholder="Ex: 12.50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Fator de Complexidade (1-5)</label>
|
||
<input type="number" class="geom-complexity" min="1" max="5" step="0.5" placeholder="1=simples, 5=muito complexa">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Quantidade de Peças</label>
|
||
<input type="number" class="geom-quantity" value="1" min="1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Observações</label>
|
||
<textarea class="geom-notes" placeholder="Furos, arredondados, cantos aguçados, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeGeometry(this)">❌ Remover Peça</button>
|
||
</div>
|
||
`;
|
||
container.insertAdjacentHTML('beforeend', html);
|
||
}
|
||
|
||
function removeGeometry(btn) {
|
||
btn.closest('.card').remove();
|
||
}
|
||
|
||
// ========== FUNÇÕES DE ESQUEMA DE PINTURA ==========
|
||
function addPaintScheme() {
|
||
const container = document.getElementById('paintingSchemeContainer');
|
||
const count = container.children.length + 1;
|
||
const html = `
|
||
<div class="card">
|
||
<div class="card-header">Demão #${count}</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Nome/Descrição da Tinta</label>
|
||
<input type="text" class="paint-name" placeholder="Ex: Primer Epóxi 2 componentes">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Tipo de Tinta</label>
|
||
<select class="paint-type">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="epoxy">Epóxi (bicomponente)</option>
|
||
<option value="polyurethane">Poliuretano (PU)</option>
|
||
<option value="silicate-zinc">Silicato Inorgânico de Zinco</option>
|
||
<option value="acrylic">Acrílica</option>
|
||
<option value="alkyd">Alquídica</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Sólidos por Volume (%)</label>
|
||
<input type="number" class="paint-sv" step="1" placeholder="Ex: 63">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Rendimento Teórico (m²/L)</label>
|
||
<input type="number" class="paint-yield" step="0.1" placeholder="Ex: 10.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura de Película Seca - Mín (μm)</label>
|
||
<input type="number" class="paint-eps-min" placeholder="Ex: 60">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura de Película Seca - Máx (μm)</label>
|
||
<input type="number" class="paint-eps-max" placeholder="Ex: 80">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Diluição Recomendada (%)</label>
|
||
<input type="number" class="paint-dilution" step="1" placeholder="Ex: 10">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Fabricante / Referência</label>
|
||
<input type="text" class="paint-manufacturer" placeholder="Ex: Sherwin-Williams / ProClassic">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Observações</label>
|
||
<textarea class="paint-notes" placeholder="Tempo de indução, cura, tempo entre demãos, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removePaintScheme(this)">❌ Remover Demão</button>
|
||
</div>
|
||
`;
|
||
container.insertAdjacentHTML('beforeend', html);
|
||
}
|
||
|
||
function removePaintScheme(btn) {
|
||
btn.closest('.card').remove();
|
||
}
|
||
|
||
// ========== FUNÇÕES DE CONTROLE ==========
|
||
function addControlRecord() {
|
||
const container = document.getElementById('controlRecordsContainer');
|
||
const count = container.children.length + 1;
|
||
const html = `
|
||
<div class="card">
|
||
<div class="card-header">Registro de Aplicação #${count}</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Demão/Camada</label>
|
||
<select class="ctrl-coat">
|
||
<option value="primer">Primer</option>
|
||
<option value="coat-1">Demão 1</option>
|
||
<option value="coat-2">Demão 2</option>
|
||
<option value="coat-3">Demão 3</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peça/Lote Pintado</label>
|
||
<input type="text" class="ctrl-piece" placeholder="Ex: Pilar I-250 (4 un.)">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Data de Aplicação</label>
|
||
<input type="date" class="ctrl-date">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Operador</label>
|
||
<input type="text" class="ctrl-operator" placeholder="Ex: João da Silva">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>⚖️ Peso Real Pintado (Kgf)</label>
|
||
<input type="number" class="ctrl-weight-real" step="0.1" placeholder="Ex: 1800.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Volume de Tinta Utilizado (L)</label>
|
||
<input type="number" class="ctrl-volume" step="0.01" placeholder="Ex: 12.50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Área Pintada (m²)</label>
|
||
<input type="number" class="ctrl-area" step="0.01" placeholder="Ex: 125.00">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Úmida (μm) - Média</label>
|
||
<input type="number" class="ctrl-epu" placeholder="Ex: 576">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Calculada (μm)</label>
|
||
<input type="number" class="ctrl-eps-real" placeholder="Ex: 325">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Método Aplicação Real</label>
|
||
<select class="ctrl-method">
|
||
<option value="airless">Airless</option>
|
||
<option value="hvlp">HVLP</option>
|
||
<option value="roller">Rolo</option>
|
||
<option value="brush">Pincel</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Rendimento Real (m²/L)</label>
|
||
<input type="number" class="ctrl-real-yield" step="0.1" placeholder="Ex: 10.0">
|
||
</div>
|
||
<div class="form-group" style="grid-column: 1 / -1;">
|
||
<label>Observações / Incidências</label>
|
||
<textarea class="ctrl-notes" placeholder="Defeitos, retrabalho, problemas encontrados, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeControlRecord(this)">❌ Remover Registro</button>
|
||
</div>
|
||
`;
|
||
container.insertAdjacentHTML('beforeend', html);
|
||
}
|
||
|
||
function removeControlRecord(btn) {
|
||
btn.closest('.card').remove();
|
||
}
|
||
|
||
// ========== FUNÇÕES DE INSPEÇÃO ==========
|
||
function addInspection() {
|
||
const container = document.getElementById('inspectionContainer');
|
||
const count = container.children.length + 1;
|
||
const html = `
|
||
<div class="card">
|
||
<div class="card-header">Inspeção #${count}</div>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label>Data da Inspeção</label>
|
||
<input type="date" class="insp-date">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Inspetor</label>
|
||
<input type="text" class="insp-inspector" placeholder="Ex: Eng. Marina Costa">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Peça Inspecionada</label>
|
||
<input type="text" class="insp-piece" placeholder="Ex: Pilar I-250">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 1</label>
|
||
<input type="number" class="insp-eps-1" placeholder="Ex: 328">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 2</label>
|
||
<input type="number" class="insp-eps-2" placeholder="Ex: 331">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Espessura Seca Medida (μm) - Ponto 3</label>
|
||
<input type="number" class="insp-eps-3" placeholder="Ex: 326">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Teste de Aderência (0-5B)</label>
|
||
<select class="insp-adhesion">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="5B">5B - Sem desprendimento</option>
|
||
<option value="4B">4B - Pequenos desprendimentos</option>
|
||
<option value="3B">3B - Desprendimento moderado</option>
|
||
<option value="2B">2B - Desprendimento significativo</option>
|
||
<option value="1B">1B - Desprendimento importante</option>
|
||
<option value="0B">0B - Completo desprendimento</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Aparência Visual</label>
|
||
<select class="insp-appearance">
|
||
<option value="">-- Selecione --</option>
|
||
<option value="excellent">Excelente</option>
|
||
<option value="good">Boa</option>
|
||
<option value="acceptable">Aceitável</option>
|
||
<option value="deficient">Deficiente</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" style="grid-column: 1 / -1;">
|
||
<label>Defeitos Encontrados</label>
|
||
<textarea class="insp-defects" placeholder="Bolhas, trincas, corrosão, áreas descascadas, etc."></textarea>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-secondary btn-small" onclick="removeInspection(this)">❌ Remover Inspeção</button>
|
||
</div>
|
||
`;
|
||
container.insertAdjacentHTML('beforeend', html);
|
||
}
|
||
|
||
function removeInspection(btn) {
|
||
btn.closest('.card').remove();
|
||
}
|
||
|
||
// ========== CÁLCULOS PRINCIPAIS ==========
|
||
function calculatePlan() {
|
||
const geometries = document.querySelectorAll('#geometryContainer .card');
|
||
const paintSchemes = document.querySelectorAll('#paintingSchemeContainer .card');
|
||
|
||
if (geometries.length === 0) {
|
||
alert('Adicione pelo menos uma peça!');
|
||
return;
|
||
}
|
||
|
||
if (paintSchemes.length === 0) {
|
||
alert('Adicione pelo menos um esquema de pintura!');
|
||
return;
|
||
}
|
||
|
||
let results = '<div class="alert alert-info">📊 <strong>Cálculos do Plano Teórico:</strong></div>';
|
||
results += '<div class="summary-grid">';
|
||
|
||
let totalArea = 0;
|
||
let totalWeight = 0;
|
||
|
||
// Análise de geometrias
|
||
geometries.forEach((card, index) => {
|
||
const desc = card.querySelector('.geom-description').value;
|
||
const area = parseFloat(card.querySelector('.geom-area').value) || 0;
|
||
const weight = parseFloat(card.querySelector('.geom-weight').value) || 0;
|
||
const qty = parseFloat(card.querySelector('.geom-quantity').value) || 1;
|
||
const complexity = parseFloat(card.querySelector('.geom-complexity').value) || 1;
|
||
|
||
const totalPieceArea = area * qty;
|
||
const totalPieceWeight = weight * qty;
|
||
totalArea += totalPieceArea;
|
||
totalWeight += totalPieceWeight;
|
||
|
||
results += `
|
||
<div class="summary-card">
|
||
<h3>Peça ${index + 1}</h3>
|
||
<div class="summary-value">${totalPieceArea.toFixed(2)}</div>
|
||
<div class="summary-label">Área Total (m²)</div>
|
||
<div class="summary-value" style="margin-top: 10px; font-size: 1.3em;">⚖️ ${totalPieceWeight.toFixed(1)}</div>
|
||
<div class="summary-label">Peso Total (Kgf)</div>
|
||
<div class="summary-label" style="margin-top: 10px; color: var(--color-primary);">Complexidade: ${complexity}/5</div>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
results += '</div>';
|
||
|
||
// Análise de esquema de pintura
|
||
results += '<div style="margin-top: 30px;"><h3 style="color: var(--color-primary); margin-bottom: 20px;">📋 Especificações de Pintura:</h3>';
|
||
results += '<div class="table-responsive"><table><tr><th>Demão</th><th>Tipo</th><th>SV (%)</th><th>Rendimento (m²/L)</th><th>EPSmín/máx (μm)</th><th>Vol. Teórico (L)</th></tr>';
|
||
|
||
let totalTheoricalVolume = 0;
|
||
|
||
paintSchemes.forEach((card, index) => {
|
||
const name = card.querySelector('.paint-name').value || 'Demão ' + (index + 1);
|
||
const type = card.querySelector('.paint-type').value;
|
||
const sv = parseFloat(card.querySelector('.paint-sv').value) || 0;
|
||
const yield_ = parseFloat(card.querySelector('.paint-yield').value) || 0;
|
||
const epsMin = parseFloat(card.querySelector('.paint-eps-min').value) || 0;
|
||
const epsMax = parseFloat(card.querySelector('.paint-eps-max').value) || 0;
|
||
|
||
// Cálculo teórico de volume: Volume = Área × EPS / Rendimento
|
||
const volumeMin = totalArea * epsMin / (yield_ * 1000);
|
||
const volumeMax = totalArea * epsMax / (yield_ * 1000);
|
||
const volumeAvg = (volumeMin + volumeMax) / 2;
|
||
totalTheoricalVolume += volumeAvg;
|
||
|
||
results += `<tr>
|
||
<td>${name}</td>
|
||
<td>${type || '--'}</td>
|
||
<td>${sv}</td>
|
||
<td>${yield_.toFixed(1)}</td>
|
||
<td>${epsMin}/${epsMax}</td>
|
||
<td>${volumeAvg.toFixed(2)}</td>
|
||
</tr>`;
|
||
});
|
||
|
||
results += '</table></div></div>';
|
||
|
||
// Resumo final COM PESO
|
||
results += `
|
||
<div style="margin-top: 30px; background: #f0f8f7; padding: 20px; border-radius: 8px;">
|
||
<h3 style="color: var(--color-primary); margin-bottom: 15px;">🎯 Resumo do Plano:</h3>
|
||
<div class="metric-box">
|
||
<div class="metric">
|
||
<div class="metric-value">${totalArea.toFixed(2)}</div>
|
||
<div class="metric-label">Área Total (m²)</div>
|
||
</div>
|
||
<div class="metric">
|
||
<div class="metric-value">⚖️ ${totalWeight.toFixed(1)}</div>
|
||
<div class="metric-label">Peso Total (Kgf)</div>
|
||
</div>
|
||
<div class="metric">
|
||
<div class="metric-value">${totalTheoricalVolume.toFixed(2)}</div>
|
||
<div class="metric-label">Volume Teórico (L)</div>
|
||
</div>
|
||
<div class="metric">
|
||
<div class="metric-value">${(totalTheoricalVolume / totalArea).toFixed(3)}</div>
|
||
<div class="metric-label">Consumo/m² (L/m²)</div>
|
||
</div>
|
||
<div class="metric">
|
||
<div class="metric-value">${(totalTheoricalVolume / totalWeight).toFixed(4)}</div>
|
||
<div class="metric-label">Consumo/Kgf (L/Kgf)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
document.getElementById('planResults').innerHTML = results;
|
||
}
|
||
|
||
// ========== FUNÇÕES DE ANÁLISE ==========
|
||
function generateAnalysis() {
|
||
const controlCards = document.querySelectorAll('#controlRecordsContainer .card');
|
||
const inspectionCards = document.querySelectorAll('#inspectionContainer .card');
|
||
|
||
if (controlCards.length === 0) {
|
||
alert('Adicione registros de controle na Etapa 2!');
|
||
return;
|
||
}
|
||
|
||
let results = '<div class="alert alert-info">📊 <strong>Análise Comparativa de Eficiência:</strong></div>';
|
||
|
||
// Coleta dados de controle
|
||
let totalRealVolume = 0;
|
||
let totalRealArea = 0;
|
||
let totalRealWeight = 0;
|
||
let totalEPSMean = 0;
|
||
let recordCount = 0;
|
||
let conformanceCount = 0;
|
||
|
||
const controlData = [];
|
||
|
||
controlCards.forEach(card => {
|
||
const volume = parseFloat(card.querySelector('.ctrl-volume').value) || 0;
|
||
const area = parseFloat(card.querySelector('.ctrl-area').value) || 0;
|
||
const weight = parseFloat(card.querySelector('.ctrl-weight-real').value) || 0;
|
||
const epsReal = parseFloat(card.querySelector('.ctrl-eps-real').value) || 0;
|
||
|
||
if (volume > 0 && (area > 0 || weight > 0)) {
|
||
totalRealVolume += volume;
|
||
totalRealArea += area;
|
||
totalRealWeight += weight;
|
||
totalEPSMean += epsReal;
|
||
recordCount++;
|
||
|
||
controlData.push({
|
||
volume,
|
||
area,
|
||
weight,
|
||
eps: epsReal,
|
||
yieldArea: area > 0 ? area / volume : 0,
|
||
yieldWeight: weight > 0 ? weight / volume : 0
|
||
});
|
||
}
|
||
});
|
||
|
||
if (recordCount === 0) {
|
||
alert('Nenhum registro de controle válido encontrado!');
|
||
return;
|
||
}
|
||
|
||
const realYieldArea = totalRealArea > 0 ? totalRealArea / totalRealVolume : 0;
|
||
const realYieldWeight = totalRealWeight > 0 ? totalRealWeight / totalRealVolume : 0;
|
||
const meanEPS = totalEPSMean / recordCount;
|
||
|
||
// Comparação teórico vs real
|
||
const theoryDiv = document.getElementById('planResults');
|
||
const theoryText = theoryDiv.innerText;
|
||
const theoryVolumeMatch = theoryText.match(/Volume Teórico \(L\)[\s\S]*?([\d.]+)/);
|
||
const theoryVolume = theoryVolumeMatch ? parseFloat(theoryVolumeMatch[1]) : totalRealVolume;
|
||
|
||
const theoryWeightMatch = theoryText.match(/Peso Total \(Kgf\)[\s\S]*?([\d.]+)/);
|
||
const theoryWeight = theoryWeightMatch ? parseFloat(theoryWeightMatch[1]) : totalRealWeight;
|
||
|
||
const consumptionVariance = ((totalRealVolume - theoryVolume) / theoryVolume * 100);
|
||
const weightVariance = totalRealWeight > 0 ? ((totalRealWeight - theoryWeight) / theoryWeight * 100) : 0;
|
||
|
||
// Montagem do resultado
|
||
results += `
|
||
<div class="summary-grid">
|
||
<div class="summary-card">
|
||
<h3>Volume Planejado</h3>
|
||
<div class="summary-value">${theoryVolume.toFixed(2)}</div>
|
||
<div class="summary-label">Litros</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Volume Real</h3>
|
||
<div class="summary-value">${totalRealVolume.toFixed(2)}</div>
|
||
<div class="summary-label">Litros</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Variância Volume</h3>
|
||
<div class="summary-value">${consumptionVariance.toFixed(1)}%</div>
|
||
<div class="summary-label">${consumptionVariance > 0 ? '⬆️ Acima' : '⬇️ Abaixo'}</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Peso Planejado</h3>
|
||
<div class="summary-value">⚖️ ${theoryWeight.toFixed(1)}</div>
|
||
<div class="summary-label">Kgf</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Peso Real</h3>
|
||
<div class="summary-value">⚖️ ${totalRealWeight.toFixed(1)}</div>
|
||
<div class="summary-label">Kgf</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Variância Peso</h3>
|
||
<div class="summary-value">${weightVariance.toFixed(1)}%</div>
|
||
<div class="summary-label">${weightVariance > 0 ? '⬆️ Acima' : '⬇️ Abaixo'}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top: 25px; background: white; padding: 20px; border-radius: 8px; border-left: 5px solid var(--color-primary);">
|
||
<h3 style="color: var(--color-primary); margin-bottom: 15px;">📈 Indicadores de Rendimento e Eficiência:</h3>
|
||
<div class="summary-grid">
|
||
<div class="summary-card">
|
||
<h3>Rendimento por Área</h3>
|
||
<div class="summary-value">${realYieldArea.toFixed(2)}</div>
|
||
<div class="summary-label">m²/L</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Rendimento por Peso</h3>
|
||
<div class="summary-value">${realYieldWeight.toFixed(3)}</div>
|
||
<div class="summary-label">Kgf/L</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>Consumo Específico</h3>
|
||
<div class="summary-value">${(totalRealVolume / totalRealWeight).toFixed(4)}</div>
|
||
<div class="summary-label">L/Kgf</div>
|
||
</div>
|
||
<div class="summary-card">
|
||
<h3>EPM Média</h3>
|
||
<div class="summary-value">${meanEPS.toFixed(0)}</div>
|
||
<div class="summary-label">micrometros (μm)</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="margin-top: 25px; background: white; padding: 20px; border-radius: 8px; border-left: 5px solid ${consumptionVariance > 15 ? 'var(--color-error)' : consumptionVariance > 5 ? 'var(--color-warning)' : 'var(--color-success)'};">
|
||
<h3 style="color: var(--color-primary); margin-bottom: 15px;">🎯 Diagnóstico de Eficiência:</h3>
|
||
<div class="alert ${consumptionVariance > 10 ? 'alert-warning' : 'alert-success'}">
|
||
<strong>Consumo vs Planejado:</strong> ${consumptionVariance > 0 ?
|
||
`Consumo ${Math.abs(consumptionVariance).toFixed(1)}% acima do planejado (${totalRealVolume.toFixed(2)}L real vs ${theoryVolume.toFixed(2)}L teórico)` :
|
||
`Consumo ${Math.abs(consumptionVariance).toFixed(1)}% abaixo do planejado (Excelente!)`
|
||
}
|
||
</div>
|
||
|
||
<div class="alert ${Math.abs(weightVariance) > 15 ? 'alert-warning' : 'alert-success'}">
|
||
<strong>⚖️ Variância de Peso:</strong> ${totalRealWeight > 0 ?
|
||
`Peso real ${Math.abs(weightVariance).toFixed(1)}% ${weightVariance > 0 ? 'acima' : 'abaixo'} do planejado (${totalRealWeight.toFixed(1)} Kgf real vs ${theoryWeight.toFixed(1)} Kgf teórico)` :
|
||
'Nenhum peso registrado'
|
||
}
|
||
</div>
|
||
|
||
${consumptionVariance > 10 ? `
|
||
<div class="alert alert-warning">
|
||
<strong>⚠️ Recomendações para Reduzir Consumo:</strong>
|
||
<ul style="margin: 10px 0; padding-left: 20px;">
|
||
<li>Revisar calibragem de pressão - reduzir para valor mínimo adequado</li>
|
||
<li>Verificar diluição das tintas - avaliar se está acima do recomendado</li>
|
||
<li>Técnica de aplicação: treinar operadores em eficiência</li>
|
||
<li>Avaliar overspray e desperdício de material na aplicação</li>
|
||
</ul>
|
||
</div>
|
||
` : ''}
|
||
|
||
${consumptionVariance < -10 ? `
|
||
<div class="alert alert-warning">
|
||
<strong>⚠️ Atenção - Consumo Abaixo do Esperado:</strong>
|
||
<ul style="margin: 10px 0; padding-left: 20px;">
|
||
<li>Verificar se espessura de película está dentro da especificação</li>
|
||
<li>Confirmar rendimento real do material (possível variação do lote)</li>
|
||
<li>Garantir que cobertura é completa e uniforme</li>
|
||
</ul>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
`;
|
||
|
||
document.getElementById('analysisResults').innerHTML = results;
|
||
}
|
||
|
||
// ========== SALVAR/EXPORTAR ==========
|
||
function savePlan() {
|
||
appData.plan = collectPlanData();
|
||
localStorage.setItem('paintingAppData', JSON.stringify(appData));
|
||
alert('✅ Planejamento salvo com sucesso!');
|
||
}
|
||
|
||
function saveControlData() {
|
||
appData.control = collectControlData();
|
||
localStorage.setItem('paintingAppData', JSON.stringify(appData));
|
||
alert('✅ Dados de controle salvos com sucesso!');
|
||
}
|
||
|
||
function collectPlanData() {
|
||
return {
|
||
projectName: document.getElementById('projectName').value,
|
||
projectClient: document.getElementById('projectClient').value,
|
||
projectStartDate: document.getElementById('projectStartDate').value,
|
||
projectEndDate: document.getElementById('projectEndDate').value,
|
||
projectTechnician: document.getElementById('projectTechnician').value,
|
||
projectEnvironment: document.getElementById('projectEnvironment').value,
|
||
geometries: Array.from(document.querySelectorAll('#geometryContainer .card')).map(card => ({
|
||
description: card.querySelector('.geom-description').value,
|
||
dimensions: card.querySelector('.geom-dimensions').value,
|
||
weight: card.querySelector('.geom-weight').value,
|
||
type: card.querySelector('.geom-type').value,
|
||
area: card.querySelector('.geom-area').value,
|
||
complexity: card.querySelector('.geom-complexity').value,
|
||
quantity: card.querySelector('.geom-quantity').value,
|
||
notes: card.querySelector('.geom-notes').value
|
||
})),
|
||
paintSchemes: Array.from(document.querySelectorAll('#paintingSchemeContainer .card')).map(card => ({
|
||
name: card.querySelector('.paint-name').value,
|
||
type: card.querySelector('.paint-type').value,
|
||
sv: card.querySelector('.paint-sv').value,
|
||
yield: card.querySelector('.paint-yield').value,
|
||
epsMin: card.querySelector('.paint-eps-min').value,
|
||
epsMax: card.querySelector('.paint-eps-max').value,
|
||
dilution: card.querySelector('.paint-dilution').value,
|
||
manufacturer: card.querySelector('.paint-manufacturer').value,
|
||
notes: card.querySelector('.paint-notes').value
|
||
}))
|
||
};
|
||
}
|
||
|
||
function collectControlData() {
|
||
return Array.from(document.querySelectorAll('#controlRecordsContainer .card')).map(card => ({
|
||
coat: card.querySelector('.ctrl-coat').value,
|
||
piece: card.querySelector('.ctrl-piece').value,
|
||
date: card.querySelector('.ctrl-date').value,
|
||
operator: card.querySelector('.ctrl-operator').value,
|
||
weightReal: card.querySelector('.ctrl-weight-real').value,
|
||
volume: card.querySelector('.ctrl-volume').value,
|
||
area: card.querySelector('.ctrl-area').value,
|
||
epu: card.querySelector('.ctrl-epu').value,
|
||
epsReal: card.querySelector('.ctrl-eps-real').value,
|
||
method: card.querySelector('.ctrl-method').value,
|
||
realYield: card.querySelector('.ctrl-real-yield').value,
|
||
notes: card.querySelector('.ctrl-notes').value
|
||
}));
|
||
}
|
||
|
||
function exportPlanPDF() {
|
||
let content = `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Plano de Pintura</title>
|
||
<style>
|
||
body { font-family: Arial; margin: 20px; line-height: 1.6; }
|
||
h1 { color: #208c80; text-align: center; }
|
||
h2 { color: #208c80; border-bottom: 2px solid #208c80; padding: 10px 0; margin-top: 20px; }
|
||
table { width: 100%; border-collapse: collapse; margin: 15px 0; }
|
||
th, td { border: 1px solid #ddd; padding: 10px; text-align: left; }
|
||
th { background: #208c80; color: white; }
|
||
.section { page-break-inside: avoid; margin: 20px 0; }
|
||
.metric { display: inline-block; width: 22%; margin: 1%; text-align: center; padding: 15px; background: #f0f8f7; border-radius: 8px; }
|
||
.value { font-size: 1.5em; font-weight: bold; color: #208c80; }
|
||
.label { font-size: 0.9em; color: #666; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
`;
|
||
|
||
// Seção de projeto
|
||
const plan = collectPlanData();
|
||
content += `
|
||
<h1>📋 Plano de Pintura Industrial</h1>
|
||
<div class="section">
|
||
<h2>Identificação do Projeto</h2>
|
||
<table>
|
||
<tr><td><strong>Projeto:</strong></td><td>${plan.projectName}</td><td><strong>Cliente:</strong></td><td>${plan.projectClient}</td></tr>
|
||
<tr><td><strong>Técnico Responsável:</strong></td><td>${plan.projectTechnician}</td><td><strong>Ambiente:</strong></td><td>${plan.projectEnvironment}</td></tr>
|
||
<tr><td><strong>Início:</strong></td><td>${plan.projectStartDate}</td><td><strong>Conclusão:</strong></td><td>${plan.projectEndDate}</td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2>📐 Peças Metálicas</h2>
|
||
<table>
|
||
<tr><th>Descrição</th><th>Dimensões</th><th>Peso Unitário (Kgf)</th><th>Área (m²)</th><th>Qtd</th><th>Peso Total (Kgf)</th><th>Complexidade</th></tr>
|
||
`;
|
||
|
||
plan.geometries.forEach(geom => {
|
||
const totalWeight = (parseFloat(geom.weight) || 0) * (parseFloat(geom.quantity) || 1);
|
||
content += `<tr>
|
||
<td>${geom.description}</td>
|
||
<td>${geom.dimensions}</td>
|
||
<td>${geom.weight}</td>
|
||
<td>${geom.area}</td>
|
||
<td>${geom.quantity}</td>
|
||
<td><strong>${totalWeight.toFixed(1)}</strong></td>
|
||
<td>${geom.complexity}</td>
|
||
</tr>`;
|
||
});
|
||
|
||
content += `
|
||
</table>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2>🎯 Esquema de Pintura</h2>
|
||
<table>
|
||
<tr><th>Demão</th><th>Tipo</th><th>SV (%)</th><th>Rendimento (m²/L)</th><th>EPS (μm)</th><th>Diluição (%)</th></tr>
|
||
`;
|
||
|
||
plan.paintSchemes.forEach((paint, idx) => {
|
||
content += `<tr>
|
||
<td>${paint.name || 'Demão ' + (idx + 1)}</td>
|
||
<td>${paint.type}</td>
|
||
<td>${paint.sv}</td>
|
||
<td>${paint.yield}</td>
|
||
<td>${paint.epsMin}/${paint.epsMax}</td>
|
||
<td>${paint.dilution}</td>
|
||
</tr>`;
|
||
});
|
||
|
||
content += `
|
||
</table>
|
||
</div>
|
||
|
||
<p style="text-align: center; color: #666; margin-top: 40px; font-size: 0.9em;">
|
||
Documento gerado pelo Gestor de Pintura Industrial - BrainSteel
|
||
</p>
|
||
</body>
|
||
</html>
|
||
`;
|
||
|
||
const blob = new Blob([content], { type: 'text/html' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `Plano_Pintura_${plan.projectName}_${new Date().toISOString().split('T')[0]}.html`;
|
||
a.click();
|
||
}
|
||
|
||
function exportControlPDF() {
|
||
const control = collectControlData();
|
||
let content = `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Fichas de Controle</title>
|
||
<style>
|
||
body { font-family: Arial; margin: 20px; line-height: 1.5; }
|
||
h1 { color: #208c80; text-align: center; }
|
||
h2 { color: #208c80; border-bottom: 2px solid #208c80; padding: 10px 0; margin-top: 25px; page-break-after: avoid; }
|
||
.record { page-break-inside: avoid; margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 8px; }
|
||
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
|
||
td { padding: 8px; border-bottom: 1px solid #eee; }
|
||
strong { color: #208c80; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>📝 Fichas de Controle de Aplicação</h1>
|
||
`;
|
||
|
||
control.forEach((record, idx) => {
|
||
content += `
|
||
<div class="record">
|
||
<h2>Registro #${idx + 1} - ${record.piece}</h2>
|
||
<table>
|
||
<tr><td><strong>Demão:</strong> ${record.coat}</td><td><strong>Data:</strong> ${record.date}</td><td><strong>Operador:</strong> ${record.operator}</td></tr>
|
||
<tr><td><strong>⚖️ Peso Real:</strong> ${record.weightReal} Kgf</td><td><strong>Volume:</strong> ${record.volume}L</td><td><strong>Área:</strong> ${record.area}m²</td></tr>
|
||
<tr><td><strong>EPU:</strong> ${record.epu}μm</td><td><strong>EPS Real:</strong> ${record.epsReal}μm</td><td><strong>Rendimento:</strong> ${record.realYield}m²/L</td></tr>
|
||
<tr><td><strong>Método:</strong> ${record.method}</td><td colspan="2"><strong>Observações:</strong> ${record.notes || 'Nenhuma'}</td></tr>
|
||
</table>
|
||
</div>
|
||
`;
|
||
});
|
||
|
||
content += `
|
||
<p style="text-align: center; color: #666; margin-top: 40px; font-size: 0.9em;">
|
||
Documento gerado pelo Gestor de Pintura Industrial - BrainSteel
|
||
</p>
|
||
</body>
|
||
</html>
|
||
`;
|
||
|
||
const blob = new Blob([content], { type: 'text/html' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `Fichas_Controle_${new Date().toISOString().split('T')[0]}.html`;
|
||
a.click();
|
||
}
|
||
|
||
function exportAnalysisPDF() {
|
||
const analysisDiv = document.getElementById('analysisResults');
|
||
if (!analysisDiv.innerHTML) {
|
||
alert('Gere a análise primeiro!');
|
||
return;
|
||
}
|
||
|
||
let content = `
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Relatório de Eficiência</title>
|
||
<style>
|
||
body { font-family: Arial; margin: 20px; line-height: 1.6; }
|
||
h1 { color: #208c80; text-align: center; }
|
||
h2, h3 { color: #208c80; }
|
||
h2 { border-bottom: 2px solid #208c80; padding: 10px 0; margin-top: 20px; }
|
||
.metric { display: inline-block; width: 22%; margin: 1%; padding: 15px; background: #f0f8f7; text-align: center; border-radius: 8px; }
|
||
.value { font-size: 1.8em; font-weight: bold; color: #208c80; }
|
||
.alert { padding: 15px; margin: 15px 0; border-left: 4px solid #f59e61; background: #fffaf0; border-radius: 4px; }
|
||
ul { margin: 10px 0; padding-left: 20px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>📊 Relatório Final de Eficiência de Pintura</h1>
|
||
<p style="text-align: center; color: #666;">Data: ${new Date().toLocaleDateString('pt-BR')}</p>
|
||
`;
|
||
|
||
content += analysisDiv.innerHTML.replace(/<div class="alert alert-info">/g, '<div class="alert">')
|
||
.replace(/class="no-print"/g, 'style="display:none"');
|
||
|
||
content += `
|
||
<p style="text-align: center; color: #666; margin-top: 40px; font-size: 0.9em;">
|
||
Documento gerado pelo Gestor de Pintura Industrial - BrainSteel
|
||
</p>
|
||
</body>
|
||
</html>
|
||
`;
|
||
|
||
const blob = new Blob([content], { type: 'text/html' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `Relatorio_Eficiencia_${new Date().toISOString().split('T')[0]}.html`;
|
||
a.click();
|
||
}
|
||
|
||
function exportAllDataJSON() {
|
||
appData.plan = collectPlanData();
|
||
appData.control = collectControlData();
|
||
|
||
const json = JSON.stringify(appData, null, 2);
|
||
const blob = new Blob([json], { type: 'application/json' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `Dados_Completos_${new Date().toISOString().split('T')[0]}.json`;
|
||
a.click();
|
||
}
|
||
|
||
function resetAll() {
|
||
if (confirm('⚠️ Tem certeza? Todos os dados serão perdidos!')) {
|
||
localStorage.removeItem('paintingAppData');
|
||
location.reload();
|
||
}
|
||
}
|
||
|
||
// ========== INICIALIZAÇÃO ==========
|
||
window.addEventListener('load', () => {
|
||
const saved = localStorage.getItem('paintingAppData');
|
||
if (saved) {
|
||
console.log('Dados restaurados do armazenamento local');
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|