top of page

Guia Prático: Criando uma Tela de Consulta de Clientes com PO UI no VSCode


Este guia detalha o processo de criação de uma tela de consulta de clientes utilizando o framework PO UI da TOTVS em um projeto Angular, desenvolvido no Visual Studio Code. A tela permitirá a busca de clientes por código, nome, CPF ou CNPJ, simulando a consulta de dados da tabela SA1 do Protheus.

Pré-requisitos

Antes de começar, certifique-se de que você tem o Node.js e o Angular CLI instalados em sua máquina. Se não tiver, siga as instruções abaixo:

  • Node.js (inclui npm): Baixe e instale a versão LTS do Node.js .

  • Angular CLI: Após instalar o Node.js, abra o terminal ou prompt de comando e instale o Angular CLI globalmente com o comando:

    bash

    npm install -g @angular/cli

Passo 1: Criando um Novo Projeto Angular

  1. Abra o terminal ou prompt de comando.

  2. Navegue até o diretório onde você deseja criar seu projeto.

  3. Execute o seguinte comando para criar um novo projeto Angular (substitua consulta-clientes-po-ui pelo nome que desejar para o seu projeto):

    bash

    ng new consulta-clientes-po-ui --routing --style=scss

    • --routing: Adiciona o módulo de roteamento ao projeto.

    • --style=scss: Define SCSS como o pré-processador de estilo (você pode escolher CSS se preferir).

  4. Quando perguntado se deseja habilitar o Server-Side Rendering (SSR) e Static Site Generation (SSG/Prerendering), você pode responder "N" (Não) para este exemplo simples.

  5. Acesse o diretório do projeto recém-criado:

    bash

    cd consulta-clientes-po-ui

Passo 2: Adicionando o PO UI ao Projeto

Com o projeto Angular criado, o próximo passo é adicionar a biblioteca do PO UI.

  1. No terminal, dentro do diretório do seu projeto, execute o comando:

    bash

    ng add @po-ui/ng-components

  2. O Angular CLI perguntará se deseja prosseguir com a instalação. Digite Y e pressione Enter.

  3. Em seguida, será perguntado se você deseja configurar um tema padrão. Você pode escolher o tema padrão ou outro de sua preferência. Para este guia, vamos manter o padrão.

  4. Aguarde a instalação e configuração automática dos pacotes e módulos necessários.

Passo 3: Configurando o Módulo Principal (AppModule)

O PO UI requer que alguns de seus módulos sejam importados no módulo principal da sua aplicação (app.module.ts).

  1. Abra o projeto no VSCode.

  2. Navegue até o arquivo src/app/app.module.ts.

  3. Importe o PoModule e o PoTemplatesModule (se for utilizar templates prontos do PO UI, o que não será o foco principal deste guia, mas é uma boa prática incluir) e adicione-os à seção imports do @NgModule:

    typescript

    import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; // Importante para animações do PO UI import { HttpClientModule } from '@angular/common/http'; // Necessário para alguns componentes PO UI e serviços import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { PoModule } from '@po-ui/ng-components'; // import { PoTemplatesModule } from '@po-ui/ng-templates'; // Opcional para este guia @NgModule({   declarations: [     AppComponent   ],   imports: [     BrowserModule,     BrowserAnimationsModule, // Adicionado     AppRoutingModule,     HttpClientModule, // Adicionado     PoModule     // PoTemplatesModule // Opcional   ],   providers: [],   bootstrap: [AppComponent] }) export class AppModule { }

    Observação: O BrowserAnimationsModule é crucial para o funcionamento correto de muitos componentes do PO UI que utilizam animações. O HttpClientModule é frequentemente necessário para carregar dados ou para o funcionamento de componentes como o PoLookup.

Passo 4: Criando o Componente da Tela de Consulta de Clientes

Vamos criar um novo componente que representará nossa tela de consulta.

  1. No terminal, dentro do diretório do projeto, execute o comando:

    bash

    ng generate component consulta-clientes

    Isso criará uma nova pasta consulta-clientes dentro de src/app com os arquivos do componente (.html, .scss, .ts e .spec.ts).

Passo 5: Configurando Rotas (Opcional, mas recomendado)

Para acessar nosso novo componente através de uma URL, vamos configurar uma rota simples.

  1. Abra o arquivo src/app/app-routing.module.ts.

  2. Importe o ConsultaClientesComponent e adicione uma rota para ele:

    typescript

    import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ConsultaClientesComponent } from './consulta-clientes/consulta-clientes.component'; // Importe o componente const routes: Routes = [   { path: 'consulta-clientes', component: ConsultaClientesComponent }, // Adicione a rota   { path: '', redirectTo: '/consulta-clientes', pathMatch: 'full' } // Rota padrão (opcional) ]; @NgModule({   imports: [RouterModule.forRoot(routes)],   exports: [RouterModule] }) export class AppRoutingModule { }

