git pyfleet en gitea.xiberus

This commit is contained in:
2026-08-28 19:30:48 +02:00
commit 89992823b4
2133 changed files with 27616 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
{% extends "base.html" %}
{% block title %}{{ 'Editar' if campus else 'Nuevo' }} Campus{% endblock %}
{% block content %}
<div class="page-header">
<div class="page-eyebrow">Campus</div>
<div class="page-title">{{ 'Editar campus' if campus else 'Nuevo campus' }}</div>
<div class="page-subtitle">
{{ 'Modifica los datos del campus #' ~ campus['id'] if campus else 'Completa el formulario para registrar un nuevo campus.' }}
</div>
</div>
<div class="form-card">
<form method="POST">
{% if campus %}
<div class="form-group">
<label class="form-label">ID</label>
<input class="form-input" type="text" value="#{{ campus['id'] }}" disabled>
</div>
{% endif %}
<div class="form-group">
<label class="form-label" for="nombre">Nombre *</label>
<input
class="form-input"
type="text"
id="nombre"
name="nombre"
placeholder="Ej. Campus Norte"
value="{{ campus['nombre'] if campus else request.form.get('nombre','') }}"
required
autofocus
>
</div>
<div class="form-group">
<label class="form-label" for="telefono">Teléfono *</label>
<input
class="form-input"
type="tel"
id="telefono"
name="telefono"
placeholder="Ej. +52 55 1234 5678"
value="{{ campus['telefono'] if campus else request.form.get('telefono','') }}"
required
>
</div>
<div class="form-group">
<label class="form-label" for="email">Email *</label>
<input
class="form-input"
type="email"
id="email"
name="email"
placeholder="Ej. [email protected]"
value="{{ campus['email'] if campus else request.form.get('email','') }}"
required
>
</div>
<div class="form-group">
<label class="form-label" for="categoria_id">Categoría</label>
<div class="select-wrap">
<select class="form-input form-select" id="categoria_id" name="categoria_id">
<option value="">— Sin categoría —</option>
{% for cat in categorias %}
<option value="{{ cat['id'] }}"
{% if campus and campus['categoria_id'] == cat['id'] %}selected
{% elif request.form.get('categoria_id') == cat['id']|string %}selected
{% endif %}>
{{ cat['tipo'] }}
</option>
{% endfor %}
</select>
<svg class="select-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<polyline points="6 9 12 15 18 9"/>
</svg>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
{{ '💾 Guardar cambios' if campus else '✚ Crear campus' }}
</button>
<a href="{{ url_for('campus_list') }}" class="btn btn-ghost">Cancelar</a>
</div>
</form>
</div>
{% endblock %}
+120
View File
@@ -0,0 +1,120 @@
{% extends "base.html" %}
{% block title %}Campus{% endblock %}
{% block content %}
<div class="page-header">
<div class="page-eyebrow">Base de datos</div>
<div class="page-title">Campus</div>
<div class="page-subtitle">Gestiona los registros de campus: búsqueda, alta, edición y baja.</div>
</div>
<div class="crud-toolbar">
<form method="GET" action="{{ url_for('campus_list') }}" class="search-wrap" id="searchForm">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input
type="text"
name="q"
id="searchInput"
placeholder="Buscar por ID, nombre, teléfono o email…"
value="{{ q }}"
autocomplete="off"
>
</form>
<a href="{{ url_for('campus_nuevo') }}" class="btn btn-primary">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
Nuevo campus
</a>
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Teléfono</th>
<th>Email</th>
<th>Categoría</th>
<th style="text-align:right">Acciones</th>
</tr>
</thead>
<tbody id="tbody">
{% if rows %}
{% for r in rows %}
<tr data-id="{{ r['id'] }}">
<td class="td-id">#{{ r['id'] }}</td>
<td><strong>{{ r['nombre'] }}</strong></td>
<td>{{ r['telefono'] }}</td>
<td>{{ r['email'] }}</td>
<td>{% if r['categoria'] %}<span style="background:rgba(92,110,248,.12);color:var(--accent);font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;border:1px solid rgba(92,110,248,.25)">{{ r['categoria'] }}</span>{% else %}<span style="color:var(--muted);font-size:12px">—</span>{% endif %}</td>
<!-- <td>{{ r['categoria'] }}</td> -->
<td>
<div class="td-actions" style="justify-content:flex-end">
<a href="{{ url_for('campus_editar', id=r['id']) }}" class="btn btn-ghost btn-sm">Editar</a>
<form method="POST" action="{{ url_for('campus_eliminar', id=r['id']) }}"
onsubmit="return confirm('¿Eliminar «{{ r['nombre'] }}»? Esta acción no se puede deshacer.')">
<button type="submit" class="btn btn-danger btn-sm">Eliminar</button>
</form>
</div>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="5">
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/>
</svg>
{% if q %}
No se encontraron resultados para <strong>"{{ q }}"</strong>.
<br><a href="{{ url_for('campus_list') }}" style="color:var(--accent);text-decoration:none">Ver todos</a>
{% else %}
No hay campus registrados aún.
{% endif %}
</div>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% if rows %}
<p id="counter" style="margin-top:12px;font-size:12px;color:var(--muted)">
{{ rows|length }} registro{{ 's' if rows|length != 1 }}
{% if q %} — filtrado por «{{ q }}»{% endif %}
</p>
{% endif %}
<script>
var input = document.getElementById('searchInput');
var tbody = document.getElementById('tbody');
var counter = document.getElementById('counter');
var timer;
/* Actualiza la tabla sin recargar la página (el foco no se pierde) */
input.addEventListener('input', function() {
clearTimeout(timer);
timer = setTimeout(function() { buscar(input.value.trim()); }, 300);
});
function buscar(q) {
var url = '{{ url_for("campus_list") }}?q=' + encodeURIComponent(q) + '&solo_filas=1';
fetch(url)
.then(function(r) { return r.text(); })
.then(function(html) {
tbody.innerHTML = html;
if (counter) {
var filas = tbody.querySelectorAll('tr[data-id]').length;
counter.textContent = filas + ' registro' + (filas !== 1 ? 's' : '')
+ (q ? ' — filtrado por «' + q + '»' : '');
counter.style.display = filas ? '' : 'none';
}
});
}
</script>
{% endblock %}
+35
View File
@@ -0,0 +1,35 @@
{% if rows %}
{% for r in rows %}
<tr data-id="{{ r['id'] }}">
<td class="td-id">#{{ r['id'] }}</td>
<td><strong>{{ r['nombre'] }}</strong></td>
<td>{{ r['telefono'] }}</td>
<td>{{ r['email'] }}</td>
<td>{% if r['categoria'] %}<span style="background:rgba(92,110,248,.12);color:var(--accent);font-size:11px;font-weight:600;padding:3px 9px;border-radius:20px;border:1px solid rgba(92,110,248,.25)">{{ r['categoria'] }}</span>{% else %}<span style="color:var(--muted);font-size:12px">—</span>{% endif %}</td>
<td>
<div class="td-actions" style="justify-content:flex-end">
<a href="/campus/{{ r['id'] }}/editar" class="btn btn-ghost btn-sm">Editar</a>
<form method="POST" action="/campus/{{ r['id'] }}/eliminar"
onsubmit="return confirm('¿Eliminar «{{ r['nombre'] }}»? Esta acción no se puede deshacer.')">
<button type="submit" class="btn btn-danger btn-sm">Eliminar</button>
</form>
</div>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="5">
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<circle cx="12" cy="12" r="10"/><line x1="8" y1="12" x2="16" y2="12"/>
</svg>
{% if q %}
No se encontraron resultados para <strong>"{{ q }}"</strong>.
{% else %}
No hay campus registrados aún.
{% endif %}
</div>
</td>
</tr>
{% endif %}