git pyfleet en gitea.xiberus
This commit is contained in:
Executable
+230
@@ -0,0 +1,230 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Via-T{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<div class="page-eyebrow">Gestión</div>
|
||||
<div class="page-title">Via-T</div>
|
||||
<div class="page-subtitle">Listado de vehículos con dispositivo Via-T. Búsqueda por Via-T, m.oficial, m.civil, marca, modelo, poblacion, unidad tipo.</div>
|
||||
</div>
|
||||
|
||||
<div class="crud-toolbar">
|
||||
<div class="search-wrap" style="max-width:420px;flex:1;">
|
||||
<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" id="searchInput"
|
||||
placeholder="Buscar… palabras separadas por comas"
|
||||
value="{{ q }}" autocomplete="off" style="padding-right:32px;" autofocus>
|
||||
<button type="button" id="clearBtn"
|
||||
style="display:{{ 'flex' if q else 'none' }};position:absolute;right:10px;top:50%;
|
||||
transform:translateY(-50%);background:none;border:none;cursor:pointer;
|
||||
color:var(--muted);padding:4px;align-items:center;z-index:2;"
|
||||
onmouseover="this.style.color='var(--text)'"
|
||||
onmouseout="this.style.color='var(--muted)'">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2.5" style="pointer-events:none;display:block;">
|
||||
<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;gap:8px;align-items:center;">
|
||||
<a href="{{ url_for('viat_exportar', q=q) }}" class="btn btn-ghost" id="btnExcel" title="Exportar Excel">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="12" y1="18" x2="12" y2="12"/>
|
||||
<line x1="9" y1="15" x2="12" y2="18"/><line x1="15" y1="15" x2="12" y2="18"/>
|
||||
</svg>
|
||||
Excel
|
||||
</a>
|
||||
<button type="button" class="btn btn-ghost" id="btnPDF" title="Imprimir PDF">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<polyline points="6 9 6 2 18 2 18 9"/>
|
||||
<path d="M6 18H4a2 2 0 01-2-2v-5a2 2 0 012-2h16a2 2 0 012 2v5a2 2 0 01-2 2h-2"/>
|
||||
<rect x="6" y="14" width="12" height="8"/>
|
||||
</svg>
|
||||
Imprimir - PDF
|
||||
</button>
|
||||
<button type="button" class="btn btn-ghost" id="btnCopiar" title="Copiar al portapapeles">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
||||
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/>
|
||||
</svg>
|
||||
Copiar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p id="counter" style="margin-bottom:10px;font-size:12px;color:var(--muted)">
|
||||
{{ rows|length }} registro{{ 's' if rows|length != 1 }}{% if q %} — filtrado por «{{ q }}»{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table id="tablaViat">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Via-T</th>
|
||||
<th>M. Oficial</th>
|
||||
<th>M. Civil</th>
|
||||
<th>Marca</th>
|
||||
<th>Modelo</th>
|
||||
<th>Población</th>
|
||||
<th>Unidad</th>
|
||||
<th>Tipo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbody">
|
||||
{% include 'viat/rows.html' %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
var input = document.getElementById('searchInput');
|
||||
var tbody = document.getElementById('tbody');
|
||||
var counter = document.getElementById('counter');
|
||||
var clearBtn = document.getElementById('clearBtn');
|
||||
var timer;
|
||||
|
||||
input.addEventListener('input', function() {
|
||||
clearBtn.style.display = this.value ? 'flex' : 'none';
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() { buscar(input.value.trim()); }, 300);
|
||||
});
|
||||
|
||||
clearBtn.addEventListener('click', function() {
|
||||
input.value = '';
|
||||
this.style.display = 'none';
|
||||
input.focus();
|
||||
buscar('');
|
||||
});
|
||||
|
||||
function buscar(q) {
|
||||
var btnExcel = document.getElementById('btnExcel');
|
||||
if (btnExcel) {
|
||||
btnExcel.href = '{{ url_for("viat_exportar") }}?q=' + encodeURIComponent(q);
|
||||
}
|
||||
fetch('{{ url_for("viat_list") }}?q=' + encodeURIComponent(q) + '&solo_filas=1')
|
||||
.then(function(r) {
|
||||
if (r.redirected || r.url.includes('/login')) {
|
||||
window.location = '{{ url_for("login") }}'; return null;
|
||||
}
|
||||
return r.text();
|
||||
})
|
||||
.then(function(html) {
|
||||
if (!html) return;
|
||||
tbody.innerHTML = html;
|
||||
var filas = document.querySelectorAll('#tbody tr[data-id]').length;
|
||||
if (counter) {
|
||||
counter.textContent = filas + ' registro' + (filas !== 1 ? 's' : '')
|
||||
+ (q ? ' — filtrado por «' + q + '»' : '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ── PDF ── */
|
||||
document.getElementById('btnPDF').addEventListener('click', function() {
|
||||
var titulo = 'Listado Via-T';
|
||||
var fecha = new Date().toLocaleDateString('es-ES');
|
||||
var heads = ['Via-T','M. Oficial','M. Civil','Marca','Modelo','Población','Unidad','Tipo'];
|
||||
var filas = '';
|
||||
document.querySelectorAll('#tablaViat tbody tr[data-id]').forEach(function(tr) {
|
||||
filas += '<tr>';
|
||||
tr.querySelectorAll('td').forEach(function(td) {
|
||||
filas += '<td>' + td.innerText.trim() + '</td>';
|
||||
});
|
||||
filas += '</tr>';
|
||||
});
|
||||
var html = `<!DOCTYPE html><html><head><meta charset="UTF-8"><title>${titulo}</title>
|
||||
<style>
|
||||
body{font-family:Arial,sans-serif;font-size:10px;color:#1a1d29;margin:20px}
|
||||
h2{font-size:14px;margin-bottom:4px}.meta{font-size:9px;color:#666;margin-bottom:14px}
|
||||
table{width:100%;border-collapse:collapse}
|
||||
th{background:#5c6ef8;color:#fff;padding:6px 7px;text-align:left;font-size:9px}
|
||||
td{padding:5px 7px;border-bottom:1px solid #e3e6ef;font-size:9px}
|
||||
tr:nth-child(even) td{background:#eef0f8}
|
||||
@media print{body{margin:10px}}
|
||||
</style></head><body>
|
||||
<h2>${titulo}</h2>
|
||||
<div class="meta">Generado el ${fecha} · ${document.querySelectorAll('#tablaViat tbody tr[data-id]').length} registros</div>
|
||||
<table><thead><tr>${heads.map(function(h){return '<th>'+h+'</th>';}).join('')}</tr></thead>
|
||||
<tbody>${filas}</tbody></table></body></html>`;
|
||||
var win = window.open('','_blank','width=1000,height=700');
|
||||
win.document.write(html); win.document.close(); win.focus();
|
||||
setTimeout(function(){ win.print(); }, 400);
|
||||
});
|
||||
|
||||
/* ── COPIAR ── */
|
||||
document.getElementById('btnCopiar').addEventListener('click', function() {
|
||||
var btn = this;
|
||||
var heads = ['Via-T','M. Oficial','M. Civil','Marca','Modelo','Población','Unidad','Tipo'];
|
||||
var lineas = [heads.join('\t')];
|
||||
document.querySelectorAll('#tablaViat tbody tr[data-id]').forEach(function(tr) {
|
||||
var fila = [];
|
||||
tr.querySelectorAll('td').forEach(function(td) { fila.push(td.innerText.trim()); });
|
||||
lineas.push(fila.join('\t'));
|
||||
});
|
||||
var texto = lineas.join('\n');
|
||||
if (!texto.trim() || lineas.length <= 1) { alert('No hay datos para copiar.'); return; }
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
navigator.clipboard.writeText(texto)
|
||||
.then(function(){ mostrarCopiado(btn); })
|
||||
.catch(function(){ copiarFallback(texto, btn); });
|
||||
} else {
|
||||
copiarFallback(texto, btn);
|
||||
}
|
||||
});
|
||||
|
||||
function copiarFallback(texto, btn) {
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = texto;
|
||||
ta.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;';
|
||||
document.body.appendChild(ta);
|
||||
ta.focus(); ta.select(); ta.setSelectionRange(0, 99999);
|
||||
var ok = false;
|
||||
try { ok = document.execCommand('copy'); } catch(e) { ok = false; }
|
||||
document.body.removeChild(ta);
|
||||
if (ok) { mostrarCopiado(btn); }
|
||||
else { alert('No se pudo copiar automáticamente.'); }
|
||||
}
|
||||
|
||||
function mostrarCopiado(btn) {
|
||||
var orig = btn.innerHTML;
|
||||
btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg> Copiado';
|
||||
btn.style.color = 'var(--success)'; btn.style.borderColor = 'var(--success)';
|
||||
setTimeout(function(){ btn.innerHTML = orig; btn.style.color=''; btn.style.borderColor=''; }, 2000);
|
||||
}
|
||||
|
||||
/* ── ORDENACIÓN ── */
|
||||
(function() {
|
||||
var estado = { col: -1, asc: true };
|
||||
document.querySelectorAll('#tablaViat thead th').forEach(function(th, idx) {
|
||||
th.style.cursor = 'pointer'; th.style.userSelect = 'none';
|
||||
var icon = document.createElement('span');
|
||||
icon.style.cssText = 'margin-left:5px;opacity:.3;font-size:10px;';
|
||||
icon.textContent = '⇅'; icon.className = 'sort-icon';
|
||||
th.appendChild(icon);
|
||||
th.addEventListener('click', function() {
|
||||
var filas = Array.from(document.querySelectorAll('#tablaViat tbody tr[data-id]'));
|
||||
if (!filas.length) return;
|
||||
var mismaCol = estado.col === idx;
|
||||
estado.asc = mismaCol ? !estado.asc : true; estado.col = idx;
|
||||
document.querySelectorAll('.sort-icon').forEach(function(ic){ ic.textContent='⇅'; ic.style.opacity='.3'; });
|
||||
icon.textContent = estado.asc ? '↑' : '↓'; icon.style.opacity='1'; icon.style.color='var(--accent)';
|
||||
filas.sort(function(a, b) {
|
||||
var valA = (a.querySelectorAll('td')[idx]||{innerText:''}).innerText.trim().toLowerCase();
|
||||
var valB = (b.querySelectorAll('td')[idx]||{innerText:''}).innerText.trim().toLowerCase();
|
||||
var numA = parseFloat(valA.replace(/[^0-9.-]/g,'')), numB = parseFloat(valB.replace(/[^0-9.-]/g,''));
|
||||
var r = (!isNaN(numA)&&!isNaN(numB)) ? numA-numB : valA.localeCompare(valB,'es');
|
||||
return estado.asc ? r : -r;
|
||||
});
|
||||
var tb = document.querySelector('#tablaViat tbody');
|
||||
filas.forEach(function(f){ tb.appendChild(f); });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
{% if rows %}
|
||||
{% for r in rows %}
|
||||
<tr data-id="{{ r['id'] }}"
|
||||
onclick="window.location='/vehiculos/{{ r['id'] }}/editar?origen=viat&q_viat={{ q|urlencode }}'"∫
|
||||
style="cursor:pointer;"
|
||||
onmouseover="this.style.background='var(--pill-bg)'"
|
||||
onmouseout="this.style.background=''">
|
||||
<td><strong>{{ r['viat'] or '—' }}</strong></td>
|
||||
<td>{{ r['m_oficial'] or '—' }}</td>
|
||||
<td>{{ r['m_civil'] or '—' }}</td>
|
||||
<td>{{ r['marca'] or '—' }}</td>
|
||||
<td>{{ r['modelo'] or '—' }}</td>
|
||||
<td>{{ r['poblacion'] or '—' }}</td>
|
||||
<td>{{ r['unidad'] or '—' }}</td>
|
||||
<td>
|
||||
{% if r['tipo'] %}
|
||||
<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['tipo'] }}</span>
|
||||
{% else %}—{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="8">
|
||||
<div class="empty-state">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"
|
||||
style="width:36px;height:36px;margin-bottom:10px;opacity:.3">
|
||||
<rect x="1" y="3" width="15" height="13" rx="2"/>
|
||||
<path d="M16 8h4l3 3v5h-7V8z"/>
|
||||
<circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/>
|
||||
</svg>
|
||||
{% if q %}
|
||||
No se encontraron resultados para <strong>"{{ q }}"</strong>.
|
||||
{% else %}
|
||||
No hay vehículos con Via-T registrado.
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user