From 5e5618dd6d18120317bedae5fab111c102e868d2 Mon Sep 17 00:00:00 2001 From: Giuliano Paschoalino Date: Mon, 21 Jul 2025 17:41:49 -0300 Subject: [PATCH] =?UTF-8?q?Refatora=C3=A7=C3=A3o=20para=20modularidade=20e?= =?UTF-8?q?=20melhorias=20visuais?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Código refatorado para maior modularidade e legibilidade, com criação de métodos auxiliares como `ExibirCabecalho`, `CriarTabelaLigacoes` e outros. - Substituição de código inline por métodos reutilizáveis, reduzindo duplicação e centralizando lógica. - Melhorias na exibição de dados com tabelas e painéis mais organizados. - Lógica de consulta e contagem de registros encapsulada em métodos dedicados (`ObterRegistrosUsuario`, `ContarRegistros`). - Introdução de formatação condicional para contagens e valores numéricos. - Uso de LINQ para simplificar manipulação de coleções. - Remoção de código redundante, dependências desnecessárias e variáveis globais fixas. - Mensagens de erro mais informativas e consistentes. - Adição de comentários explicativos e organização com `#region Helpers`. - Funcionalidade principal mantida, com melhorias na experiência do usuário. --- Program.cs | 250 +++++++++++++++++++++++++++++------------------------ 1 file changed, 139 insertions(+), 111 deletions(-) diff --git a/Program.cs b/Program.cs index 1178477..7d0acaa 100644 --- a/Program.cs +++ b/Program.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; +using System.Data.Common; using System.Numerics; -using System.Threading.Tasks; using Npgsql; using Spectre.Console; @@ -13,6 +10,7 @@ class Program static bool _isAuthenticated = false; static readonly string _connectionString = "Server=192.168.10.248;Port=5432;Database=pipefy_move_cards;User Id=postgres;Password=gds21;"; static readonly string _windowsID = Environment.UserName; + //static readonly string _windowsID = "comercial6"; static readonly List<(string actionId, string actionName)> _actionIds = // Tuplas de IDs e nomes das fases que queremos monitorar [ new ("318642783-318906957", "Agendou reunião 1"), @@ -88,122 +86,35 @@ class Program public string? AcaoID { get; set; } public required string Acao { get; set; } } + static void AtualizarDados() { var records = new List(); AnsiConsole.Clear(); - // Painel de cabeçalho que mostra quantos usuários foram carregados + ExibirCabecalho(); - var status = new Align(new Panel($"[bold]WindowsID[/]: {_windowsID} | [bold]Usuários encontrados[/]: {_pipeUsers.Count}"), HorizontalAlignment.Center, VerticalAlignment.Top); - var header = new Panel(status) - .Header("[yellow]Resumo Diário por Usuário[/]",Justify.Center) - .Expand(); - AnsiConsole.Write(new Align(header, HorizontalAlignment.Center, VerticalAlignment.Top)); - - // Montamos uma tabela com: Nome do usuário | UserID | Registros Hoje - var tableContLigacoes = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); - tableContLigacoes.Border(TableBorder.Rounded); - tableContLigacoes.AddColumn(new TableColumn("[green]Nome[/]").Centered()); - tableContLigacoes.AddColumn(new TableColumn("[green]UserID[/]").Centered()); - tableContLigacoes.AddColumn(new TableColumn("[green]Registros Hoje[/]").Centered()); - - // Montamos uma tabela com: Nome do usuário | UserID | Registros Hoje - var tableContReunioes = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); - tableContReunioes.Border(TableBorder.Rounded); - tableContReunioes.AddColumn(new TableColumn("[green]Nome[/]").Centered()); - tableContReunioes.AddColumn(new TableColumn("[green]UserID[/]").Centered()); - tableContReunioes.AddColumn(new TableColumn("[green]Agendadas[/]").Centered()); - tableContReunioes.AddColumn(new TableColumn("[green]Realizadas[/]").Centered()); - tableContReunioes.AddColumn(new TableColumn("[green]Canceladas[/]").Centered()); + var tableContLigacoes = CriarTabelaLigacoes(); + var tableContReunioes = CriarTabelaReunioes(); // Para cada usuário, rodar uma query COUNT(*) e adicionar linha na tabela foreach (var (userId, nome) in _pipeUsers) { - var userRecords = new List(); - int count = 0; - int countR = 0; - int countA = 0; - int countC = 0; - AnsiConsole.Status() - .Spinner(Spinner.Known.Line) - .Start($"[blue]Obtendo registros de [yellow]{nome}[/]...[/]", ctx => - { - const string query = @" - SELECT * FROM public.""ActionsHistory"" - WHERE ""UserID"" = @pipeUser AND - ""MovedAt"" >= date_trunc('month', CURRENT_DATE)"; - try - { - using var conn = new NpgsqlConnection(_connectionString); - conn.Open(); - using var cmd = new NpgsqlCommand(query, conn); - cmd.Parameters.AddWithValue("@pipeUser", userId); - var reader = cmd.ExecuteReader(); - using (reader) - { - while (reader.Read()) - { - var temp = new Record - { - Id = ToIntOrNull(reader, "Id"), - Action = ToStringOrNull(reader, "Action"), - User = _pipeUsers.Find(u => u.UserId == ToIntOrNull(reader, "UserID")).Nome, - FieldID = ToStringOrNull(reader, "FieldID"), - From = ToIntOrNull(reader, "From"), - To = ToIntOrNull(reader, "To"), - CardID = ToIntOrNull(reader, "CardID"), - PipeSUID = ToStringOrNull(reader, "PipeSUID"), - MovedAt = (DateTime)(reader["MovedAt"] ?? DateTime.MinValue), - Title = ToStringOrNull(reader, "Title") ?? "-", - Acao = "Desconhecida" - }; - temp.AcaoID = temp.From + "-" + temp.To; - temp.Acao = _actionIds.Find(p => p.actionId == temp.AcaoID).actionName; + var userRecords = ObterRegistrosUsuario(userId, nome); + var (count, countA, countR, countC) = ContarRegistros(userRecords); - userRecords.Add(temp); - } - } - } - catch (Exception ex) - { - // Em caso de erro, exibimos zero e continuamos - count = 0; - AnsiConsole.MarkupLine($"\n[red]Erro ao consultar {nome}:[/] {ex.Message}"); - } - }); - count = userRecords.Where(x => (x.MovedAt > DateTime.Today && x.FieldID is not null)).ToList().Count; - countR = userRecords.Where(x => ((x.Acao ?? "").StartsWith("Realizou"))).ToList().Count; - countA = userRecords.Where(x => ((x.Acao ?? "").StartsWith("Agendou"))).ToList().Count; - countC = userRecords.Where(x => ((x.Acao ?? "").EndsWith("cancelada"))).ToList().Count; - tableContLigacoes.AddRow(nome, userId.ToString(), $"[bold yellow]{count}[/]"); - tableContReunioes.AddRow(nome, userId.ToString(), $"[bold yellow]{countA}[/]", $"[bold yellow]{countR}[/]", $"[bold yellow]{countC}[/]"); + var format = ObterFormatoCor(count); + + tableContLigacoes.AddRow(nome, userId.ToString(), $"{format} {count} [/]"); + tableContReunioes.AddRow(nome, userId.ToString(), $"[yellow] {countA:#;-#;} [/]", $"[green] {countR:#;-#;} [/]", $"[red] {countC:#;-#;} [/]"); records.AddRange(userRecords); } - var panel = new Panel(new Align(tableContLigacoes, HorizontalAlignment.Center, VerticalAlignment.Top)) - .Header("[blue bold] Ligações [/]", Justify.Center) - .Border(BoxBorder.Double) - .Expand(); - AnsiConsole.Write(new Align(panel, HorizontalAlignment.Center, VerticalAlignment.Top)); + ExibirPainel(tableContLigacoes, "[blue bold] Ligações [/]"); + ExibirPainel(tableContReunioes, "[blue bold] Reuniões Agendadas e Realizadas [/]"); - panel = new Panel(new Align(tableContReunioes, HorizontalAlignment.Center, VerticalAlignment.Top)) - .Header("[blue bold] Reuniões Agendadas e Realizadas [/]", Justify.Center) - .Border(BoxBorder.Double) - .Expand(); - AnsiConsole.Write(new Align(panel, HorizontalAlignment.Center, VerticalAlignment.Top)); - // Montamos uma tabela com: Nome do usuário | UserID | Registros Hoje - var tableReunioes = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); - tableReunioes.AddColumn(new TableColumn("[green]Data[/]").Centered()); - tableReunioes.AddColumn(new TableColumn("[green]Status[/]").Centered()); - tableReunioes.AddColumn(new TableColumn("[green]Empresa[/]").Centered()); - tableReunioes.AddColumn(new TableColumn("[green]Card ID\n(Ctrl + click)[/]").Centered()); - tableReunioes.AddColumn(new TableColumn("[green]Prospectante[/]").Centered()); - - records = [.. records.OrderBy(x => x.MovedAt.Date).OrderBy(x => x.Acao).OrderBy(y => y.User)]; - - // Para cada usuário, rodar uma query COUNT(*) e adicionar linha na tabela - foreach (var record in records) + var tableReunioes = CriarTabelaDetalhesReunioes(); + foreach (var record in records.OrderBy(x => x.User).ThenBy(x => x.Acao).ThenBy(x => x.MovedAt.Date)) { if (record.Acao is not null) { @@ -216,15 +127,132 @@ class Program ); } } - panel = new Panel(new Align(tableReunioes, HorizontalAlignment.Center, VerticalAlignment.Top)) - .Header("[blue bold] Reuniões no Mês [/]", Justify.Center) - .Border(BoxBorder.Double) - .Expand(); - AnsiConsole.Write(new Align(panel, HorizontalAlignment.Center, VerticalAlignment.Top)); + + ExibirPainel(tableReunioes, "[blue bold] Reuniões no Mês [/]"); AnsiConsole.MarkupLine("\n[gray]Pressione [green]ENTER[/] para atualizar agora ou qualquer outra tecla para sair.[/]"); } + static void ExibirCabecalho() + { + // Painel de cabeçalho que mostra quantos usuários foram carregados + var status = new Align(new Panel($"[bold]WindowsID[/]: {_windowsID} | [bold]Usuários encontrados[/]: {_pipeUsers.Count}"), HorizontalAlignment.Center, VerticalAlignment.Top); + var header = new Panel(status) + .Header("[yellow]Resumo Diário por Usuário[/]", Justify.Center) + .Expand(); + AnsiConsole.Write(new Align(header, HorizontalAlignment.Center, VerticalAlignment.Top)); + + } + static Table CriarTabelaLigacoes() + { + var table = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); + table.AddColumn(new TableColumn("[green]Nome[/]").Centered()); + table.AddColumn(new TableColumn("[green]UserID[/]").Centered()); + table.AddColumn(new TableColumn("[green]Registros Hoje[/]").Centered()); + return table; + } + static Table CriarTabelaReunioes() + { + var table = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); + table.AddColumn(new TableColumn("[white]Nome[/]").Centered()); + table.AddColumn(new TableColumn("[white]UserID[/]").Centered()); + table.AddColumn(new TableColumn("[yellow]Agendadas[/]").Centered()); + table.AddColumn(new TableColumn("[green]Realizadas[/]").Centered()); + table.AddColumn(new TableColumn("[red]Canceladas[/]").Centered()); + return table; + } + static Table CriarTabelaDetalhesReunioes() + { + var table = new Table().Border(TableBorder.Rounded).Alignment(Justify.Center); + table.AddColumn(new TableColumn("[green]Data[/]").Centered()); + table.AddColumn(new TableColumn("[green]Status[/]").Centered()); + table.AddColumn(new TableColumn("[green]Empresa[/]").Centered()); + table.AddColumn(new TableColumn("[green]Card ID\n(Ctrl + click)[/]").Centered()); + table.AddColumn(new TableColumn("[green]Prospectante[/]").Centered()); + return table; + } + static void ExibirPainel(Table table, string titulo) + { + var panel = new Panel(new Align(table, HorizontalAlignment.Center, VerticalAlignment.Top)) + .Header(titulo, Justify.Center) + .Border(BoxBorder.Double) + .Expand(); + AnsiConsole.Write(new Align(panel, HorizontalAlignment.Center, VerticalAlignment.Top)); + } + static List ObterRegistrosUsuario(BigInteger userId, string nome) + { + var userRecords = new List(); + AnsiConsole.Status() + .Spinner(Spinner.Known.Line) + .Start($"[blue]Obtendo registros de [yellow]{nome}[/]...[/]", ctx => + { + const string query = @" + SELECT * FROM public.""ActionsHistory"" + WHERE ""UserID"" = @pipeUser AND + ""MovedAt"" >= date_trunc('month', CURRENT_DATE)"; + try + { + using var conn = new NpgsqlConnection(_connectionString); + conn.Open(); + using var cmd = new NpgsqlCommand(query, conn); + cmd.Parameters.AddWithValue("@pipeUser", userId); + using var reader = cmd.ExecuteReader(); + while (reader.Read()) + { + var temp = new Record + { + Id = ToIntOrNull(reader, "Id"), + Action = ToStringOrNull(reader, "Action"), + User = _pipeUsers.Find(u => u.UserId == ToIntOrNull(reader, "UserID")).Nome, + FieldID = ToStringOrNull(reader, "FieldID"), + From = ToIntOrNull(reader, "From"), + To = ToIntOrNull(reader, "To"), + CardID = ToIntOrNull(reader, "CardID"), + PipeSUID = ToStringOrNull(reader, "PipeSUID"), + MovedAt = (DateTime)(reader["MovedAt"] ?? DateTime.MinValue), + Title = ToStringOrNull(reader, "Title") ?? "-", + Acao = "Desconhecida" + }; + temp.AcaoID = temp.From + "-" + temp.To; + temp.Acao = _actionIds.Find(p => p.actionId == temp.AcaoID).actionName; + userRecords.Add(temp); + } + } + catch (Exception ex) + { + AnsiConsole.MarkupLine($"\n[red]Erro ao consultar {nome}:[/] {ex.Message}"); + } + }); + return userRecords; + } + static (int count, int countA, int countR, int countC) ContarRegistros(List userRecords) + { + int count = userRecords.Count(x => x.MovedAt > DateTime.Today && x.FieldID is not null); + int countR = userRecords.Count(x => (x.Acao ?? "").StartsWith("Realizou")); + int countA = userRecords.Count(x => (x.Acao ?? "").StartsWith("Agendou")); + int countC = userRecords.Count(x => (x.Acao ?? "").EndsWith("cancelada")); + return (count, countA, countR, countC); + } + static string ObterFormatoCor(int count) + { + var format = ""; + switch (count) + { + case int n when (n < 20): + format = "[red]"; + break; + case int n when (n >= 20 && n < 40): + format = "[yellow]"; + break; + case int n when (n >= 40 && n < 60): + format = "[blue]"; + break; + case int n when (n >= 60): + format = "[white on green bold]"; + break; + } + return format; + } static void AguardarEntrada() { // Tempo de espera em segundos (ex.: 10 minutos = 600s) @@ -268,7 +296,6 @@ class Program // Garante que, ao sair do loop, o cursor fique embaixo do texto Console.WriteLine(""); } - static void Autenticacao() { AnsiConsole.Status() @@ -312,6 +339,7 @@ class Program } }); } + #region Helpers static int? ToIntOrNull(DbDataReader r, string col)