using System; using System.Collections.Generic; using System.Numerics; using System.Threading.Tasks; using Npgsql; using Spectre.Console; class Program { static DateTime _endTime; static bool _stop = false; 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; // Agora guardamos uma lista de tuplas (UserID, Nome) static readonly List<(BigInteger UserId, string Nome)> _pipeUsers = new(); static void Main() { AnsiConsole.Clear(); // 1) Autenticação (pode retornar múltiplos usuários) Autenticacao(); if (!_isAuthenticated) { AnsiConsole.MarkupLine("[bold red]Nenhum usuário encontrado ou erro na autenticação. Saindo...[/]"); Console.ReadLine(); return; } // 2) Loop principal: atualizar dados e aguardar entrada while (!_stop) { AtualizarDados(); AguardarEntrada(); } AnsiConsole.MarkupLine("[bold yellow]Aplicação encerrada.[/]"); } static void Autenticacao() { AnsiConsole.Status() .Spinner(Spinner.Known.Dots) .Start("[green]Autenticando usuário...[/]", ctx => { const string query = @" SELECT ""UserID"", ""Nome"" FROM public.""usuarios"" WHERE ""windowsID"" = @WindowsID"; try { using var conn = new NpgsqlConnection(_connectionString); conn.Open(); using var cmd = new NpgsqlCommand(query, conn); cmd.Parameters.AddWithValue("@WindowsID", _windowsID); using var reader = cmd.ExecuteReader(); while (reader.Read()) { var userId = BigInteger.Parse(reader["UserID"].ToString()!); var nome = reader["Nome"].ToString()!; _pipeUsers.Add((userId, nome)); } if (_pipeUsers.Count > 0) { _isAuthenticated = true; } else { AnsiConsole.MarkupLine("[bold red]Nenhum usuário encontrado para este WindowsID.[/]"); _isAuthenticated = false; } } catch (Exception ex) { AnsiConsole.MarkupLine($"\n[red]Erro na autenticação:[/] {ex.Message}"); _isAuthenticated = false; } }); } static void AtualizarDados() { AnsiConsole.Clear(); // Painel de cabeçalho que mostra quantos usuários foram carregados var header = new Panel($"[bold]WindowsID[/]: {_windowsID} • [bold]Usuários encontrados[/]: {_pipeUsers.Count}") .Header("[yellow]Resumo Diário por Usuário[/]") .Expand(); AnsiConsole.Write(header); // Montamos uma tabela com: Nome do usuário | UserID | Registros Hoje var table = new Table().Border(TableBorder.Rounded); table.AddColumn("[green]Nome[/]"); table.AddColumn("[green]UserID[/]"); table.AddColumn("[green]Registros Hoje[/]"); // Para cada usuário, rodar uma query COUNT(*) e adicionar linha na tabela foreach (var (userId, nome) in _pipeUsers) { int count = 0; AnsiConsole.Status() .Spinner(Spinner.Known.Line) .Start($"[blue]Obtendo registros de [yellow]{nome}[/]...[/]", ctx => { const string query = @" SELECT COUNT(*) FROM public.""ActionsHistory"" WHERE ""UserID"" = @pipeUser AND ""MovedAt"" > CURRENT_DATE AND ""FieldID"" IS NOT NULL"; try { using var conn = new NpgsqlConnection(_connectionString); conn.Open(); using var cmd = new NpgsqlCommand(query, conn); cmd.Parameters.AddWithValue("@pipeUser", userId); count = Convert.ToInt32(cmd.ExecuteScalar()); } catch (Exception ex) { // Em caso de erro, exibimos zero e continuamos count = 0; AnsiConsole.MarkupLine($"\n[red]Erro ao consultar {nome}:[/] {ex.Message}"); } }); table.AddRow(nome, userId.ToString(), $"[bold yellow]{count}[/]"); } AnsiConsole.Write(table); AnsiConsole.MarkupLine("\n[gray]Pressione [green]ENTER[/] para atualizar agora ou qualquer outra tecla para sair.[/]"); } static void AguardarEntrada() { // Tempo de espera em segundos (ex.: 10 minutos = 600s) int intervalSeconds = 600; _endTime = DateTime.Now.AddSeconds(intervalSeconds); // Escreve uma linha em branco para “reservar” o lugar do contador AnsiConsole.WriteLine(""); // Começa o loop que vai atualizar a mesma linha a cada segundo while (!_stop) { var remaining = _endTime - DateTime.Now; if (remaining.TotalMilliseconds <= 0) { // Quando chegar a zero, exibe a mensagem de atualização automática AnsiConsole.MarkupLine("\r[red]Atualização automática agora![/]"); Thread.Sleep(1000); break; } // Monta o texto de “Próxima atualização em MM:SS” AnsiConsole.Markup($"\r[blue]Próxima atualização em {remaining.Minutes:00}:{remaining.Seconds:00}[/]"); // Pequena pausa de 1 segundo Thread.Sleep(1000); // Se o usuário apertar qualquer tecla… if (Console.KeyAvailable) { var key = Console.ReadKey(true); // …e não for ENTER, sinalizamos para parar o loop e sair if (key.Key != ConsoleKey.Enter) _stop = true; else break; } } // Garante que, ao sair do loop, o cursor fique embaixo do texto Console.WriteLine(""); } }