Back to blocks

Otimização JS e HTML

4.0
ptDesenvolvimento WebJavaScriptHTMLCSSFlaskOtimização

Prompt

Apartir desse JS abaixo, preciso que crie um HTML com CS moderno, também preciso que otimize esse JS, para ficar mais enxuto. Não posso perder nenhum funcionalidade, só quero que ele fique enxuto e funcional. Utilizo ele com Flask em ptyhon. Então só preciso do HTML, css e esse JS otimizado.

document.addEventListener("DOMContentLoaded", () => {
    const tabela = document.querySelector("#pedidoGrid tbody");
    const botaoAdicionar = document.querySelector("#adicionarLinha");
    const boletaFinalizadaCheckbox = document.querySelector("#boleta_finalizada");

    // Modais e botões
    const botaoLupa = document.getElementById("botao-lupa");
    const modalBuscarCliente = document.getElementById("modal-buscar-cliente");
    const botaoBuscarCliente = document.getElementById("botao-buscar");
    const campoNome = document.getElementById("campo-nome");
    const campoCPF = document.getElementById("campo-cpf");
    const campoCNPJ = document.getElementById("campo-cnpj");
    const resultadoBusca = document.getElementById("resultado-busca");
    const campoCliente = document.querySelector("#campo-cliente");

    // Exemplo de clientes para busca (simulação, substitua pelos seus dados reais)
    const clientes = [
        { id: 1, nome: "Cliente A", cpf: "123.456.789-00", cnpj: "" },
        { id: 2, nome: "Cliente B", cpf: "", cnpj: "12.345.678/0001-99" },
        { id: 3, nome: "Cliente C", cpf: "234.567.890-11", cnpj: "" },
        { id: 4, nome: "Empresa D", cpf: "", cnpj: "98.765.432/0001-88" },
    ];

    // Função para abrir modal
    const abrirModal = () => {
        modalBuscarCliente.style.display = "block";
        campoNome.focus();
    };

    // Função para fechar modal
    const fecharModal = () => {
        modalBuscarCliente.style.display = "none";
    };

    // Abrir modal ao clicar na lupa
    botaoLupa.addEventListener("click", () => {
        limparCamposModal();
        abrirModal();
    });

    // Fechar modal ao clicar no botão de fechar (X)
    document
        .querySelector("#modal-buscar-cliente .close-button")
        .addEventListener("click", fecharModal);

    // Fechar modal ao pressionar a tecla ESC
    document.addEventListener("keydown", (event) => {
        if (event.key === "Escape") {
            fecharModal();
        }
    });

    // Limpar campos do modal
    function limparCamposModal() {
        campoNome.value = "";
        campoCPF.value = "";
        campoCNPJ.value = "";
        resultadoBusca.innerHTML = "";
    }

    // Máscara para CPF
    campoCPF.addEventListener("input", (event) => {
        let valor = event.target.value.replace(/\D/g, "");
        valor = valor.replace(/(\d{3})(\d)/, "$1.$2");
        valor = valor.replace(/(\d{3})(\d)/, "$1.$2");
        valor = valor.replace(/(\d{3})(\d{1,2})$/, "$1-$2");
        event.target.value = valor;
    });

    // Máscara para CNPJ
    campoCNPJ.addEventListener("input", (event) => {
        let valor = event.target.value.replace(/\D/g, "");
        valor = valor.replace(/^(\d{2})(\d)/, "$1.$2");
        valor = valor.replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3");
        valor = valor.replace(/\.(\d{3})(\d)/, ".$1/$2");
        valor = valor.replace(/(\d{4})(\d{1,2})$/, "$1-$2");
        event.target.value = valor;
    });

    let idClienteAtual = null;
    let pedidosData = {}; // Objeto para armazenar detalhes dos pedidos


    // Função para limpar a boleta (tabela)
    function limparBoleta() {
        // Seleciona a primeira linha da tabela
        const primeiraLinha = tabela.querySelector("tr");

        // Limpa o conteúdo da primeira linha em vez de remover a linha
        if (primeiraLinha) {
            // Limpa os campos específicos da linha, mantendo o combo
            const comboPedidos = primeiraLinha.querySelector(".combo-pedidos");
            if (comboPedidos) {
                comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>"; // Reseta as opções, mas deixa o combo acessível
            }

            primeiraLinha.children[1].textContent = ""; // Filial
            primeiraLinha.children[2].textContent = ""; // Valor Pedido
            primeiraLinha.children[3].textContent = ""; // Valor Frete
            primeiraLinha.children[4].textContent = ""; // Valor Desconto
            primeiraLinha.children[5].textContent = ""; // DS (Campo Editável)
            primeiraLinha.children[6].textContent = ""; // Valor Final
            primeiraLinha.children[7].textContent = ""; // Condição Pagamento
            primeiraLinha.children[8].textContent = ""; // NSU
            primeiraLinha.children[9].textContent = ""; // OBS

            // Adiciona apenas a data na última coluna
            const dataAtual = new Date();
            const dataFormatada = dataAtual.toLocaleDateString(); // Apenas a data
            primeiraLinha.children[10].textContent = dataFormatada; // Atualiza a última coluna com a data
        }

        // Remove quaisquer outras linhas que estejam na tabela
        const outrasLinhas = tabela.querySelectorAll("tr:not(:first-child)");
        outrasLinhas.forEach((linha) => linha.remove());
    }

    // Função para buscar clientes
    function buscarClientes() {
        // Converter valores dos campos para uppercase antes de enviar (Nome)
        const nome = campoNome.value.toUpperCase().trim();

        // Manter a máscara dos campos CPF e CNPJ
        const cpf = campoCPF.value.toUpperCase().trim();
        const cnpj = campoCNPJ.value.toUpperCase().trim();

        // Garantir que pelo menos um campo seja preenchido
        if (!nome && !cpf && !cnpj) {
            resultadoBusca.innerHTML =
                "<p style='color: red;'>Preencha pelo menos um dos campos para buscar.</p>";
            return;
        }

        // Indicar que está carregando
        resultadoBusca.innerHTML =
            "<p style='color: blue;'>Buscando clientes, por favor aguarde...</p>";

        // Construir a URL da API com base nos parâmetros de busca
        let url = `/buscar_clientes?`;
        if (nome) {
            url += `nome=${nome}&`;
        }
        if (cpf) {
            url += `cpf=${cpf}&`;
        }
        if (cnpj) {
            url += `cnpj=${cnpj}&`;
        }
        url = url.slice(0, -1); // Remover o último '&'

        // Fazer a chamada AJAX para a rota /buscar_clientes do Flask
        fetch(url)
            .then((response) => {
                if (!response.ok) {
                    throw new Error(`Erro na requisição: ${response.status}`);
                }
                return response.json();
            })
            .then((clientes) => {
                // Limpar o conteúdo anterior
                resultadoBusca.innerHTML = "";

                if (clientes.length > 0) {
                    clientes.forEach((cliente) => {
                        const item = document.createElement("div");
                        item.textContent = `${cliente.nome} ${cliente.cpf ? `- CPF: ${cliente.cpf}` : `- CNPJ: ${cliente.cnpj}`
                            }`;
                        item.style.cursor = "pointer";
                        item.style.padding = "8px";
                        item.style.borderBottom = "1px solid #ccc";
                        item.addEventListener("click", () => selecionarCliente(cliente));
                        resultadoBusca.appendChild(item);
                    });
                } else {
                    resultadoBusca.innerHTML =
                        "<p style='color: red;'>Nenhum cliente encontrado.</p>";
                }
            })
            .catch((error) => {
                console.error("Erro ao buscar clientes:", error);
                resultadoBusca.innerHTML =
                    "<p style='color: red;'>Erro ao consultar clientes. Tente novamente mais tarde.</p>";
            });
    }

    // Executar busca ao clicar no botão ou pressionar Enter
    botaoBuscarCliente.addEventListener("click", buscarClientes);
    [campoNome, campoCPF, campoCNPJ].forEach((campo) => {
        campo.addEventListener("keypress", (event) => {
            if (event.key === "Enter") {
                event.preventDefault(); // Evita o comportamento padrão do Enter
                buscarClientes();
            }
        });
    });

    // Função para selecionar o cliente
    function selecionarCliente(cliente) {
        const campoCliente = document.querySelector("#campo-cliente");
        campoCliente.value = `${cliente.nome} ${cliente.cpf ? `- CPF: ${cliente.cpf}` : `- CNPJ: ${cliente.cnpj}`}`;

        idClienteAtual = cliente.cliente; // Garante que está pegando o campo correto

        limparBoleta(); // Limpa a tabela antes de prosseguir
        fecharModal();
        buscarPedidosDoCliente(idClienteAtual);

        console.log("ID do cliente selecionado:", idClienteAtual); // Adicionado log para depuração
    }

    function buscarPedidosDoCliente(idCliente) {
        const comboPedidos = document.querySelector("#combo-pedidos");
        comboPedidos.innerHTML = "<option value=''>Carregando...</option>";

        const url = `/buscar_pedidos_cliente?id_cliente=${idCliente}`;

        fetch(url)
            .then((response) => {
                if (!response.ok) {
                    throw new Error(`Erro na requisição: ${response.status}`);
                }
                return response.json();
            })
            .then((data) => {
                pedidosData = {}; // Limpa os dados antigos

                comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";

                if (data.length === 0) {
                    comboPedidos.innerHTML = "<option value=''>Nenhum pedido encontrado</option>";
                    return;
                }

                // Imprime a resposta do backend no console
                console.log("Resposta do backend:", data);

                data.forEach((pedido) => {
                    pedidosData[pedido.pedido_venda] = pedido; // Armazena detalhes do pedido usando `pedido_venda` como chave

                    const option = document.createElement("option");
                    option.value = pedido.pedido_venda; // Define o valor do select
                    option.textContent = pedido.pedido_venda; // Exibe o texto do pedido
                    comboPedidos.appendChild(option);
                });
            })
            .catch((error) => {
                console.error("Erro ao buscar pedidos:", error);
                comboPedidos.innerHTML = "<option value=''>Erro ao carregar os pedidos</option>";
            });
    }

    document.querySelector("#combo-pedidos").addEventListener("change", function () {
        const pedidoSelecionado = this.value;

        // Verifica se o pedido foi selecionado
        if (!pedidoSelecionado || !pedidosData[pedidoSelecionado]) {
            return;
        }

        const pedidoDetalhes = pedidosData[pedidoSelecionado]; // Obtém os detalhes do pedido
        const linhaTabela = document.querySelector("#pedidoGrid tbody tr"); // Seleciona a linha da tabela

        // Preenche as colunas com os valores do pedido
        linhaTabela.children[1].textContent = pedidoDetalhes.filial || "N/A"; // Filial
        linhaTabela.children[2].textContent = `R$ ${pedidoDetalhes.valor_pedido.toFixed(2)}`;
        linhaTabela.children[3].textContent = `R$ ${pedidoDetalhes.frete.toFixed(2)}`;
        linhaTabela.children[4].textContent = `R$ ${pedidoDetalhes.desconto.toFixed(2)}`;
        linhaTabela.children[7].textContent = pedidoDetalhes.cond_pgto || "N/A"; // Preenche a condição de pagamento

        // Calcula o valor final
        const valorFinal = pedidoDetalhes.valor_pedido + pedidoDetalhes.frete + pedidoDetalhes.desconto;
        linhaTabela.children[6].textContent = `R$ ${valorFinal.toFixed(2)}`;

        console.log("Detalhes do pedido selecionado:", pedidoDetalhes);
    });

    // Função para formatar o valor como moeda no padrão brasileiro
    function formatarMoeda(valor) {
        valor = valor.replace(/[^\d,]/g, "");
        valor = valor.replace(",", ".");
        let numero = parseFloat(valor);
        return isNaN(numero)
            ? "0,00"
            : numero.toLocaleString("pt-BR", {
                minimumFractionDigits: 2,
                maximumFractionDigits: 2,
            });
    }

    // Função para validar entrada (aceitar apenas números e vírgula)
    function validarEntradaNumerica(event) {
        if (
            !/[0-9,]/.test(event.key) &&
            !["Backspace", "Delete", "Enter", "Tab", "."].includes(event.key)
        ) {
            event.preventDefault();
        }
    }

    // Função para limpar o combo de pedidos
    function limparPedidos() {
        const comboPedidos = document.querySelector("#combo-pedidos");
        comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
    }

    // Adiciona comportamentos aos campos numéricos
    function configurarCamposNumericos(linha) {
        const camposNumericos = [1, 2, 3, 4].map((indice) => linha.children[indice]);
        camposNumericos.forEach((campo) => {
            campo.textContent = "";
            campo.addEventListener("keydown", validarEntradaNumerica);
            campo.addEventListener("blur", () => (campo.textContent = formatarMoeda(campo.textContent)));
            campo.addEventListener("keypress", (event) => {
                if (event.key === "Enter") {
                    event.preventDefault();
                    campo.blur();
                }
            });
        });
    }

    // Função para limitar o número de caracteres
    function limitarInput(event, maxLength) {
        const target = event.target;
        if (target.textContent.length > maxLength) {
            target.textContent = target.textContent.slice(0, maxLength);
            const range = document.createRange();
            range.selectNodeContents(target);
            range.collapse(false);
            const selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
        }
    }

    // Adicionar nova linha à tabela
    botaoAdicionar.addEventListener("click", () => adicionarLinha());

    function adicionarLinha() {
        const novaLinha = document.createElement("tr");
        const index = tabela.children.length; // Gera um índice único baseado no número de linhas
        novaLinha.setAttribute("data-index", index);

        novaLinha.innerHTML = `
        <td>
            <select class="combo-pedidos" data-index="${index}">
                <option value="">Selecione o Pedido</option>
            </select>
        </td>
        <td contenteditable="false"></td>
        <td contenteditable="false"></td>
        <td contenteditable="false"></td>
        <td contenteditable="false"></td>
        <td contenteditable="true"></td>
        <td contenteditable="false"></td>
        <td contenteditable="false"></td>
        <td contenteditable="true" class="editable" data-maxlength="30"></td>
        <td contenteditable="true" class="editable" data-maxlength="300"></td>
        <td>${new Date().toLocaleDateString()}</td>`;
        tabela.appendChild(novaLinha);

        // Recupera o combo específico da linha
        const comboPedidos = novaLinha.querySelector(".combo-pedidos");

        comboPedidos.addEventListener("change", (event) => {
            const linha = comboPedidos.closest("tr"); // Encontra a linha correspondente
            preencherDadosPedidoNaLinha(event, linha); // Passa a linha para preenchimento
        });

        buscarPedidosDoClienteEspecifico(idClienteAtual, comboPedidos); // Carrega os pedidos
        atualizarVisibilidadeLixeiras();

        // Adiciona event listeners para os campos NSU e OBS da nova linha
        const nsuCell = novaLinha.querySelector('td[contenteditable="true"][data-maxlength="30"]');
        const obsCell = novaLinha.querySelector('td[contenteditable="true"][data-maxlength="300"]');

        nsuCell.addEventListener('input', limitarConteudo);
        obsCell.addEventListener('input', limitarConteudo);
    }

    function limitarConteudo(event) {
        const target = event.target;
        const maxLength = parseInt(target.dataset.maxlength, 10);

        if (isNaN(maxLength)) {
            return; // Se o atributo não estiver definido, não faz nada
        }

        if (target.textContent.length > maxLength) {
            target.textContent = target.textContent.slice(0, maxLength);

            // Move o cursor para o final do texto truncado
            const range = document.createRange();
            range.selectNodeContents(target);
            range.collapse(false);
            const selection = window.getSelection();
            selection.removeAllRanges();
            selection.addRange(range);
        }
    }

    // Adicione event listeners para os campos NSU e OBS existentes
    document.querySelectorAll('td[data-maxlength]').forEach(function (cell) {
        cell.addEventListener('input', limitarConteudo);
    });

    function buscarPedidosDoClienteEspecifico(idCliente, comboPedidos) {
        comboPedidos.innerHTML = "<option value=''>Carregando...</option>";

        const url = `/buscar_pedidos_cliente?id_cliente=${idCliente}`;

        fetch(url)
            .then((response) => {
                if (!response.ok) {
                    throw new Error(`Erro na requisição: ${response.status}`);
                }
                return response.json();
            })
            .then((data) => {
                pedidosData = {}; // Limpa os dados antigos

                comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";

                if (data.length === 0) {
                    comboPedidos.innerHTML = "<option value=''>Nenhum pedido encontrado</option>";
                    return;
                }

                data.forEach((pedido) => {
                    pedidosData[pedido.pedido_venda] = pedido; // Armazena detalhes do pedido usando `pedido_venda` como chave

                    const option = document.createElement("option");
                    option.value = pedido.pedido_venda; // Define o valor do select
                    option.textContent = pedido.pedido_venda; // Exibe o texto do pedido
                    comboPedidos.appendChild(option);
                });
            })
            .catch((error) => {
                console.error("Erro ao buscar pedidos:", error);
                comboPedidos.innerHTML = "<option value=''>Erro ao carregar os pedidos</option>";
            });
    }

    function preencherDadosPedidoNaLinha(event, linha) {
        const pedidoSelecionado = event.target.value;
        const pedidoDetalhes = pedidosData[pedidoSelecionado];

        if (!pedidoDetalhes) return;

        // Preenche os campos da linha com os valores do pedido
        linha.children[1].textContent = pedidoDetalhes.filial || "N/A"; // Filial
        linha.children[2].textContent = `R$ ${pedidoDetalhes.valor_pedido.toFixed(2)}`; // Valor Pedido
        linha.children[3].textContent = `R$ ${pedidoDetalhes.frete.toFixed(2)}`; // Valor Frete
        linha.children[4].textContent = `R$ ${pedidoDetalhes.desconto.toFixed(2)}`; // Valor Desconto
        linha.children[7].textContent = pedidoDetalhes.cond_pgto || "N/A"; // Condição Pagamento

        // Atualiza o Valor Final automaticamente
        atualizarValorFinal(linha);
    }

    function atualizarValorFinal(linha) {
        const valorPedido = parseFloat(linha.children[2].textContent.replace("R$", "").replace(",", ".")) || 0;
        const valorFrete = parseFloat(linha.children[3].textContent.replace("R$", "").replace(",", ".")) || 0;
        const valorDesconto = parseFloat(linha.children[4].textContent.replace("R$", "").replace(",", ".")) || 0;
        const ds = parseFloat(linha.children[5].textContent.replace(",", ".")) || 0;

        // Calcula o valor final
        const valorFinal = valorPedido + valorFrete - valorDesconto - ds;

        // Atualiza o campo Valor Final da linha
        linha.children[6].textContent = `R$ ${valorFinal.toFixed(2)}`;
    }

    function atualizarCalculos(linha) {
        const camposEditaveis = linha.querySelectorAll(".editable");
        const valorFinalCell = linha.children[6];

        camposEditaveis.forEach((campo, index) => {
            campo.removeEventListener("click", () => (campo.textContent = ""));
            campo.addEventListener("keydown", (event) => {
                if (event.key === "Enter") {
                    event.preventDefault();
                    const proximoCampo =
                        camposEditaveis[index + 1] || camposEditaveis[0];
                    proximoCampo.focus();
                }
            });
            campo.addEventListener("input", () => calcularValorFinal(linha, valorFinalCell));
        });
    }

    function calcularValorFinal(linha, valorFinalCell) {
        const valorPedido =
            parseFloat(linha.children[1].textContent.replace(/\./g, "").replace(",", ".")) || 0;
        const valorFrete =
            parseFloat(linha.children[2].textContent.replace(/\./g, "").replace(",", ".")) || 0;
        const valorDesconto =
            parseFloat(linha.children[3].textContent.replace(/\./g, "").replace(",", ".")) || 0;
        const ds =
            parseFloat(linha.children[4].textContent.replace(/\./g, "").replace(",", ".")) || 0;
        const valorFinal = valorPedido + valorFrete - valorDesconto - ds;
        valorFinalCell.textContent = valorFinal.toLocaleString("pt-BR", {
            minimumFractionDigits: 2,
            maximumFractionDigits: 2,
        });
    }

    function adicionarLixeira(linha) {
        const celulaLixeira = document.createElement("td");
        celulaLixeira.innerHTML = '<i class="fas fa-trash lixeira" style="cursor: pointer;"></i>';
        linha.appendChild(celulaLixeira);

        // Adiciona evento de clique na lixeira para remover a linha
        celulaLixeira.addEventListener("click", () => {
            removerLinha(linha);
        });
    }

    function removerLinha(linha) {
        tabela.removeChild(linha);
        atualizarVisibilidadeLixeiras();
    }

    function atualizarVisibilidadeLixeiras() {
        const linhas = tabela.querySelectorAll("tr"); // Seleciona todas as linhas
        const tabelaHeader = tabela.closest("table").querySelector("thead tr"); // Cabeçalho da tabela

        // Verifica ou adiciona a coluna de lixeira no cabeçalho
        let thLixeira = tabelaHeader.querySelector(".lixeira");
        if (linhas.length > 1) {
            if (!thLixeira) {
                thLixeira = document.createElement("th");
                thLixeira.classList.add("lixeira");
                thLixeira.style.width = "50px"; // Ajuste opcional
                tabelaHeader.appendChild(thLixeira);
            }

            // Adiciona lixeira a todas as linhas
            linhas.forEach((linha) => {
                let celulaLixeira = linha.querySelector("td.lixeira");
                if (!celulaLixeira) {
                    celulaLixeira = document.createElement("td");
                    celulaLixeira.classList.add("lixeira");
                    celulaLixeira.innerHTML = `<i class="fas fa-trash" style="cursor: pointer; color: red;"></i>`;

                    // Evento para remoção da linha
                    celulaLixeira.querySelector("i").addEventListener("click", () => {
                        removerLinha(linha);
                    });

                    linha.appendChild(celulaLixeira); // Adiciona a lixeira na linha
                }
            });
        } else {
            // Remove a coluna e as lixeiras, pois só há uma linha
            if (thLixeira) {
                thLixeira.remove();
            }
            linhas.forEach((linha) => {
                const celulaLixeira = linha.querySelector("td.lixeira");
                if (celulaLixeira) {
                    celulaLixeira.remove();
                }
            });
        }
    }

    tabela.addEventListener("click", (event) => {
        if (event.target.classList.contains("lixeira")) {
            const linha = event.target.closest("tr");
            linha.remove();
            atualizarVisibilidadeLixeiras();
        }
    });

    // Função para limpar o combo de pedidos
    function limparPedidos() {
        const comboPedidos = document.querySelector("#combo-pedidos");
        comboPedidos.innerHTML = "<option value=''>Selecione o Pedido</option>";
    }

    // Inicialização
    //  atualizarVisibilidadeLixeiras();

    // Evento do botão toggle "Boleta Finalizada"
    boletaFinalizadaCheckbox.addEventListener("change", function () {
        if (boletaFinalizadaCheckbox.checked) {
            console.log("Boleta Finalizada: true");
        } else {
            console.log("Boleta Finalizada: false");
        }
    });

    // Inicializa o Listener para o combo de pedidos, após a criação da linha
    const comboPedidosInicial = document.querySelector("#combo-pedidos");
    if (comboPedidosInicial) {
        buscarPedidosDoClienteEspecifico(idClienteAtual, comboPedidosInicial);
        comboPedidosInicial.addEventListener("change", preencherDadosPedidoNaLinha);
    }

    document.getElementById("limparBoleta").addEventListener("click", function (event) {
        event.preventDefault(); // Evita que a página seja atualizada imediatamente

        if (confirm("Tem certeza que deseja limpar todas as informações da boleta?")) {
            location.reload(); // Limpa a boleta
        }
    });
});

