From b9144c1ade331973012c12522661563964eb7b8f Mon Sep 17 00:00:00 2001 From: Marco Pisco Date: Fri, 9 Jan 2026 16:44:54 +0000 Subject: [PATCH 1/2] =?UTF-8?q?Adicionar=20gera=C3=A7=C3=A3o=20de=20relat?= =?UTF-8?q?=C3=B3rios=20em=20PDF=20para=20utiliza=C3=A7=C3=A3o=20de=20sala?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/scripts/relatoriosaladiario.php | 234 ++++++++++++++++++++++++++ composer.json | 3 +- composer.lock | 75 ++++++++- 3 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 admin/scripts/relatoriosaladiario.php diff --git a/admin/scripts/relatoriosaladiario.php b/admin/scripts/relatoriosaladiario.php new file mode 100644 index 0000000..9658d69 --- /dev/null +++ b/admin/scripts/relatoriosaladiario.php @@ -0,0 +1,234 @@ +Não pode entrar no Painel Administrativo. Voltar para a página inicial"); + } + if (!isset($_SESSION['validity']) || $_SESSION['validity'] < time()) { + http_response_code(403); + header("Location: /login"); + die("A reencaminhar para iniciar sessão..."); + } else { + // A validade da sessão está quase a expirir. Extender a sessão por mais 1h. + if ($_SESSION['validity'] - time() < 900) { + $_SESSION['validity'] = time() + 3600; + } + } +use TCPDF; + +// Handle PDF generation +if (isset($_POST['gerar_pdf'])) { + $data_selecionada = $_POST['data_relatorio'] ?? date('Y-m-d'); + $sala_id = $_POST['sala_id'] ?? null; + + // Validate date + if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $data_selecionada)) { + $data_selecionada = date('Y-m-d'); + } + + // Build query based on room selection + if ($sala_id && $sala_id !== 'todas') { + // Specific room + $stmt = $db->prepare(" + SELECT + s.nome as sala_nome, + t.horashumanos, + c.nome as requisitor_nome, + r.aprovado, + r.motivo + FROM salas s + CROSS JOIN tempos t + LEFT JOIN reservas r ON r.sala = s.id AND r.tempo = t.id AND r.data = ? + LEFT JOIN cache c ON r.requisitor = c.id + WHERE s.id = ? + ORDER BY t.horashumanos ASC + "); + $stmt->bind_param("ss", $data_selecionada, $sala_id); + } else { + // All rooms + $stmt = $db->prepare(" + SELECT + s.nome as sala_nome, + t.horashumanos, + c.nome as requisitor_nome, + r.aprovado, + r.motivo + FROM salas s + CROSS JOIN tempos t + LEFT JOIN reservas r ON r.sala = s.id AND r.tempo = t.id AND r.data = ? + LEFT JOIN cache c ON r.requisitor = c.id + ORDER BY s.nome ASC, t.horashumanos ASC + "); + $stmt->bind_param("s", $data_selecionada); + } + + $stmt->execute(); + $result = $stmt->get_result(); + + // Group data by room + $salas_data = []; + while ($row = $result->fetch_assoc()) { + $sala_nome = $row['sala_nome']; + + if (!isset($salas_data[$sala_nome])) { + $salas_data[$sala_nome] = []; + } + + $salas_data[$sala_nome][] = [ + 'tempo' => $row['horashumanos'], + 'requisitor' => $row['requisitor_nome'], + 'status' => $row['aprovado'], + 'motivo' => $row['motivo'] + ]; + } + $stmt->close(); + + // Start output buffering to prevent any output before PDF + ob_start(); + + // Create PDF + $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + + // Set document information + $pdf->SetCreator('ClassLink'); + $pdf->SetAuthor('Sistema de Reserva de Salas'); + $pdf->SetTitle('Relatório de Utilização de Salas - ' . date('d/m/Y', strtotime($data_selecionada))); + $pdf->SetSubject('Relatório Diário'); + + // Remove default header/footer + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + + // Set margins + $pdf->SetMargins(15, 15, 15); + $pdf->SetAutoPageBreak(TRUE, 25); + + // Add page + $pdf->AddPage(); + + // Set font + $pdf->SetFont('helvetica', 'B', 16); + $pdf->Cell(0, 10, 'Relatório de Utilização de Salas', 0, 1, 'C'); + + $pdf->SetFont('helvetica', '', 11); + $dia_semana_map = [ + 'Monday' => 'Segunda-feira', + 'Tuesday' => 'Terça-feira', + 'Wednesday' => 'Quarta-feira', + 'Thursday' => 'Quinta-feira', + 'Friday' => 'Sexta-feira', + 'Saturday' => 'Sábado', + 'Sunday' => 'Domingo' + ]; + $dia_semana_en = date('l', strtotime($data_selecionada)); + $dia_semana = $dia_semana_map[$dia_semana_en] ?? $dia_semana_en; + + $pdf->Cell(0, 8, 'Data: ' . $dia_semana . ', ' . date('d/m/Y', strtotime($data_selecionada)), 0, 1, 'C'); + $pdf->Ln(5); + + // Display rooms and reservations + foreach ($salas_data as $sala_nome => $tempos) { + $pdf->SetFont('helvetica', 'B', 12); + $pdf->SetFillColor(200, 220, 255); + $pdf->Cell(0, 8, 'Sala: ' . $sala_nome, 0, 1, 'L', true); + + $pdf->SetFont('helvetica', '', 10); + + // Create table for room reservations + $pdf->SetFillColor(240, 240, 240); + $pdf->Cell(40, 7, 'Horário', 1, 0, 'C', true); + $pdf->Cell(50, 7, 'Requisitor', 1, 0, 'C', true); + $pdf->Cell(30, 7, 'Status', 1, 0, 'C', true); + $pdf->Cell(60, 7, 'Motivo', 1, 1, 'C', true); + + $has_reservation = false; + foreach ($tempos as $tempo) { + if ($tempo['requisitor']) { + $has_reservation = true; + $status_label = ''; + $pdf->SetFillColor(255, 255, 255); + + if ($tempo['status'] === null) { + $status_label = 'Pendente'; + $pdf->SetFillColor(255, 255, 200); + } elseif ($tempo['status'] == 1) { + $status_label = 'Aprovado'; + $pdf->SetFillColor(200, 255, 200); + } elseif ($tempo['status'] == 0) { + $status_label = 'Rejeitado'; + $pdf->SetFillColor(255, 200, 200); + } else { + $status_label = 'Cancelado'; + $pdf->SetFillColor(220, 220, 220); + } + + $pdf->Cell(40, 7, $tempo['tempo'], 1, 0, 'L', true); + $pdf->Cell(50, 7, substr($tempo['requisitor'], 0, 25), 1, 0, 'L'); + $pdf->Cell(30, 7, $status_label, 1, 0, 'C', true); + $pdf->Cell(60, 7, substr($tempo['motivo'] ?? '-', 0, 30), 1, 1, 'L'); + } + } + + if (!$has_reservation) { + $pdf->Cell(180, 7, 'Sem reservas', 1, 1, 'C'); + } + + $pdf->Ln(3); + } + + // Add footer with print date and time at the bottom of the last page + $pdf->SetY(-20); + $pdf->SetFont('helvetica', 'I', 9); + $pdf->SetTextColor(128, 128, 128); + + $data_hora_impressao = date('d/m/Y') . ' às ' . date('H:i:s'); + $pdf->Cell(0, 10, 'Impresso em: ' . $data_hora_impressao, 0, 1, 'R'); + + // Log the action + $sala_log = ($sala_id && $sala_id !== 'todas') ? " (Sala específica)" : " (Todas as salas)"; + logaction('Geração de Relatório de Salas Diário para ' . $data_selecionada . $sala_log, $_SESSION['id']); + + // Clear any output buffer and output PDF + ob_end_clean(); + + // Output PDF + $pdf->Output('Relatorio_Salas_' . date('Ymd_His') . '.pdf', 'D'); + exit; +} +require '../index.php'; +?> +
+

