230 lines
9.8 KiB
HTML
Executable File
230 lines
9.8 KiB
HTML
Executable File
{% 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"><i class="bi bi-broadcast"></i> Via-T</div>
|
|
<div class="page-subtitle">Listado de vehículos con dispositivo Via-T. Búsqueda por Via-T, m.oficial, m.reservada, 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. Reservada</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. Reservada','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. Reservada','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 %} |