En este momento estás viendo Sistema de gimnasio con Codeigniter 4 y MySQL

Sistema de gimnasio con Codeigniter 4 y MySQL

Sistema de Gestión para Gimnasios, desarrollado con CodeIgniter 4 y MySQL, ideal para administrar de forma eficiente todas las operaciones de un centro deportivo.

🚀 ¿Qué incluye este sistema?

✔️ Registro y control de usuarios

✔️ Gestión de membresías y planes de pago

✔️ Control de asistencia diaria

✔️ Reportes de ingresos y membresías activas

✔️ Historial de pagos y suscripciones

✔️ Panel administrativo con estadísticas gráficas

🛠️ Tecnologías utilizadas: Backend: CodeIgniter 4 (framework PHP moderno, ligero y seguro) Base de datos: MySQL Frontend: HTML, Bootstrap 5, (personalizable y responsive).

Ticket de Pago

Dompdf
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <style>
    *{
        margin: 0;
        padding: 0;
    }
    body {
        font-family: "DejaVu Sans", sans-serif;
        font-size: 10px;
        margin: 0;
        padding: 0;
        width: 100%;
    }
    .ticket {
        padding: 10px;
    }
    .logo {
        text-align: center;
        margin-bottom: 5px;
    }
    .logo img {
        width: 80px;
        height: auto;
    }
    .center {
        text-align: center;
    }
    .bold {
        font-weight: bold;
    }
    .title {
        font-size: 14px;
    }
    .subtitle {
        font-size: 11px;
    }
    .line {
        border-top: 1px dashed #000;
        margin: 8px 0;
    }
    table {
        width: 100%;
    }
    td {
        vertical-align: top;
    }
    .totales td {
        font-size: 11px;
        padding: 2px 0;
    }
    .totales .label {
        font-weight: bold;
    }
    .footer {
        text-align: center;
        font-size: 9px;
        margin-top: 10px;
        font-style: italic;
    }
  </style>
</head>
<body>
  <div class="ticket">
    <div class="logo">
      <img src="logo.png" alt="Logo">
    </div>
    <div class="center bold title">GIMNASIO ELITE FITNESS</div>
    <div class="center subtitle">RUC: 12345678901</div>
    <div class="center">Av. Ejemplo 123 - Lima</div>
    <div class="center">Tel: 987 654 321</div>

    <div class="line"></div>

    <div><strong>Fecha:</strong> 2025-06-19 10:23 AM</div>
    <div><strong>Cliente:</strong> Juan Pérez</div>
    <div><strong>DNI:</strong> 12345678</div>
    <div><strong>Atendido por:</strong> Admin</div>

    <div class="line"></div>

    <table>
      <tr>
        <td>Membresía Mensual</td>
        <td style="text-align: right;">S/ 100.00</td>
      </tr>
    </table>

    <div class="line"></div>

    <table class="totales">
      <tr>
        <td class="label">TOTAL</td>
        <td style="text-align: right;" class="label">S/ 100.00</td>
      </tr>
      <tr>
        <td>Efectivo</td>
        <td style="text-align: right;">S/ 100.00</td>
      </tr>
      <tr>
        <td>Cambio</td>
        <td style="text-align: right;">S/ 0.00</td>
      </tr>
    </table>

    <div class="line"></div>

    <div class="footer">
      ¡Gracias por su pago!<br>
      Su compromiso con la salud es nuestra motivación.
    </div>
  </div>
</body>
</html>

Logo en ticket con DOMPDF

  • Es muy importantes tener activo la extensión gd de PHP para mostrar imágenes en el pdf.
  • Agregar las opciones a dompdf
  • Agregar la ruta absoluta de la imagen.
use Dompdf\Dompdf;
use Dompdf\Options;

$options = new Options();
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);

Reportes de Movimientos

Caja – Pagos
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <style>
        body {
            font-family: Arial, sans-serif;
            font-size: 12px;
            margin: 20px;
            color: #444;
        }

        .header {
            display: flex;
            align-items: center;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 10px;
            margin-bottom: 20px;
        }

        .header img {
            width: 80px;
            margin-right: 20px;
        }

        .header .company-info {
            font-size: 14px;
        }

        .title {
            background-color: #4CAF50;
            color: white;
            padding: 6px;
            margin-bottom: 8px;
            font-weight: bold;
        }

        .box {
            border: 1px solid #ddd;
            border-radius: 6px;
            padding: 10px;
            margin-bottom: 15px;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 8px;
        }

        th {
            background-color: #E0F2F1;
            color: #00695C;
            text-align: left;
            padding: 6px;
        }

        td {
            padding: 6px;
            border-bottom: 1px solid #eee;
        }

        .total-row {
            font-weight: bold;
            background-color: #F1F8E9;
        }

        .highlight {
            color: #388E3C;
            font-weight: bold;
        }
    </style>
</head>
<body>

<div class="header">
    <img src="<?= base_url('uploads/logo.png') ?>" alt="Logo">
    <div class="company-info">
        <strong>Mi Empresa S.A.</strong><br>
        RUC: 12345678901<br>
        Dirección: Av. Principal 123, Lima<br>
        Teléfono: (01) 234-5678
    </div>
</div>

<div class="box">
    <div class="title">Monto Inicial y Gastos</div>
    <table>
        <tr>
            <th>Monto Inicial</th>
            <th>Gastos</th>
        </tr>
        <tr>
            <td>S/ 90,000.00</td>
            <td>S/ 0.00</td>
        </tr>
    </table>
</div>

