Guia Prático: Criando uma Tela de Consulta de Clientes com PO UI no VSCode
- Eloy Vanço
- há 1 dia
- 10 min de leitura
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
Abra o terminal ou prompt de comando.
Navegue até o diretório onde você deseja criar seu projeto.
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).
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.
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.
No terminal, dentro do diretório do seu projeto, execute o comando:
bash
ng add @po-ui/ng-components
O Angular CLI perguntará se deseja prosseguir com a instalação. Digite Y e pressione Enter.
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.
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).
Abra o projeto no VSCode.
Navegue até o arquivo src/app/app.module.ts.
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.
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.
Abra o arquivo src/app/app-routing.module.ts.
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
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.
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.
Comments