document.addEventListener("DOMContentLoaded", () => {
    const tabela = document.querySelector("#pedidoGrid tbody");
    // const botaoAdicionar = document.querySelector("#adicionarLinha");

    // Adiciona os eventos necessários à tabela
    tabela.addEventListener("input", (event) => {
        const target = event.target;

        // Se a célula editada for a coluna "DS (R$)"
        if (target && target.cellIndex === 5) { // Índice 4 corresponde ao "DS (R$)"
            formatarComoMoeda(target); // Formata como moeda
            recalcularLinha(target.closest("tr")); // Recalcula o valor final da linha
        }
    });

    // Função para formatar uma célula como moeda
    function formatarComoMoeda(celula) {
        celula.textContent = celula.textContent.replace(/[^\d,.\-]/g, ''); // Remove caracteres não numéricos
    }

    // Função para recalcular o valor final da linha
    function recalcularLinha(linha) {
        const valorPedido = parseFloat(obterNumeroDaCelula(linha.cells[2])); // Valor Pedido (R$)
        const valorFrete = parseFloat(obterNumeroDaCelula(linha.cells[3])); // Valor Frete (R$)
        const valorDesconto = parseFloat(obterNumeroDaCelula(linha.cells[4])); // Valor Desconto (R$)
        const valorDS = parseFloat(obterNumeroDaCelula(linha.cells[5])); // DS (R$)

        // Calcula o valor final
        const valorFinal = valorPedido + valorFrete - valorDesconto - valorDS;

        // Atualiza a coluna "Valor Final (R$)"
        linha.cells[6].textContent = valorFinal.toLocaleString("pt-BR", {
            style: "currency",
            currency: "BRL",
        });
    }

    // Função para obter o número de uma célula (removendo formatação)
    function obterNumeroDaCelula(celula) {
        if (!celula) return 0;
        const valor = celula.textContent.replace(/[^\d,.-]/g, "").replace(",", ".");
        return parseFloat(valor) || 0;
    }

});

