Refatoração para modularidade e melhorias visuais
- 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.
This commit is contained in:
parent
ad6bd1f479
commit
5e5618dd6d
250
Program.cs
250
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<Record>();
|
||||
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<Record>();
|
||||
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<Record> ObterRegistrosUsuario(BigInteger userId, string nome)
|
||||
{
|
||||
var userRecords = new List<Record>();
|
||||
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<Record> 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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user