Passo 6: Implementando o Template da Tela de Consulta (HTML)

Agora vamos construir a interface da nossa tela de consulta no arquivo src/app/consulta-clientes/consulta-clientes.component.html.

Utilizaremos os seguintes componentes do PO UI:

  • po-page-default: Para a estrutura básica da página.

  • po-divider: Para separar seções.

  • po-input: Para os campos de filtro (Código, Nome, CPF/CNPJ).

  • po-button: Para o botão de busca.

  • po-table: Para exibir os resultados da consulta.

html

<po-page-default p-title="Consulta de Clientes (SA1 - Protheus)">

  <div class="po-row">
    <po-input class="po-md-3" name="codigoCliente" [(ngModel)]="filtroCodigo" p-label="Código Cliente"></po-input>
    <po-input class="po-md-6" name="nomeCliente" [(ngModel)]="filtroNome" p-label="Nome/Razão Social"></po-input>
    <po-input class="po-md-3" name="cpfCnpjCliente" [(ngModel)]="filtroCpfCnpj" p-label="CPF/CNPJ"></po-input>
  </div>

  <div class="po-row po-mt-2">
    <div class="po-offset-md-9 po-md-3">
      <po-button p-label="Buscar Clientes" (p-click)="buscarClientes()" p-type="primary" class="po-mb-2"></po-button>
      <po-button p-label="Limpar Filtros" (p-click)="limparFiltros()" p-type="default"></po-button>
    </div>
  </div>

  <po-divider p-label="Resultados da Consulta"></po-divider>

  <po-table
    [p-columns]="colunasTabela"
    [p-items]="clientesExibidos"
    [p-loading]="carregandoTabela"
    [p-height]="400"
    p-striped="true"
    p-sort="true"
    p-selectable="true"
    (p-selected)="itemSelecionado($event)"
    (p-unselected)="itemDeselecionado($event)">
  </po-table>

  <div *ngIf="clienteDetalhe" class="po-mt-2">
    <po-divider p-label="Detalhes do Cliente Selecionado"></po-divider>
    <p><strong>Código:</strong> {{ clienteDetalhe.codigo }}</p>
    <p><strong>Nome:</strong> {{ clienteDetalhe.nome }}</p>
    <p><strong>CPF/CNPJ:</strong> {{ clienteDetalhe.cpfCnpj }}</p>
    <p><strong>Endereço:</strong> {{ clienteDetalhe.endereco }}</p>
    <p><strong>Telefone:</strong> {{ clienteDetalhe.telefone }}</p>
  </div>

</po-page-default>

Passo 7: Implementando a Lógica do Componente (TypeScript)

Agora, vamos adicionar a lógica ao nosso componente no arquivo src/app/consulta-clientes/consulta-clientes.component.ts.

typescript

import { Component, OnInit, ViewChild } from '@angular/core';
import { PoTableColumn, PoTableAction, PoNotificationService, PoModalComponent } from '@po-ui/ng-components';

// Interface para representar um cliente (simulando a SA1)
interface Cliente {
  id: number;
  codigo: string;
  nome: string;
  cpfCnpj: string;
  endereco: string;
  cidade: string;
  estado: string;
  telefone: string;
  email: string;
  status: string; // Ativo, Inativo, Bloqueado
}

@Component({
  selector: 'app-consulta-clientes',
  templateUrl: './consulta-clientes.component.html',
  styleUrls: ['./consulta-clientes.component.scss']
})
export class ConsultaClientesComponent implements OnInit {

  // Filtros
  filtroCodigo: string = '';
  filtroNome: string = '';
  filtroCpfCnpj: string = '';

  // Tabela
  colunasTabela: Array<PoTableColumn> = [];
  clientesExibidos: Array<Cliente> = [];
  carregandoTabela: boolean = false;