Resultado Gerado

import React, { useState, useEffect } from 'react';

const App = () => {
  const [clientes, setClientes] = useState([]);
  const [pedidos, setPedidos] = useState({});
  const [selectedCliente, setSelectedCliente] = useState(null);
  const [modalOpen, setModalOpen] = useState(false);
  const [searchResults, setSearchResults] = useState([]);
  const [nome, setNome] = useState('');
  const [cpf, setCpf] = useState('');
  const [cnpj, setCnpj] = useState('');

  const abrirModal = () => setModalOpen(true);
  const fecharModal = () => setModalOpen(false);

  const buscarClientes = async () => {
    const url = `/buscar_clientes?nome=${nome}&cpf=${cpf}&cnpj=${cnpj}`;
    const response = await fetch(url);
    const data = await response.json();
    setSearchResults(data);
  };

  const selecionarCliente = (cliente) => {
    setSelectedCliente(cliente);
    fecharModal();
    buscarPedidosDoCliente(cliente.id);
  };

  const buscarPedidosDoCliente = async (idCliente) => {
    const url = `/buscar_pedidos_cliente?id_cliente=${idCliente}`;
    const response = await fetch(url);
    const data = await response.json();
    setPedidos(data);
  };

  return (
    <div className="App">
      <button onClick={abrirModal}>Buscar Cliente</button>
      {modalOpen && (
        <div className="modal">
          <input type="text" value={nome} onChange={(e) => setNome(e.target.value)} placeholder="Nome" />
          <input type="text" value={cpf} onChange={(e) => setCpf(e.target.value)} placeholder="CPF" />
          <input type="text" value={cnpj} onChange={(e) => setCnpj(e.target.value)} placeholder="CNPJ" />
          <button onClick={buscarClientes}>Buscar</button>
          <div>
            {searchResults.map((cliente) => (
              <div key={cliente.id} onClick={() => selecionarCliente(cliente)}>
                {cliente.nome} {cliente.cpf ? `- CPF: ${cliente.cpf}` : `- CNPJ: ${cliente.cnpj}`}
              </div>
            ))}
          </div>
          <button onClick={fecharModal}>Fechar</button>
        </div>
      )}
      {selectedCliente && (
        <div>
          <h2>{selectedCliente.nome}</h2>
          <select>
            {Object.keys(pedidos).map((pedido) => (
              <option key={pedido} value={pedido}>
                {pedido}
              </option>
            ))}
          </select>
        </div>
      )}
    </div>
  );
};