<div class="box">
    <div class="title">Ventas por Método de Pago</div>
    <table>
        <tr>
            <th>Método de Pago</th>
            <th>Total</th>
        </tr>
        <tr>
            <td></td>
            <td>S/ 0.00</td>
        </tr>
        <tr class="total-row">
            <td>Total General</td>
            <td class="highlight">S/ 0.00</td>
        </tr>
    </table>
</div>

<div class="box">
    <div class="title">Membresías por Método de Pago</div>
    <table>
        <tr>
            <th>Método de Pago</th>
            <th>Total</th>
        </tr>
        <tr>
            <td>Efectivo</td>
            <td>S/ 150.00</td>
        </tr>
        <tr class="total-row">
            <td>Total General</td>
            <td class="highlight">S/ 150.00</td>
        </tr>
    </table>
</div>

<div class="box">
    <div class="title">Resumen del Cuadre de Caja</div>
    <table>
        <tr>
            <td>Monto Inicial</td>
            <td>S/ 90,000.00</td>
        </tr>
        <tr>
            <td>Total Métodos de Pago</td>
            <td>S/ 0.00</td>
        </tr>
        <tr>
            <td>Gastos</td>
            <td>S/ 0.00</td>
        </tr>
        <tr>
            <td>Pagos Membresías</td>
            <td>S/ 150.00</td>
        </tr>
        <tr class="total-row">
            <td>Saldo Restante</td>
            <td class="highlight">S/ 90,150.00</td>
        </tr>
    </table>
</div>

</body>
</html>

CREAR CÓDIGO QR.

https://github.com/endroid/qr-code
$qrName = uniqid($user['username'] . '_');
            $directorio = 'images/qrcodes/' . $qrName . '.png';
            $companyModel = new CompanyModel();
            $company = $companyModel->select('name')->first();
            //CREAR CODIGO QR
            $builder = new Builder(
                writer: new PngWriter(),
                writerOptions: [],
                validateResult: false,
                data: $qrName,
                encoding: new Encoding('UTF-8'),
                errorCorrectionLevel: ErrorCorrectionLevel::High,
                size: 300,
                margin: 10,
                roundBlockSizeMode: RoundBlockSizeMode::Margin,
                logoPath: base_url('/images/logo.png'),
                logoResizeToWidth: 50,
                logoPunchoutBackground: true,
                labelText: $company['name'],
                labelFont: new OpenSans(20),
                labelAlignment: LabelAlignment::Center
            );

            $result = $builder->build();
            $result->saveToFile($directorio);

Descargar CARD con Canvas

https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js
html2canvas(document.querySelector('.profile-card-3')).then(function (canvas) {
    // Crea un enlace para descargar la imagen
    let link = document.createElement('a');
    link.download = 'tarjeta.png';
    link.href = canvas.toDataURL();
    link.click();
});

Modal Tarjeta

<div class="modal fade" id="modalTarjeta" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" role="dialog" aria-labelledby="modalTitleId" aria-hidden="true">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="modalTitleId">
                    Tarjeta
                </h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div class="text-center">
                    <button id="download-btn" class="btn btn-primary btn-sm">Descargar Tarjeta</button>
                </div>
                <hr>
                <div class="row">
                    <div class="col-md-8 mx-auto">
                        <div class="card profile-card-3">
                            <div class="background-block"></div>
                            <div class="profile-thumb-block">
                                <img id="card-avatar" src="https://randomuser.me/api/portraits/men/78.jpg" alt="profile-image" class="profile" />
                            </div>
                            <div class="card-content">
                                <h2 id="card-name"></h2>
                                <div class="icon-block">
                                    <img id="card-qr" class="img-thumbnail" src="https://randomuser.me/api/portraits/men/78.jpg" alt="qr-image" />
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

Estilos Tarjeta

css
/*Profile Card 3*/
.profile-card-3 {
    font-family: "Open Sans", Arial, sans-serif;
    position: relative;
    float: left;
    overflow: hidden;
    width: 100%;
    text-align: center;
    border: none;
}

.profile-card-3 .background-block {
    float: left;
    width: 100%;
    height: 180px;
    background: #000;
}

.profile-card-3 .card-content {
    width: 100%;
    padding: 15px 25px;
    color: #232323;
    float: left;
    background: #efefef;
    height: 50%;
    border-radius: 0 0 5px 5px;
    position: relative;
    z-index: 9999;
}

.profile-card-3 .card-content::before {
    content: "";
    background: #efefef;
    width: 120%;
    height: 100%;
    left: 11px;
    bottom: 51px;
    position: absolute;
    z-index: -1;
    transform: rotate(-13deg);
}

.profile-card-3 .profile {
    border-radius: 50%;
    position: absolute;
    top: 15%;
    left: 50%;
    max-width: 100px;
    opacity: 1;
    box-shadow: 3px 3px 20px rgba(0, 0, 0, 0.5);
    border: 2px solid rgba(255, 255, 255, 1);
    -webkit-transform: translate(-50%, 0%);
    transform: translate(-50%, 0%);
    z-index: 99999;
}

.profile-card-3 h2 {
    margin: 0 0 5px;
    font-weight: 600;
    font-size: 25px;
}

.profile-card-3 h2 small {
    display: block;
    font-size: 15px;
    margin-top: 10px;
}

.profile-card-3 i {
    display: inline-block;
    font-size: 16px;
    color: #232323;
    text-align: center;
    border: 1px solid #232323;
    width: 30px;
    height: 30px;
    line-height: 30px;
    border-radius: 50%;
    margin: 0 5px;
}

.profile-card-3 .icon-block {
    float: left;
    width: 100%;
    margin-top: 15px;
}

.profile-card-3 .icon-block a {
    text-decoration: none;
}

.profile-card-3 i:hover {
    background-color: #232323;
    color: #fff;
    text-decoration: none;
}

Deja una respuesta