Relatório de Utilização de Salas

+

Gere um relatório em PDF da utilização de salas para um dia específico.

+ +
+
+ + +
+ +
+ + +
+ + +
+ +
+

Nota: Este relatório mostra as reservações para a data e sala(s) selecionada(s).

+

O PDF incluirá a data e hora de impressão no rodapé.

+
+
diff --git a/composer.json b/composer.json index 0f0c1a3..569fe49 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "require": { "phpmailer/phpmailer": "^7.0", - "league/oauth2-client": "^2.8" + "league/oauth2-client": "^2.8", + "tecnickcom/tcpdf": "^6.7" } } diff --git a/composer.lock b/composer.lock index bed7af8..7ce3d9e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "74d142af84086da2d0098a2f80689cdd", + "content-hash": "a70c45bc99f49fdb8ac6c62174ccea1a", "packages": [ { "name": "guzzlehttp/guzzle", @@ -748,6 +748,77 @@ } ], "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "tecnickcom/tcpdf", + "version": "6.10.1", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/TCPDF.git", + "reference": "7a2701251e5d52fc3d508fd71704683eb54f5939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/7a2701251e5d52fc3d508fd71704683eb54f5939", + "reference": "7a2701251e5d52fc3d508fd71704683eb54f5939", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=7.1.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "config", + "include", + "tcpdf.php", + "tcpdf_barcodes_1d.php", + "tcpdf_barcodes_2d.php", + "include/tcpdf_colors.php", + "include/tcpdf_filters.php", + "include/tcpdf_font_data.php", + "include/tcpdf_fonts.php", + "include/tcpdf_images.php", + "include/tcpdf_static.php", + "include/barcodes/datamatrix.php", + "include/barcodes/pdf417.php", + "include/barcodes/qrcode.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", + "homepage": "http://www.tcpdf.org/", + "keywords": [ + "PDFD32000-2008", + "TCPDF", + "barcodes", + "datamatrix", + "pdf", + "pdf417", + "qrcode" + ], + "support": { + "issues": "https://github.com/tecnickcom/TCPDF/issues", + "source": "https://github.com/tecnickcom/TCPDF/tree/6.10.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", + "type": "custom" + } + ], + "time": "2025-11-21T10:58:21+00:00" } ], "packages-dev": [], @@ -758,5 +829,5 @@ "prefer-lowest": false, "platform": {}, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } From fc5c138553085122003118c18813b4bf70547299 Mon Sep 17 00:00:00 2001 From: Marco Pisco Date: Fri, 9 Jan 2026 17:06:36 +0000 Subject: [PATCH 2/2] =?UTF-8?q?Adicionar=20cabe=C3=A7alho=20e=20rodap?= =?UTF-8?q?=C3=A9=20personalizados=20ao=20relat=C3=B3rio=20PDF=20de=20util?= =?UTF-8?q?iza=C3=A7=C3=A3o=20de=20salas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/scripts/relatoriosaladiario.php | 72 ++++++++++++++++++++------- 1 file changed, 53 insertions(+), 19 deletions(-) diff --git a/admin/scripts/relatoriosaladiario.php b/admin/scripts/relatoriosaladiario.php index 9658d69..8d2138e 100644 --- a/admin/scripts/relatoriosaladiario.php +++ b/admin/scripts/relatoriosaladiario.php @@ -89,8 +89,53 @@ // Start output buffering to prevent any output before PDF ob_start(); + // Create custom TCPDF class with header and footer + class PDF extends TCPDF { + private $print_datetime; + + public function setPrintDateTime($datetime) { + $this->print_datetime = $datetime; + } + + public function Header() { + // Logo path + $logo_path = __DIR__ . '/../../assets/logo.png'; + + // Add logo if file exists + if (file_exists($logo_path)) { + $this->Image($logo_path, 15, 10, 15, 0, 'PNG', '', 'T', false, 300, '', false, false, 0, false, false, false); + } + + // Set font + $this->SetFont('helvetica', 'B', 18); + $this->SetTextColor(0, 0, 0); + + // Title with logo space + $this->SetY(10); + $this->Cell(0, 15, 'ClassLink', 0, 1, 'C'); + + // Draw a line + $this->SetLineStyle(array('width' => 0.5, 'color' => array(200, 200, 200))); + $this->Line(15, 28, $this->getPageWidth() - 15, 28); + } + + public function Footer() { + // Position at 15 mm from bottom + $this->SetY(-15); + // Set font + $this->SetFont('helvetica', 'I', 9); + $this->SetTextColor(128, 128, 128); + // Print date and time + $this->Cell(0, 10, 'Impresso em: ' . $this->print_datetime, 0, 0, 'R'); + } + } + // Create PDF - $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + $pdf = new PDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); + + // Set the print datetime + $data_hora_impressao = date('d/m/Y') . ' às ' . date('H:i:s'); + $pdf->setPrintDateTime($data_hora_impressao); // Set document information $pdf->SetCreator('ClassLink'); @@ -98,20 +143,17 @@ $pdf->SetTitle('Relatório de Utilização de Salas - ' . date('d/m/Y', strtotime($data_selecionada))); $pdf->SetSubject('Relatório Diário'); - // Remove default header/footer - $pdf->setPrintHeader(false); - $pdf->setPrintFooter(false); - - // Set margins - $pdf->SetMargins(15, 15, 15); - $pdf->SetAutoPageBreak(TRUE, 25); + // Set margins (top margin increased for header) + $pdf->SetMargins(15, 32, 15); + $pdf->SetAutoPageBreak(TRUE, 20); // Add page $pdf->AddPage(); - // Set font - $pdf->SetFont('helvetica', 'B', 16); - $pdf->Cell(0, 10, 'Relatório de Utilização de Salas', 0, 1, 'C'); + // Set font for report title + $pdf->SetFont('helvetica', 'B', 14); + $pdf->SetTextColor(0, 0, 0); + $pdf->Cell(0, 8, 'Relatório de Utilização de Salas', 0, 1, 'C'); $pdf->SetFont('helvetica', '', 11); $dia_semana_map = [ @@ -179,14 +221,6 @@ $pdf->Ln(3); } - // Add footer with print date and time at the bottom of the last page - $pdf->SetY(-20); - $pdf->SetFont('helvetica', 'I', 9); - $pdf->SetTextColor(128, 128, 128); - - $data_hora_impressao = date('d/m/Y') . ' às ' . date('H:i:s'); - $pdf->Cell(0, 10, 'Impresso em: ' . $data_hora_impressao, 0, 1, 'R'); - // Log the action $sala_log = ($sala_id && $sala_id !== 'todas') ? " (Sala específica)" : " (Todas as salas)"; logaction('Geração de Relatório de Salas Diário para ' . $data_selecionada . $sala_log, $_SESSION['id']);