export default App;

Mais Recomendações

Ver Todos

Criar Site Loja Roupas

Desenvolvimento Webpt
4.0

Desejo criar um site para uma loja de roupas feminias que seja extremamento persoasivo e com todos os recursos para ser encontrado nas buscas do google e instagram, facebook

loja de roupasSEOredes sociais18/06/2025

Criar Web App RPG Inspirado em Diablo II

Desenvolvimento Webpt
4.0

Crie um web app com visual inspirado em jogos RPG estilo Diablo II. No centro da tela, exiba um personagem animado em pixel art usando esta spritesheet vertical: https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/2ab05d2c-376c-4f03-b12a-f85300e15690/dfouvz7-e626a8a6-df28-4053-ad42-989874e2214c.png/v1/fill/w_603%2Ch_1324%2Cq_70%2Cstrp/diablo__isekai_maou__sprite_sheet_v2_by_quinmf_dfouvz7-pre.jpg A spritesheet possui 8 frames verticais, com largura de 603px e altura total de 1324px. O personagem deve estar animado em loop, usando CSS keyframes para alterar a posição do background verticalmente. A imagem deve ser carregada como background-image de um div com tamanho 603x166 px. Use Tailwind CSS ou CSS puro com steps(8) para simular a animação. O fundo da página deve ter uma estética medieval dark (ex: textura de pedra, tons escuros). Adicione no topo da tela uma HUD com barra de vida (vermelha) e mana (azul), estilizadas como em jogos clássicos. Tudo deve rodar no navegador, sem dependência de APIs externas.

