mirror of
https://github.com/marcogll/ap_pos.git
synced 2026-01-13 21:25:16 +00:00
466 lines
19 KiB
HTML
466 lines
19 KiB
HTML
<!doctype html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title>Ale Ponce | AlMa</title>
|
|
<!-- Favicon SVG -->
|
|
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23444' d='M20 4H4c-1.11 0-1.99.89-1.99 2L2 18c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V6c0-1.11-.89-2-2-2zm0 14H4V6h16v12zM6 10h2v4H6zm3 0h2v4H9zm3 0h2v4h-2zm3 0h2v4h-2z'/%3E%3C/svg%3E">
|
|
<!-- Google Fonts & Icons -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600&family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Material+Icons+Outlined" rel="stylesheet">
|
|
<!-- Styles -->
|
|
<link rel="stylesheet" href="styles.css?v=1.4" />
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
</head>
|
|
<body>
|
|
<main class="container">
|
|
<header class="main-header">
|
|
<!-- Logo del negocio en lugar de texto -->
|
|
<img src="src/logo.png" alt="Ale Ponce" class="header-logo">
|
|
<nav class="tabs">
|
|
<button type="button" class="tab-link" data-tab="tab-dashboard">
|
|
<span class="material-icons-outlined">dashboard</span><span>Dashboard</span>
|
|
</button>
|
|
<button type="button" class="tab-link" data-tab="tab-movements">
|
|
<span class="material-icons-outlined">receipt_long</span><span>Ventas</span>
|
|
</button>
|
|
<button type="button" class="tab-link" data-tab="tab-clients">
|
|
<span class="material-icons-outlined">groups</span><span>Clientes</span>
|
|
</button>
|
|
<button type="button" class="tab-link" data-tab="tab-products">
|
|
<span class="material-icons-outlined">inventory_2</span><span>Productos</span>
|
|
</button>
|
|
<button type="button" class="tab-link" data-tab="tab-settings">
|
|
<span class="material-icons-outlined">settings</span><span>Configuración</span>
|
|
</button>
|
|
</nav>
|
|
<button type="button" id="btnLogout" class="btn-icon btn-danger">
|
|
<span class="material-icons-outlined">logout</span>
|
|
</button>
|
|
</header>
|
|
|
|
<!-- Pestaña de Dashboard -->
|
|
<div id="tab-dashboard" class="tab-content">
|
|
<div class="section">
|
|
<h2>Dashboard</h2>
|
|
<div class="dashboard-stats">
|
|
<div class="stat-card">
|
|
<h3>Ingresos Totales</h3>
|
|
<p id="stat-total-income">$0.00</p>
|
|
</div>
|
|
<div class="stat-card">
|
|
<h3>Servicios Realizados</h3>
|
|
<p id="stat-total-movements">0</p>
|
|
</div>
|
|
</div>
|
|
<div class="dashboard-grid">
|
|
<div class="dashboard-chart">
|
|
<h3>Ingresos por Servicio</h3>
|
|
<canvas id="incomeChart"></canvas>
|
|
</div>
|
|
<div class="dashboard-chart">
|
|
<h3>Ingresos por Método de Pago</h3>
|
|
<canvas id="paymentMethodChart"></canvas>
|
|
</div>
|
|
</div>
|
|
<div class="section">
|
|
<h3>Próximas Citas</h3>
|
|
<div id="upcoming-appointments-list" class="appointments-list">
|
|
<!-- Las citas se renderizarán aquí -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pestaña de Movimientos/Recibos -->
|
|
<div id="tab-movements" class="tab-content">
|
|
<div class="section">
|
|
<h2>Nuevo Movimiento</h2>
|
|
<form id="formMove">
|
|
<div class="form-grid">
|
|
<label>Cliente:</label>
|
|
<div>
|
|
<input type="text" id="m-cliente" list="client-list" required autocomplete="off" />
|
|
<datalist id="client-list"></datalist>
|
|
</div>
|
|
<label>Categoría:</label>
|
|
<select id="m-categoria" required>
|
|
<option value="service">Servicio</option>
|
|
<option value="course">Curso</option>
|
|
</select>
|
|
<label>Artículo:</label>
|
|
<select id="m-articulo" required>
|
|
</select>
|
|
<div id="m-subtipo-container" class="hidden">
|
|
<label>Subtipo:</label>
|
|
<select id="m-subtipo">
|
|
<option value="Servicio">Servicio</option>
|
|
<option value="Retoque">Retoque</option>
|
|
</select>
|
|
</div>
|
|
<label>Fecha de Cita:</label>
|
|
<input type="date" id="m-fecha-cita" />
|
|
<label>Hora de Cita:</label>
|
|
<input type="time" id="m-hora-cita" />
|
|
<label>Monto (MXN):</label><input type="number" id="m-monto" step="0.01" min="0" required />
|
|
<label>Método:</label>
|
|
<select id="m-metodo">
|
|
<option value="">-- Opcional --</option>
|
|
<option value="Efectivo">Efectivo</option>
|
|
<option value="Tarjeta">Tarjeta</option>
|
|
<option value="Transferencia">Transferencia</option>
|
|
<option value="Depósito">Depósito</option>
|
|
<option value="Otros">Otros</option>
|
|
</select>
|
|
<label>Concepto:</label><input type="text" id="m-concepto" />
|
|
<label>Atendió:</label><input type="text" id="m-staff" />
|
|
<label>Notas:</label><textarea id="m-notas" rows="2"></textarea>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit">Guardar y Generar Recibo</button>
|
|
<button type="reset" class="btn-danger">Limpiar</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h2>Movimientos Recientes</h2>
|
|
<button id="btnExport" class="btn-secondary">Exportar a CSV</button>
|
|
<div class="table-wrapper">
|
|
<table id="tblMoves">
|
|
<thead>
|
|
<tr>
|
|
<th>Folio</th>
|
|
<th>Fecha</th>
|
|
<th>Cita</th>
|
|
<th>Cliente</th>
|
|
<th>Servicio</th>
|
|
<th>Monto</th>
|
|
<th>Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pestaña de Clientes -->
|
|
<div id="tab-clients" class="tab-content">
|
|
<div class="sub-tabs">
|
|
<button type="button" class="sub-tab-link active" data-subtab="sub-tab-register">Registro de Cliente</button>
|
|
<button type="button" class="sub-tab-link" data-subtab="sub-tab-consult">Consulta de Clientes</button>
|
|
</div>
|
|
|
|
<!-- Sub-Pestaña de Registro -->
|
|
<div id="sub-tab-register" class="sub-tab-content active">
|
|
<div class="section">
|
|
<h2>Registrar Nuevo Cliente</h2>
|
|
<form id="formClient">
|
|
<input type="hidden" id="c-id" />
|
|
<div class="form-grid-single">
|
|
<label for="c-nombre">Nombre:</label>
|
|
<input type="text" id="c-nombre" required />
|
|
|
|
<label for="c-telefono">Teléfono:</label>
|
|
<input type="tel" id="c-telefono" />
|
|
|
|
<label for="c-genero">Género:</label>
|
|
<select id="c-genero">
|
|
<option value="">-- Seleccionar --</option>
|
|
<option value="Mujer">Mujer</option>
|
|
<option value="Hombre">Hombre</option>
|
|
</select>
|
|
|
|
<label for="c-cumple">Cumpleaños:</label>
|
|
<input type="date" id="c-cumple" />
|
|
|
|
<div class="checkbox-container">
|
|
<input type="checkbox" id="c-consent" />
|
|
<label for="c-consent">¿Consentimiento médico informado completo?</label>
|
|
</div>
|
|
|
|
<div class="checkbox-container">
|
|
<input type="checkbox" id="c-esOncologico" />
|
|
<label for="c-esOncologico">¿Es paciente oncológico?</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Campos condicionales para paciente oncológico -->
|
|
<div id="oncologico-fields" class="sub-section hidden">
|
|
<h3>Información Oncológica</h3>
|
|
<div class="form-grid-single">
|
|
<div class="checkbox-container">
|
|
<input type="checkbox" id="c-oncologoAprueba" />
|
|
<label for="c-oncologoAprueba">¿Oncólogo aprueba procedimiento?</label>
|
|
</div>
|
|
|
|
<label for="c-nombreMedico">Nombre del Médico:</label>
|
|
<input type="text" id="c-nombreMedico" />
|
|
|
|
<label for="c-telefonoMedico">Teléfono del Médico:</label>
|
|
<input type="tel" id="c-telefonoMedico" />
|
|
|
|
<label for="c-cedulaMedico">Cédula Profesional:</label>
|
|
<input type="text" id="c-cedulaMedico" />
|
|
|
|
<div class="checkbox-container">
|
|
<input type="checkbox" id="c-pruebaAprobacion" />
|
|
<label for="c-pruebaAprobacion">¿Presenta prueba de aprobación?</label>
|
|
</div>
|
|
|
|
<p class="data-location-info">
|
|
El consentimiento del médico debe ser presentado físicamente antes de la evaluación.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="client-courses-section" class="sub-section">
|
|
<h3>Cursos Registrados</h3>
|
|
<div id="client-courses-list"></div>
|
|
<button type="button" id="btnAddCourseToClient" class="btn-secondary">Registrar Curso</button>
|
|
</div>
|
|
|
|
<div class="form-actions-single">
|
|
<button type="submit">Guardar Cliente</button>
|
|
<button type="reset" id="btnCancelEditClient" class="btn-danger">Limpiar</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sub-Pestaña de Consulta -->
|
|
<div id="sub-tab-consult" class="sub-tab-content">
|
|
<div class="section">
|
|
<div class="consult-grid">
|
|
<div class="client-list-container">
|
|
<h2>Lista de Clientes</h2>
|
|
<input type="text" id="search-client" placeholder="Buscar por nombre o teléfono..." />
|
|
<div class="table-wrapper">
|
|
<table id="tblClients">
|
|
<thead>
|
|
<tr>
|
|
<th>Nombre</th>
|
|
<th>Teléfono</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div id="client-record-container" class="client-record-container">
|
|
<h2>Expediente del Cliente</h2>
|
|
<div id="client-record-content" class="hidden">
|
|
<div id="client-details"></div>
|
|
<h3>Historial de Servicios</h3>
|
|
<div id="client-history-table-container" class="table-wrapper">
|
|
<table id="client-history-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Folio</th>
|
|
<th>Fecha</th>
|
|
<th>Servicio</th>
|
|
<th>Monto</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
<h3>Historial de Cursos</h3>
|
|
<div id="client-courses-history-container" class="table-wrapper">
|
|
<!-- Course history will be rendered here -->
|
|
</div>
|
|
<div class="form-actions-single">
|
|
<button id="btn-edit-client" class="btn-secondary">Editar Cliente</button>
|
|
<button id="btn-delete-client" class="btn-danger">Eliminar Cliente</button>
|
|
</div>
|
|
</div>
|
|
<div id="client-record-placeholder">
|
|
<p>Selecciona un cliente de la lista para ver su expediente.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pestaña de Productos -->
|
|
<div id="tab-products" class="tab-content">
|
|
<div class="section">
|
|
<h2>Gestión de Productos y Cursos</h2>
|
|
<div class="sub-section">
|
|
<h3>Añadir/Editar</h3>
|
|
<form id="formProduct">
|
|
<input type="hidden" id="p-id" />
|
|
<div class="form-grid">
|
|
<label>Nombre:</label>
|
|
<input type="text" id="p-name" required />
|
|
<label>Tipo:</label>
|
|
<select id="p-type" required>
|
|
<option value="service">Servicio</option>
|
|
<option value="course">Curso</option>
|
|
</select>
|
|
<label>Precio (MXN):</label>
|
|
<input type="number" id="p-price" step="0.01" min="0" />
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit">Guardar</button>
|
|
<button type="reset" id="btnCancelEditProduct" class="btn-danger">Cancelar</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<hr class="section-divider">
|
|
|
|
<div class="sub-section">
|
|
<h3>Servicios</h3>
|
|
<div class="table-wrapper">
|
|
<table id="tblServices">
|
|
<thead>
|
|
<tr>
|
|
<th>Nombre</th>
|
|
<th>Precio</th>
|
|
<th>Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<hr class="section-divider">
|
|
|
|
<div class="sub-section">
|
|
<h3>Cursos</h3>
|
|
<div class="table-wrapper">
|
|
<table id="tblCourses">
|
|
<thead>
|
|
<tr>
|
|
<th>Nombre</th>
|
|
<th>Precio</th>
|
|
<th>Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pestaña de Configuración -->
|
|
<div id="tab-settings" class="tab-content">
|
|
<div class="section">
|
|
<h2>Configuración del Negocio</h2>
|
|
<form id="formSettings">
|
|
<div class="form-grid">
|
|
<label>Nombre del negocio:</label><input type="text" id="s-negocio" required />
|
|
<label>Eslogan (opcional):</label><input type="text" id="s-tagline" />
|
|
<label>Calle y Número:</label><input type="text" id="s-calle" placeholder="Ej: Av. Siempre Viva 123" />
|
|
<label>Colonia y C.P.:</label><input type="text" id="s-colonia-cp" placeholder="Ej: Centro, 25000" />
|
|
<label>Teléfono:</label><input type="text" id="s-tel" />
|
|
<label>RFC:</label><input type="text" id="s-rfc" />
|
|
<label>Leyenda pie de ticket:</label><input type="text" id="s-leyenda" />
|
|
<label>Prefijo de folio:</label><input type="text"id="s-folioPrefix" />
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit">Guardar Configuración</button>
|
|
<button type="button" id="btnTestTicket" class="btn-secondary">Probar Ticket</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="section" id="credentials-section">
|
|
<h2>Mis Credenciales</h2>
|
|
<form id="formCredentials">
|
|
<div class="form-grid">
|
|
<label>Mi Nombre:</label>
|
|
<input type="text" id="s-name" required />
|
|
<label>Mi Usuario:</label>
|
|
<input type="text" id="s-username" required />
|
|
<label>Nueva Contraseña:</label>
|
|
<input type="password" id="s-password" placeholder="Dejar en blanco para no cambiar" />
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit">Guardar Credenciales</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<!-- Sección de Gestión de Usuarios (Solo para Admins) -->
|
|
<div class="section" id="user-management-section" style="display: none;">
|
|
<h2>Gestión de Usuarios</h2>
|
|
<div class="sub-section">
|
|
<h3>Añadir/Editar Usuario</h3>
|
|
<form id="formAddUser">
|
|
<input type="hidden" id="u-id" />
|
|
<div class="form-grid">
|
|
<label>Nombre:</label>
|
|
<input type="text" id="u-name" required />
|
|
<label>Usuario:</label>
|
|
<input type="text" id="u-username" required />
|
|
<label>Contraseña:</label>
|
|
<input type="password" id="u-password" placeholder="Dejar en blanco para no cambiar" />
|
|
<label>Rol:</label>
|
|
<select id="u-role">
|
|
<option value="user">Usuario (Ventas)</option>
|
|
<option value="admin">Administrador</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit">Guardar Usuario</button>
|
|
<button type="reset" id="btnCancelEditUser" class="btn-danger">Cancelar Edición</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="sub-section">
|
|
<h3>Usuarios Existentes</h3>
|
|
<div class="table-wrapper">
|
|
<table id="tblUsers">
|
|
<thead>
|
|
<tr>
|
|
<th>Nombre</th>
|
|
<th>Usuario</th>
|
|
<th>Rol</th>
|
|
<th>Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Los usuarios se insertarán aquí -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="section" id="db-location-section">
|
|
<h2>Ubicación y Exportación de Datos
|
|
<span class="material-icons-outlined info-icon" id="db-info-icon" style="display: none;">help_outline</span>
|
|
</h2>
|
|
<div id="db-instructions" class="data-location-info hidden">
|
|
<p>Toda la información de tu negocio (clientes, recibos, configuración) se guarda localmente. Para respaldar tus datos, simplemente copia el archivo correspondiente.</p>
|
|
<p>Para usuarios avanzados, la base de datos (<code>ap-pos.db</code>) se encuentra dentro del contenedor de la aplicación. Puedes acceder a ella usando los comandos estándar de Docker para copiar el archivo.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<footer class="main-footer">
|
|
<div class="footer-logos">
|
|
<img src="src/logo_dev.png" alt="Marco Gallegos">
|
|
<img src="src/logo_gemini.png" alt="Google Gemini">
|
|
</div>
|
|
<div class="footer-info">
|
|
<p>Marco Gallegos | Creado con Google Gemini ®</p>
|
|
<p id="footer-date"></p>
|
|
<p id="footer-version"></p>
|
|
</div>
|
|
</footer>
|
|
|
|
<div id="printArea" class="no-print"></div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/qrcode@1/build/qrcode.min.js"></script>
|
|
<script type="module" src="app.js?v=1.3"></script>
|
|
</body>
|
|
</html> |