  // Mock de dados (simulando dados do Protheus - SA1)
  private todosClientes: Array<Cliente> = [
    { id: 1, codigo: '000001', nome: 'EMPRESA MODELO LTDA', cpfCnpj: '11.222.333/0001-44', endereco: 'RUA DAS PALMEIRAS, 123', cidade: 'SAO PAULO', estado: 'SP', telefone: '(11) 99999-1234', email: 'contato@empresamodelo.com.br', status: 'Ativo' },
    { id: 2, codigo: '000002', nome: 'JOAO DA SILVA SAURO', cpfCnpj: '123.456.789-00', endereco: 'AV. PRINCIPAL, 456', cidade: 'RIO DE JANEIRO', estado: 'RJ', telefone: '(21) 98888-5678', email: 'joao.sauro@email.com', status: 'Ativo' },
    { id: 3, codigo: '000003', nome: 'MARIA PEREIRA INDÚSTRIA', cpfCnpj: '44.555.666/0001-77', endereco: 'ALAMEDA DOS ANJOS, 789', cidade: 'BELO HORIZONTE', estado: 'MG', telefone: '(31) 97777-9012', email: 'financeiro@mariapereira.ind.br', status: 'Inativo' },
    { id: 4, codigo: '000004', nome: 'PEDRO ALBUQUERQUE ME', cpfCnpj: '987.654.321-11', endereco: 'TRAVESSA SECUNDARIA, 101', cidade: 'CURITIBA', estado: 'PR', telefone: '(41) 96666-3456', email: 'pedro.albuquerque@teste.com', status: 'Bloqueado' },
    { id: 5, codigo: '000005', nome: 'CONSULTORIA XYZ LTDA', cpfCnpj: '88.777.999/0001-00', endereco: 'RUA TERCIARIA, 202', cidade: 'PORTO ALEGRE', estado: 'RS', telefone: '(51) 95555-7890', email: 'comercial@consultoriaxyz.com.br', status: 'Ativo' }
  ];

  clienteDetalhe: Cliente | undefined;

  constructor(private poNotification: PoNotificationService) { }

  ngOnInit(): void {
    this.definirColunas();
    this.buscarClientes(); // Carrega todos inicialmente
  }

  definirColunas(): void {
    this.colunasTabela = [
      { property: 'codigo', label: 'Código', width: '10%' },
      { property: 'nome', label: 'Nome/Razão Social', width: '30%' },
      { property: 'cpfCnpj', label: 'CPF/CNPJ', width: '15%' },
      { property: 'cidade', label: 'Cidade', width: '15%' },
      { property: 'estado', label: 'UF', width: '5%' },
      { property: 'telefone', label: 'Telefone', width: '15%' },
      {
        property: 'status',
        label: 'Status',
        type: 'label',
        width: '10%',
        labels: [
          { value: 'Ativo', color: 'color-11', label: 'Ativo' },
          { value: 'Inativo', color: 'color-07', label: 'Inativo' },
          { value: 'Bloqueado', color: 'color-08', label: 'Bloqueado' }
        ]
      }
    ];
  }

  buscarClientes(): void {
    this.carregandoTabela = true;
    this.clienteDetalhe = undefined; // Limpa detalhes ao buscar

    // Simulação de uma chamada a um serviço de backend
    setTimeout(() => {
      let resultadoFiltrado = [...this.todosClientes];

      if (this.filtroCodigo) {
        resultadoFiltrado = resultadoFiltrado.filter(cliente =>
          cliente.codigo.toLowerCase().includes(this.filtroCodigo.toLowerCase())
        );
      }
      if (this.filtroNome) {
        resultadoFiltrado = resultadoFiltrado.filter(cliente =>
          cliente.nome.toLowerCase().includes(this.filtroNome.toLowerCase())
        );
      }
      if (this.filtroCpfCnpj) {
        resultadoFiltrado = resultadoFiltrado.filter(cliente =>
          cliente.cpfCnpj.replace(/\.|\/|-/g, '').includes(this.filtroCpfCnpj.replace(/\.|\/|-/g, ''))
        );
      }

      this.clientesExibidos = resultadoFiltrado;
      this.carregandoTabela = false;

      if (this.clientesExibidos.length === 0) {
        this.poNotification.warning('Nenhum cliente encontrado com os filtros informados.');
      }
    }, 1000); // Simula delay da API
  }

  limparFiltros(): void {
    this.filtroCodigo = '';
    this.filtroNome = '';
    this.filtroCpfCnpj = '';
    this.clienteDetalhe = undefined;
    this.buscarClientes(); // Recarrega todos os clientes
    this.poNotification.information('Filtros limpos.');
  }

  itemSelecionado(cliente: Cliente): void {
    if (cliente) {
      this.clienteDetalhe = cliente;
      // console.log('Cliente selecionado:', cliente);
      // this.poNotification.success(`Cliente selecionado: ${cliente.nome}`);
    }
  }

  itemDeselecionado(cliente?: Cliente): void {
    this.clienteDetalhe = undefined;
    // console.log('Cliente deselecionado:', cliente);
  }

}