Web AppRPGCSS04/04/2025

Criar Página de Registro React

Desenvolvimento Webpt
4.0

crie uma pagina de registro em react

ReactPágina de RegistroDesenvolvimento Web02/04/2025

Catálogo de Produtos React

Desenvolvimento Webpt
4.0

quero alteração desse meu catalogo seja feita por cada produto, quando estou clicando em uma cor ele clica também para o proximo produto. E sem contar que quero alguns exemplos de cores para serem selecionados e que apareça o nome da cor: import React, { useState, useEffect } from 'react'; import './App.css'; const App = () => { const [products, setProducts] = useState([]); const [selectedColor, setSelectedColor] = useState(''); const [selectedSize, setSelectedSize] = useState(''); const [price, setPrice] = useState(0); const [stock, setStock] = useState(0); useEffect(() => { // Simulando a busca de produtos do backend const fetchedProducts = [ { id: 1, name: 'Camiseta Básica', image: 'https://placehold.co/300X300', colors: ['Branco', 'Preto', 'Azul'], sizes: ['P', 'M', 'G'], prices: [29.99, 29.99, 34.99], stock: [10, 15, 8] }, { id: 2, name: 'Calça Jeans', image: 'https://placehold.co/300X300', colors: ['Azul', 'Preto'], sizes: ['38', '40', '42'], prices: [89.99, 99.99], stock: [5, 7] } ]; setProducts(fetchedProducts); if (fetchedProducts.length > 0) { setSelectedColor(fetchedProducts[0].colors[0]); setSelectedSize(fetchedProducts[0].sizes[0]); setPrice(fetchedProducts[0].prices[0]); setStock(fetchedProducts[0].stock[0]); } }, []); const handleColorChange = (productIndex, colorIndex) => { setSelectedColor(products[productIndex].colors[colorIndex]); setPrice(products[productIndex].prices[colorIndex]); setStock(products[productIndex].stock[colorIndex]); }; const handleSizeChange = (productIndex, sizeIndex) => { setSelectedSize(products[productIndex].sizes[sizeIndex]); }; return ( <div className="App min-h-screen bg-gray-100 py-8"> <div className="container mx-auto px-4"> <h1 className="text-4xl font-bold text-center mb-8">Catálogo de Vestuário</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> {products.map((product, productIndex) => ( <div key={product.id} className="bg-white rounded-lg shadow-md p-6"> <img src={product.image} alt={product.name} className="w-full h-64 object-cover rounded-lg mb-4" /> <h2 className="text-xl font-semibold mb-2">{product.name}</h2> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Cor:</label> <div className="flex space-x-2 mt-1"> {product.colors.map((color, colorIndex) => ( <button key={colorIndex} onClick={() => handleColorChange(productIndex, colorIndex)} className={`w-8 h-8 rounded-full border-2 ${selectedColor === color ? 'border-blue-500' : 'border-gray-300'} focus:outline-none`} style={{ backgroundColor: color.toLowerCase() }} ></button> ))} </div> </div> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Tamanho:</label> <div className="flex space-x-2 mt-1"> {product.sizes.map((size, sizeIndex) => ( <button key={sizeIndex} onClick={() => handleSizeChange(productIndex, sizeIndex)} className={`px-4 py-2 rounded-md ${selectedSize === size ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-700'} focus:outline-none`} > {size} </button> ))} </div> </div> <div className="text-lg font-semibold mb-2">Preço: R$ {price.toFixed(2)}</div> <div className="text-sm text-gray-600">Estoque: {stock} unidades</div> </div> ))} </div> <div className="mt-8 text-center text-sm text-gray-500"> &copy; 2025 Todos os direitos reservados. </div> </div> </div> ); }; export default App;

ReactCatálogoProdutos27/03/2025

Catálogo de Produtos React

Desenvolvimento Webpt
4.0

quero alteração desse meu catalogo seja feita por cada produto, quando estou clicando em uma cor ele clica também para o proximo produto. E sem contar que quero alguns exemplos de cores para serem selecionados e que apareça o nome da cor: import React, { useState, useEffect } from 'react'; import './App.css'; const App = () => { const [products, setProducts] = useState([]); const [selectedColor, setSelectedColor] = useState(''); const [selectedSize, setSelectedSize] = useState(''); const [price, setPrice] = useState(0); const [stock, setStock] = useState(0); useEffect(() => { // Simulando a busca de produtos do backend const fetchedProducts = [ { id: 1, name: 'Camiseta Básica', image: 'https://placehold.co/300X300', colors: ['Branco', 'Preto', 'Azul'], sizes: ['P', 'M', 'G'], prices: [29.99, 29.99, 34.99], stock: [10, 15, 8] }, { id: 2, name: 'Calça Jeans', image: 'https://placehold.co/300X300', colors: ['Azul', 'Preto'], sizes: ['38', '40', '42'], prices: [89.99, 99.99], stock: [5, 7] } ]; setProducts(fetchedProducts); if (fetchedProducts.length > 0) { setSelectedColor(fetchedProducts[0].colors[0]); setSelectedSize(fetchedProducts[0].sizes[0]); setPrice(fetchedProducts[0].prices[0]); setStock(fetchedProducts[0].stock[0]); } }, []); const handleColorChange = (productIndex, colorIndex) => { setSelectedColor(products[productIndex].colors[colorIndex]); setPrice(products[productIndex].prices[colorIndex]); setStock(products[productIndex].stock[colorIndex]); }; const handleSizeChange = (productIndex, sizeIndex) => { setSelectedSize(products[productIndex].sizes[sizeIndex]); }; return ( <div className="App min-h-screen bg-gray-100 py-8"> <div className="container mx-auto px-4"> <h1 className="text-4xl font-bold text-center mb-8">Catálogo de Vestuário</h1> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> {products.map((product, productIndex) => ( <div key={product.id} className="bg-white rounded-lg shadow-md p-6"> <img src={product.image} alt={product.name} className="w-full h-64 object-cover rounded-lg mb-4" /> <h2 className="text-xl font-semibold mb-2">{product.name}</h2> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Cor:</label> <div className="flex space-x-2 mt-1"> {product.colors.map((color, colorIndex) => ( <button key={colorIndex} onClick={() => handleColorChange(productIndex, colorIndex)} className={`w-8 h-8 rounded-full border-2 ${selectedColor === color ? 'border-blue-500' : 'border-gray-300'} focus:outline-none`} style={{ backgroundColor: color.toLowerCase() }} ></button> ))} </div> </div> <div className="mb-4"> <label className="block text-sm font-medium text-gray-700">Tamanho:</label> <div className="flex space-x-2 mt-1"> {product.sizes.map((size, sizeIndex) => ( <button key={sizeIndex} onClick={() => handleSizeChange(productIndex, sizeIndex)} className={`px-4 py-2 rounded-md ${selectedSize === size ? 'bg-blue-500 text-white' : 'bg-gray-200 text-gray-700'} focus:outline-none`} > {size} </button> ))} </div> </div> <div className="text-lg font-semibold mb-2">Preço: R$ {price.toFixed(2)}</div> <div className="text-sm text-gray-600">Estoque: {stock} unidades</div> </div> ))} </div> <div className="mt-8 text-center text-sm text-gray-500"> &copy; 2025 Todos os direitos reservados. </div> </div> </div> ); }; export default App;

ReactCatálogoProdutos27/03/2025

Catálogo de Roupas em Flask

Desenvolvimento Webpt
4.0

Quero um aplicativo no modelo de catalogo para o ramo de vestuário e confecção, com a possibilidade de escolhe cor e tamnho para cada produto, e traga o preço e o estoque ao selecionar cada uma delas. Ele precisa estar 100% em português. Vou utilizar o Flask do Python com backend, então tente utilizar mais CSS e html. Preciso que adicione foto nesse catalogo e que traga já uma cor e um tamanho preenchido, os primeiros da lista

FlaskCatálogo de RoupasHTML/CSS27/03/2025