431 lines
21 KiB
C#
431 lines
21 KiB
C#
using BLL;
|
|
using DAL;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
|
|
namespace UI
|
|
{
|
|
public class AgendaConsultaPanel : UserControl
|
|
{
|
|
// ── CORES ─────────────────────────────────────────────────────────────
|
|
private readonly Color AccentBlue = Color.FromArgb(37, 99, 235);
|
|
private readonly Color TextDark = Color.FromArgb(30, 41, 59);
|
|
private readonly Color BorderColor = Color.FromArgb(226, 232, 240);
|
|
private readonly Color GreenColor = Color.FromArgb(34, 197, 94);
|
|
private readonly Color MutedGray = Color.FromArgb(148, 163, 184);
|
|
private readonly Color SurfaceColor = Color.FromArgb(248, 250, 252);
|
|
|
|
// ── CONTROLES ─────────────────────────────────────────────────────────
|
|
private Panel pnlToolbar = null!;
|
|
private Panel pnlFiltros = null!;
|
|
private Panel pnlRodape = null!;
|
|
private DataGridView dgvAgenda = null!;
|
|
private Label lblTotal = null!;
|
|
|
|
// ── FILTROS ───────────────────────────────────────────────────────────
|
|
private RoundTextBox txtFiltroCompromisso = null!;
|
|
private RoundTextBox txtFiltroFunc = null!;
|
|
private RoundTextBox txtFiltroOsVinc = null!;
|
|
private RoundTextBox txtDataInicio = null!;
|
|
private RoundTextBox txtDataFim = null!;
|
|
private ComboBox cmbSituacao = null!;
|
|
|
|
// ── DADOS ─────────────────────────────────────────────────────────────
|
|
private List<MLL.ModeloAgenda> _todos = new();
|
|
private List<MLL.ModeloAgenda> _filtrados = new();
|
|
|
|
// ── EVENTO: abre cadastro com o registro selecionado ──────────────────
|
|
public event Action<MLL.ModeloAgenda>? OnAbrirCadastro;
|
|
|
|
//Carrega a string conexao com o banco de dados, para ser usada no repositório
|
|
private string _conexao = DadosDaConexao.ObterConexao();
|
|
|
|
// ── CONSTRUTOR ────────────────────────────────────────────────────────
|
|
public AgendaConsultaPanel()
|
|
{
|
|
Dock = DockStyle.Fill;
|
|
BackColor = Color.White;
|
|
DoubleBuffered = true;
|
|
|
|
InitializeLayout();
|
|
//CarregarDadosFake();
|
|
CarregarDadosDoBanco();
|
|
AplicarFiltros();
|
|
}
|
|
|
|
// ══════════════════════════════════════════════════════════════════════
|
|
// LAYOUT
|
|
//
|
|
// REGRA WINFORMS — ordem de adição ao Controls é INVERSA à exibição:
|
|
// 1º adicionar → Fill (ocupa o centro)
|
|
// 2º adicionar → Bottom
|
|
// 3º adicionar → Top (empurra o Fill para baixo; último = mais alto)
|
|
//
|
|
// ══════════════════════════════════════════════════════════════════════
|
|
private void InitializeLayout()
|
|
{
|
|
Controls.Clear();
|
|
|
|
// ── 1º: GRID (Fill) ───────────────────────────────────────────────
|
|
BuildGrid();
|
|
Controls.Add(dgvAgenda);
|
|
|
|
// ── 2º: RODAPÉ (Bottom) ───────────────────────────────────────────
|
|
pnlRodape = new Panel
|
|
{
|
|
Dock = DockStyle.Bottom,
|
|
Height = 30,
|
|
BackColor = SurfaceColor
|
|
};
|
|
lblTotal = new Label
|
|
{
|
|
AutoSize = true,
|
|
Location = new Point(16, 7),
|
|
Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
|
|
ForeColor = MutedGray,
|
|
Text = "0 registros encontrados"
|
|
};
|
|
pnlRodape.Controls.Add(lblTotal);
|
|
Controls.Add(pnlRodape);
|
|
|
|
// ── 3º: FILTROS (Top) ─────────────────────────────────────────────
|
|
pnlFiltros = new Panel
|
|
{
|
|
Dock = DockStyle.Top,
|
|
Height = 95,
|
|
BackColor = SurfaceColor,
|
|
Padding = new Padding(16, 8, 16, 8)
|
|
};
|
|
BuildFiltros();
|
|
Controls.Add(pnlFiltros);
|
|
|
|
// ── 4º: TOOLBAR (Top) — por último = fica acima dos filtros ───────
|
|
pnlToolbar = new Panel
|
|
{
|
|
Dock = DockStyle.Top,
|
|
Height = 55,
|
|
BackColor = SurfaceColor
|
|
};
|
|
|
|
var flow = new FlowLayoutPanel
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
Padding = new Padding(12, 10, 0, 0),
|
|
BackColor = Color.Transparent
|
|
};
|
|
|
|
var btnPesquisar = CreateToolbarButton("Pesquisar", AccentBlue);
|
|
var btnLimpar = CreateToolbarButton("Limpar", MutedGray);
|
|
var btnAbrir = CreateToolbarButton("Abrir", GreenColor);
|
|
var btnExportar = CreateToolbarButton("Exportar", Color.FromArgb(99, 102, 241));
|
|
|
|
btnPesquisar.Click += (_, _) => AplicarFiltros();
|
|
btnLimpar.Click += (_, _) => LimparFiltros();
|
|
btnAbrir.Click += (_, _) => AbrirRegistroSelecionado();
|
|
btnExportar.Click += (_, _) => ExportarCSV();
|
|
|
|
flow.Controls.AddRange(new Control[] { btnPesquisar, btnLimpar, btnAbrir, btnExportar });
|
|
pnlToolbar.Controls.Add(flow);
|
|
Controls.Add(pnlToolbar); // ← último Top = aparece no topo
|
|
}
|
|
|
|
// ── FILTROS ───────────────────────────────────────────────────────────
|
|
private void BuildFiltros()
|
|
{
|
|
// Linha 1
|
|
txtFiltroCompromisso = AddFiltroInput(pnlFiltros, "Compromisso", 0, 8, 260);
|
|
txtFiltroFunc = AddFiltroInput(pnlFiltros, "Funcionário", 270, 8, 200);
|
|
txtFiltroOsVinc = AddFiltroInput(pnlFiltros, "OS Vinculada", 480, 8, 130);
|
|
|
|
// Linha 2
|
|
txtDataInicio = AddFiltroInput(pnlFiltros, "Data Início", 0, 50, 130);
|
|
txtDataFim = AddFiltroInput(pnlFiltros, "Data Fim", 140, 50, 130);
|
|
|
|
pnlFiltros.Controls.Add(new Label
|
|
{
|
|
Text = "Situação",
|
|
Location = new Point(280, 50),
|
|
Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
|
|
ForeColor = TextDark,
|
|
AutoSize = true
|
|
});
|
|
|
|
cmbSituacao = new ComboBox
|
|
{
|
|
Location = new Point(280, 66),
|
|
Size = new Size(160, 26),
|
|
DropDownStyle = ComboBoxStyle.DropDownList,
|
|
Font = new Font("Segoe UI", 8.5f),
|
|
FlatStyle = FlatStyle.Flat
|
|
};
|
|
cmbSituacao.Items.AddRange(new object[] { "Todos", "Pendente", "Realizado" });
|
|
cmbSituacao.SelectedIndex = 0;
|
|
pnlFiltros.Controls.Add(cmbSituacao);
|
|
|
|
foreach (var txt in new[] { txtFiltroCompromisso, txtFiltroFunc, txtFiltroOsVinc, txtDataInicio, txtDataFim })
|
|
txt.KeyDown += (_, e) => { if (e.KeyCode == Keys.Enter) AplicarFiltros(); };
|
|
}
|
|
|
|
private RoundTextBox AddFiltroInput(Control parent, string label, int x, int y, int width)
|
|
{
|
|
parent.Controls.Add(new Label
|
|
{
|
|
Text = label,
|
|
Location = new Point(x, y),
|
|
Font = new Font("Segoe UI", 7.5f, FontStyle.Bold),
|
|
ForeColor = TextDark,
|
|
AutoSize = true
|
|
});
|
|
var txt = new RoundTextBox
|
|
{
|
|
Location = new Point(x, y + 16),
|
|
Size = new Size(width, 26),
|
|
Radius = 4,
|
|
BorderColor = BorderColor,
|
|
FocusColor = AccentBlue,
|
|
BackColor = Color.White
|
|
};
|
|
parent.Controls.Add(txt);
|
|
return txt;
|
|
}
|
|
|
|
// ── GRID ──────────────────────────────────────────────────────────────
|
|
private void BuildGrid()
|
|
{
|
|
dgvAgenda = new DataGridView
|
|
{
|
|
Dock = DockStyle.Fill,
|
|
BackgroundColor = Color.White,
|
|
BorderStyle = BorderStyle.None,
|
|
CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal,
|
|
ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single,
|
|
GridColor = BorderColor,
|
|
RowHeadersVisible = false,
|
|
AllowUserToAddRows = false,
|
|
AllowUserToDeleteRows = false,
|
|
ReadOnly = true,
|
|
SelectionMode = DataGridViewSelectionMode.FullRowSelect,
|
|
MultiSelect = false,
|
|
Font = new Font("Segoe UI", 8.5f),
|
|
AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill,
|
|
ColumnHeadersHeight = 36,
|
|
ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing,
|
|
RowTemplate = { Height = 32 }
|
|
};
|
|
|
|
dgvAgenda.ColumnHeadersDefaultCellStyle = new DataGridViewCellStyle
|
|
{
|
|
BackColor = SurfaceColor,
|
|
ForeColor = TextDark,
|
|
Font = new Font("Segoe UI", 8.5f, FontStyle.Bold),
|
|
Alignment = DataGridViewContentAlignment.MiddleLeft,
|
|
Padding = new Padding(8, 0, 0, 0),
|
|
SelectionBackColor = SurfaceColor,
|
|
SelectionForeColor = TextDark
|
|
};
|
|
|
|
dgvAgenda.DefaultCellStyle = new DataGridViewCellStyle
|
|
{
|
|
ForeColor = TextDark,
|
|
BackColor = Color.White,
|
|
SelectionBackColor = Color.FromArgb(239, 246, 255),
|
|
SelectionForeColor = AccentBlue,
|
|
Padding = new Padding(8, 0, 0, 0)
|
|
};
|
|
|
|
dgvAgenda.AlternatingRowsDefaultCellStyle = new DataGridViewCellStyle
|
|
{
|
|
BackColor = SurfaceColor,
|
|
SelectionBackColor = Color.FromArgb(239, 246, 255),
|
|
SelectionForeColor = AccentBlue
|
|
};
|
|
|
|
dgvAgenda.Columns.AddRange(new DataGridViewColumn[]
|
|
{
|
|
new DataGridViewTextBoxColumn { Name = "colId", HeaderText = "ID", FillWeight = 5 },
|
|
new DataGridViewTextBoxColumn { Name = "colCodigo", HeaderText = "Código", FillWeight = 8 },
|
|
new DataGridViewTextBoxColumn { Name = "colCompromisso", HeaderText = "Compromisso", FillWeight = 26 },
|
|
new DataGridViewTextBoxColumn { Name = "colData", HeaderText = "Data", FillWeight = 10 },
|
|
new DataGridViewTextBoxColumn { Name = "colHora", HeaderText = "Hora", FillWeight = 7 },
|
|
new DataGridViewTextBoxColumn { Name = "colDia", HeaderText = "Dia", FillWeight = 10 },
|
|
new DataGridViewTextBoxColumn { Name = "colFunc", HeaderText = "Funcionário", FillWeight = 16 },
|
|
new DataGridViewTextBoxColumn { Name = "colAvisar", HeaderText = "Avisar", FillWeight = 12 },
|
|
new DataGridViewTextBoxColumn { Name = "colOs", HeaderText = "OS Vinc.", FillWeight = 8 },
|
|
new DataGridViewTextBoxColumn { Name = "colSituacao", HeaderText = "Situação", FillWeight = 10 },
|
|
});
|
|
|
|
dgvAgenda.CellDoubleClick += (_, e) =>
|
|
{
|
|
if (e.RowIndex >= 0) AbrirRegistroSelecionado();
|
|
};
|
|
|
|
dgvAgenda.CellFormatting += (_, e) =>
|
|
{
|
|
if (e.RowIndex < 0 || e.ColumnIndex < 0) return;
|
|
if (dgvAgenda.Columns[e.ColumnIndex].Name != "colSituacao") return;
|
|
|
|
bool realizado = e.Value?.ToString() == "Realizado";
|
|
e.CellStyle.ForeColor = realizado ? Color.FromArgb(22, 101, 52) : Color.FromArgb(146, 64, 14);
|
|
e.CellStyle.Font = new Font("Segoe UI", 8f, FontStyle.Bold);
|
|
e.CellStyle.SelectionForeColor = e.CellStyle.ForeColor;
|
|
e.FormattingApplied = true;
|
|
};
|
|
}
|
|
|
|
// ══════════════════════════════════════════════════════════════════════
|
|
// LÓGICA
|
|
// ══════════════════════════════════════════════════════════════════════
|
|
private void AplicarFiltros()
|
|
{
|
|
_filtrados = _todos.ToList();
|
|
|
|
var termComp = txtFiltroCompromisso.Text.Trim().ToLower();
|
|
if (!string.IsNullOrEmpty(termComp))
|
|
_filtrados = _filtrados.Where(e => e.COMPROMISSO?.ToLower().Contains(termComp) == true).ToList();
|
|
|
|
var termFunc = txtFiltroFunc.Text.Trim().ToLower();
|
|
if (!string.IsNullOrEmpty(termFunc))
|
|
_filtrados = _filtrados.Where(e => e.FUNC?.ToLower().Contains(termFunc) == true).ToList();
|
|
|
|
var termOs = txtFiltroOsVinc.Text.Trim().ToLower();
|
|
if (!string.IsNullOrEmpty(termOs))
|
|
_filtrados = _filtrados.Where(e => e.OS_VINC?.ToLower().Contains(termOs) == true).ToList();
|
|
|
|
if (DateTime.TryParseExact(txtDataInicio.Text.Trim(), "dd/MM/yyyy",
|
|
System.Globalization.CultureInfo.InvariantCulture,
|
|
System.Globalization.DateTimeStyles.None, out var dtIni))
|
|
_filtrados = _filtrados.Where(e => ParseData(e.dDATA) >= dtIni).ToList();
|
|
|
|
if (DateTime.TryParseExact(txtDataFim.Text.Trim(), "dd/MM/yyyy",
|
|
System.Globalization.CultureInfo.InvariantCulture,
|
|
System.Globalization.DateTimeStyles.None, out var dtFim))
|
|
_filtrados = _filtrados.Where(e => ParseData(e.dDATA) <= dtFim).ToList();
|
|
|
|
var sit = cmbSituacao.SelectedItem?.ToString();
|
|
if (sit == "Realizado") _filtrados = _filtrados.Where(e => e.REALIZADO?.ToUpper() == "S").ToList();
|
|
else if (sit == "Pendente") _filtrados = _filtrados.Where(e => e.REALIZADO?.ToUpper() != "S").ToList();
|
|
|
|
PreencherGrid();
|
|
}
|
|
|
|
private void LimparFiltros()
|
|
{
|
|
txtFiltroCompromisso.Text = string.Empty;
|
|
txtFiltroFunc.Text = string.Empty;
|
|
txtFiltroOsVinc.Text = string.Empty;
|
|
txtDataInicio.Text = string.Empty;
|
|
txtDataFim.Text = string.Empty;
|
|
cmbSituacao.SelectedIndex = 0;
|
|
AplicarFiltros();
|
|
}
|
|
|
|
private void PreencherGrid()
|
|
{
|
|
dgvAgenda.Rows.Clear();
|
|
|
|
foreach (var ev in _filtrados.OrderBy(e => ParseData(e.dDATA)).ThenBy(e => e.HORA))
|
|
{
|
|
dgvAgenda.Rows.Add(
|
|
ev.ID_AGENDA, ev.CODIGO, ev.COMPROMISSO,
|
|
ev.dDATA, ev.HORA, ev.DIA, ev.FUNC, ev.AVISAR, ev.OS_VINC,
|
|
ev.REALIZADO?.ToUpper() == "S" ? "Realizado" : "Pendente"
|
|
);
|
|
}
|
|
|
|
int total = _filtrados.Count;
|
|
lblTotal.Text = total == 1 ? "1 registro encontrado" : $"{total} registros encontrados";
|
|
}
|
|
|
|
private void AbrirRegistroSelecionado()
|
|
{
|
|
if (dgvAgenda.SelectedRows.Count == 0)
|
|
{
|
|
MessageBox.Show("Selecione um registro na lista.",
|
|
"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return;
|
|
}
|
|
|
|
var row = dgvAgenda.SelectedRows[0];
|
|
if (row.Cells["colId"].Value is int id)
|
|
{
|
|
var ev = _filtrados.FirstOrDefault(e => e.ID_AGENDA == id);
|
|
if (ev != null) OnAbrirCadastro?.Invoke(ev);
|
|
}
|
|
}
|
|
|
|
private void ExportarCSV()
|
|
{
|
|
if (!_filtrados.Any())
|
|
{
|
|
MessageBox.Show("Nenhum registro para exportar.",
|
|
"Atenção", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return;
|
|
}
|
|
|
|
using var dlg = new SaveFileDialog
|
|
{
|
|
Filter = "CSV (*.csv)|*.csv",
|
|
FileName = $"Agenda_{DateTime.Today:yyyyMMdd}.csv"
|
|
};
|
|
if (dlg.ShowDialog() != DialogResult.OK) return;
|
|
|
|
var sb = new System.Text.StringBuilder();
|
|
sb.AppendLine("ID;Código;Compromisso;Data;Hora;Dia;Funcionário;Avisar;OS Vinculada;Situação");
|
|
foreach (var ev in _filtrados.OrderBy(e => ParseData(e.dDATA)).ThenBy(e => e.HORA))
|
|
sb.AppendLine($"{ev.ID_AGENDA};{ev.CODIGO};{ev.COMPROMISSO};{ev.dDATA};" +
|
|
$"{ev.HORA};{ev.DIA};{ev.FUNC};{ev.AVISAR};{ev.OS_VINC};" +
|
|
$"{(ev.REALIZADO?.ToUpper() == "S" ? "Realizado" : "Pendente")}");
|
|
|
|
System.IO.File.WriteAllText(dlg.FileName, sb.ToString(), System.Text.Encoding.UTF8);
|
|
MessageBox.Show($"Exportado com sucesso!\n{dlg.FileName}", "Exportar",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
|
|
// ── DADOS FAKE — substituir pelo repositório ──────────────────────────
|
|
private void CarregarDadosFake()
|
|
{
|
|
var hoje = DateTime.Today;
|
|
_todos = new List<MLL.ModeloAgenda>
|
|
{
|
|
new(1, "AG001", "Reunião com cliente", hoje.ToString("dd/MM/yyyy"), "30 minutos antes", "Carlos Silva", DiaSemana(hoje), "09:00", "S", "OS-1042"),
|
|
new(2, "AG002", "Visita técnica", hoje.ToString("dd/MM/yyyy"), "1 hora antes", "Ana Souza", DiaSemana(hoje), "14:00", "N", "OS-1055"),
|
|
new(3, "AG003", "Entrega de equipamento", hoje.AddDays(4).ToString("dd/MM/yyyy"), "1 dia antes", "Pedro Lima", DiaSemana(hoje.AddDays(4)), "10:30", "N", ""),
|
|
new(4, "AG004", "Manutenção preventiva", hoje.AddDays(-2).ToString("dd/MM/yyyy"), "30 minutos antes", "Carlos Silva", DiaSemana(hoje.AddDays(-2)), "08:00", "S", "OS-1030"),
|
|
new(5, "AG005", "Treinamento equipe", hoje.AddDays(7).ToString("dd/MM/yyyy"), "1 dia antes", "Ana Souza", DiaSemana(hoje.AddDays(7)), "13:00", "N", ""),
|
|
};
|
|
}//Carregar dados fakes para ixibição
|
|
private void CarregarDadosDoBanco()
|
|
{
|
|
BLLAgenda _agendaBLL = new BLLAgenda(_conexao);
|
|
_todos.Clear();
|
|
_todos.AddRange(_agendaBLL.Listar());
|
|
}//Carregar dados reais do banco de dados usando o repositório
|
|
|
|
private static DateTime ParseData(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value)) return DateTime.MinValue;
|
|
if (DateTime.TryParseExact(value, "dd/MM/yyyy",
|
|
System.Globalization.CultureInfo.InvariantCulture,
|
|
System.Globalization.DateTimeStyles.None, out var dt)) return dt;
|
|
if (DateTime.TryParse(value, out dt)) return dt;
|
|
return DateTime.MinValue;
|
|
}
|
|
|
|
private static string DiaSemana(DateTime d) =>
|
|
new System.Globalization.CultureInfo("pt-BR").DateTimeFormat.GetDayName(d.DayOfWeek);
|
|
|
|
private RoundButton CreateToolbarButton(string text, Color color) => new RoundButton
|
|
{
|
|
Text = text,
|
|
Size = new Size(95, 32),
|
|
BackColor = color,
|
|
ForeColor = Color.White,
|
|
Font = new Font("Segoe UI Semibold", 8.5f),
|
|
Margin = new Padding(0, 0, 6, 0),
|
|
Cursor = Cursors.Hand
|
|
};
|
|
}
|
|
} |