Explicação do Código TypeScript:

  • Interface Cliente: Define a estrutura dos dados de um cliente, simulando os campos que poderiam vir da tabela SA1 do Protheus.

  • Filtros (filtroCodigo, filtroNome, filtroCpfCnpj): Variáveis que armazenam os valores digitados nos campos de input, ligadas através do [(ngModel)] no HTML.

  • Tabela (colunasTabela, clientesExibidos, carregandoTabela):

    • colunasTabela: Array do tipo PoTableColumn que define as colunas a serem exibidas na tabela (propriedade, título, largura, tipo, etc.).

    • clientesExibidos: Array que armazena os clientes que serão efetivamente mostrados na tabela após a aplicação dos filtros.

    • carregandoTabela: Booleano para controlar o estado de carregamento da tabela (útil para exibir um indicador de loading).

  • todosClientes: Um array privado que serve como nosso mock de dados. Em uma aplicação real, esses dados viriam de um serviço que se conecta ao backend e, consequentemente, ao Protheus.

  • clienteDetalhe: Armazena o cliente selecionado na tabela para exibir seus detalhes.

  • constructor(private poNotification: PoNotificationService): Injeta o serviço de notificação do PO UI para exibir mensagens ao usuário.

  • ngOnInit(): Método do ciclo de vida do Angular, chamado quando o componente é inicializado. Aqui, chamamos definirColunas() para configurar a estrutura da tabela e buscarClientes() para carregar os dados iniciais.

  • definirColunas(): Configura as colunas da po-table, especificando a propriedade do objeto Cliente que será exibida, o rótulo da coluna, a largura e, para a coluna 'Status', como ela deve ser renderizada (usando o tipo label do PO UI para mostrar cores diferentes conforme o valor).

  • buscarClientes():

    • Simula uma chamada assíncrona a um serviço (usando setTimeout).

    • Cria uma cópia do array todosClientes para não modificar o array original.

    • Aplica os filtros de código, nome e CPF/CNPJ. Note que para CPF/CNPJ, removemos caracteres especiais antes de comparar para tornar a busca mais flexível.

    • Atualiza clientesExibidos com os resultados filtrados.

    • Controla a variável carregandoTabela.

    • Exibe uma notificação se nenhum cliente for encontrado.

  • limparFiltros(): Reseta os campos de filtro e recarrega todos os clientes.

  • itemSelecionado(cliente: Cliente) e itemDeselecionado(cliente?: Cliente): Funções chamadas quando um item é selecionado ou deselecionado na tabela, respectivamente. A função itemSelecionado atualiza clienteDetalhe para mostrar mais informações do cliente abaixo da tabela.

Passo 8: Adicionando o Componente ao app.component.html (se não usar rotas)

Se você optou por não configurar rotas no Passo 5, ou se deseja que a tela de consulta seja a página principal, você precisará adicionar o seletor do componente ConsultaClientesComponent ao arquivo src/app/app.component.html.

Substitua o conteúdo de src/app/app.component.html por:

html

<app-consulta-clientes></app-consulta-clientes>
<!-- Ou, se estiver usando rotas, mantenha apenas <router-outlet></router-outlet> -->
<!-- <router-outlet></router-outlet> -->

Se você configurou as rotas como no Passo 5, o app.component.html deve conter apenas <router-outlet></router-outlet> para que o Angular possa renderizar o componente correto com base na URL.

Passo 9: Executando a Aplicação

  1. No terminal, dentro do diretório do projeto, execute o comando:

    bash

    ng serve -o

    • ng serve: Compila e serve a aplicação localmente.

    • -o: Abre automaticamente a aplicação no seu navegador padrão.

  2. A aplicação estará disponível em http://localhost:4200/. Se você configurou a rota, acesse http://localhost:4200/consulta-clientes.

Você deverá ver a tela de consulta de clientes com os campos de filtro e a tabela. Teste os filtros e a seleção de itens na tabela.

Considerações Finais e Próximos Passos

  • Integração com Backend: Este guia utiliza um mock de dados (todosClientes) . Em uma aplicação real, o método buscarClientes() faria uma requisição HTTP (usando o HttpClient do Angular) para um serviço de backend. Esse backend, por sua vez, seria responsável por consultar os dados na tabela SA1 do Protheus (ou em qualquer outra fonte de dados).

  • Tratamento de Erros: Adicione tratamento de erros para chamadas de API.

  • Paginação: Para grandes volumes de dados, implemente paginação na tabela. O po-table possui suporte para paginação do lado do servidor.

  • Componentes Avançados de Filtro: O PO UI oferece componentes como po-lookup ou po-combo que podem ser usados para filtros mais avançados (por exemplo, buscar um cliente específico por código antes de preencher outros campos).

  • Estilização: Personalize a aparência da tela utilizando SCSS no arquivo consulta-clientes.component.scss ou aproveitando os tokens CSS do PO UI.

Este guia fornece uma base sólida para você começar a desenvolver telas de consulta com PO UI. Explore a documentação oficial do PO UI  para descobrir mais componentes e funcionalidades que podem enriquecer suas aplicações.

 
 
 

Posts recentes

Ver tudo

Comments


Precisa de mais informações?

Estamos aqui para ajudá-lo. Entre em contato por telefone, email ou redes sociais.

  • Black Facebook Icon
  • Black Twitter Icon
  • Black LinkedIn Icon
end_rodape_edited_edited_edited.jpg

© 2017 por EPV Consulting

bottom of page