Estoque Pro - Exportação Completa

by thvinic

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>

<div class="container" id="areaCaptura">
    <h2>📦 Controle de Materiais</h2>
    
    <div id="alerta" class="aviso-falta"></div>

    <div class="input-group">
        <input type="text" id="itemInput" placeholder="Material...">
        <input type="number" id="qtdInput" value="1">
        <button class="btn-add" onclick="addItem()">ADD</button>
    </div>

    <div class="export-group">
        <button class="btn-pdf" onclick="exportarPDF()">📄 PDF COLORIDO</button>
        <button class="btn-img" onclick="exportarImagem()">🖼️ SALVAR IMAGEM</button>
    </div>

    <ul id="listaEstoque"></ul>
</div>

CSS

:root {
            --primary: #2c3e50;
            --success: #27ae60;
            --danger: #e74c3c;
            --warning: #f39c12;
            --info: #3498db;
        }

        body { font-family: 'Segoe UI', sans-serif; background-color: #f0f2f5; padding: 15px; }
        .container { max-width: 700px; margin: auto; background: white; padding: 25px; border-radius: 12px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
        
        h2 { text-align: center; color: var(--primary); }

        .input-group { display: flex; gap: 8px; margin-bottom: 20px; }
        input[type="text"], input[type="number"] { padding: 12px; border: 2px solid #ddd; border-radius: 8px; outline: none; }
        input[type="text"] { flex: 2; }
        input[type="number"] { width: 80px; }
        
        button { padding: 12px; border: none; border-radius: 8px; cursor: pointer; font-weight: bold; color: white; transition: 0.2s; }
        .btn-add { background-color: var(--success); }
        
        .export-group { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px; }
        .btn-pdf { background-color: var(--primary); }
        .btn-img { background-color: var(--info); }
        
        .btn-remove { background-color: #eee; color: #666; padding: 5px 10px; font-size: 12px; }

        .aviso-falta { 
            background-color: #fff3cd; color: #856404; padding: 10px; 
            border-radius: 8px; margin-bottom: 15px; border-left: 5px solid var(--warning);
            display: none;
        }

        ul { list-style: none; padding: 0; margin: 0; background: white; border-radius: 8px; }
        li { 
            display: flex; align-items: center; justify-content: space-between; 
            padding: 12px; border-bottom: 1px solid #eee; 
        }

        .item-missing { background-color: #fff5f5; }
        .item-info { display: flex; align-items: center; gap: 10px; flex: 1; }
        
        .qtd-edit { 
      ...

JavaScript

let estoque = JSON.parse(localStorage.getItem('dadosEstoqueV5')) || [];

    function salvar() {
        localStorage.setItem('dadosEstoqueV5', JSON.stringify(estoque));
        renderizar();
    }

    function addItem() {
        const nome = document.getElementById('itemInput').value.trim();
        const qtd = document.getElementById('qtdInput').value;
        if (!nome) return;
        estoque.push({ id: Date.now(), nome, qtd: parseInt(qtd), tem: true });
        document.getElementById('itemInput').value = "";
        salvar();
    }

    function toggleStatus(id) {
        estoque = estoque.map(item => {
            if (item.id === id) {
                item.tem = !item.tem;
                if (!item.tem) item.qtd = 0;
            }
            return item;
        });
        salvar();
    }

    function editarQtd(id, novaQtd) {
        estoque = estoque.map(item => {
            if (item.id === id) {
                item.qtd = parseInt(novaQtd) || 0;
                item.tem = item.qtd > 0;
            }
            return item;
        });
        salvar();
    }

    function removeItem(id) {
        estoque = estoque.filter(item => item.id !== id);
        salvar();
    }

    function renderizar() {
        const lista = document.getElementById('listaEstoque');
        const alerta = document.getElementById('alerta');
        lista.innerHTML = "";
        let faltantes = 0;

        estoque.forEach(item => {
            if (!item.tem) faltantes++;
            const li = document.createElement('li');
            if (!item.tem) li.className = 'item-missing';
            
            li.innerHTML = `
                <div class="item-info">
                    <input type="checkbox" ${item.tem ? 'checked' : ''} onchange="toggleStatus(${item.id})">
                    <input type="number" class="qtd-edit" value="${item.qtd}" onchange="editarQtd(${item.id}, this.value)">
                    <span...