correcciones finales

This commit is contained in:
2026-09-11 23:30:29 +02:00
parent 5d2912f789
commit 2b8f5374c9
18 changed files with 1582 additions and 440 deletions
Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+51 -109
View File
@@ -16,7 +16,8 @@ app.secret_key = 'clave-secreta-navbar-app'
# Límite máximo de subida: 5 MiB
# app.config['MAX_CONTENT_LENGTH'] = 5 * 1024 * 1024
DATABASE = 'database/pyfleet.db'
# DATABASE = 'database/pyfleet.db'
DATABASE = 'database/auto.db'
PASSWORD_HASH = generate_password_hash('123')
@@ -236,7 +237,7 @@ def vehiculos_list():
NORM(modelo) LIKE ? OR
NORM(poblacion) LIKE ? OR
NORM(unidad) LIKE ? OR
NORM(denominacion) LIKE ? OR
NORM(tipo) LIKE ? OR
NORM(situacion) LIKE ?
)''')
params.extend([like] * 9)
@@ -245,7 +246,7 @@ def vehiculos_list():
rows = db.execute(
f'''SELECT id, m_oficial, m_reservada, marca, modelo, poblacion, unidad,
denominacion, tipo, situacion, lanzadestellos
tipo, situacion, lanzadestellos
FROM vehiculos
WHERE {where} {filtro_bajas}
ORDER BY id''',
@@ -329,7 +330,7 @@ def vehiculos_editar(id):
desde = request.args.get('desde', '')
hasta = request.args.get('hasta', '')
q_itv = request.args.get('q_itv', '')
origen = request.args.get('origen', '')
origen = request.args.get('origen', '')
q_viat = request.args.get('q_viat', '')
if not vehiculo:
@@ -409,12 +410,20 @@ def vehiculos_eliminar(id):
return redirect(url_for('vehiculos_list', q=q) if q else url_for('vehiculos_list'))
@app.route('/vehiculos/<int:vid>/historial/nuevo', methods=['POST'])
@login_required
def historial_nuevo(vid):
q = request.form.get('_q', '')
db = get_db()
# Recoger TODOS los parámetros de navegación del POST
q = request.form.get('_q', '')
desde = request.form.get('_desde', '')
hasta = request.form.get('_hasta', '')
q_itv = request.form.get('_q_itv', '')
origen = request.form.get('_origen', '')
q_viat = request.form.get('_q_viat', '') # ← POST no GET
# Datos del historial
h_fecha = request.form.get('h_fecha') or None
h_vehiculo_id = request.form.get('h_vehiculo_id', '').strip()
h_matricula = request.form.get('h_matricula', '').strip()
@@ -424,11 +433,7 @@ def historial_nuevo(vid):
h_grupo = request.form.get('h_grupo', '').strip()
h_observaciones = request.form.get('h_observaciones', '').strip()
desde = request.form.get('_desde', '')
hasta = request.form.get('_hasta', '')
q_itv = request.form.get('_q_itv', '')
# Obtener el NOMBRE de la población a partir del id
# Obtener nombre de población
poblacion_nombre = ''
if h_poblacion_id:
row = db.execute('SELECT poblacion FROM poblaciones WHERE id=?', (h_poblacion_id,)).fetchone()
@@ -440,32 +445,47 @@ def historial_nuevo(vid):
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (h_fecha, h_vehiculo_id, h_matricula, h_situacion, poblacion_nombre, h_unidad, h_grupo, h_observaciones))
# Si la unidad es BAJA, actualizar situacion del vehiculo
# Actualizar situacion del vehiculo
if h_situacion.upper() == 'BAJA':
db.execute("UPDATE vehiculos SET situacion='BAJA' WHERE id=?", (vid,))
db.execute("UPDATE vehiculos SET situacion='BAJA', poblacion='', unidad='' WHERE id=?", (vid,))
else:
db.execute("UPDATE vehiculos SET situacion=?, poblacion=?, unidad=?, grupo=? WHERE id=?", (h_situacion, poblacion_nombre, h_unidad, h_grupo, vid,))
db.execute(
"UPDATE vehiculos SET situacion=?, poblacion=?, unidad=?, grupo=? WHERE id=?",
(h_situacion, poblacion_nombre, h_unidad, h_grupo, vid)
)
db.commit()
flash('Entrada añadida al historial.', 'ok')
# Volver a ITV si venía de ahí, si no al formulario del vehículo
# Redirect según origen
if origen == 'viat':
return redirect(f'/vehiculos/{vid}/editar?origen=viat&q_viat={q_viat}')
if desde or hasta or q_itv:
return redirect(f'/vehiculos/{vid}/editar?desde={desde}&hasta={hasta}&q_itv={q_itv}')
# return redirect(f'/vehiculos/{vid}/editar?q={q}')
return redirect(f'/vehiculos/{vid}/editar?desde={desde}&hasta={hasta}&q_itv={q_itv}')
return redirect(url_for('vehiculos_editar', id=vid, q=q))
@app.route('/vehiculos/<int:vid>/historial/<int:hid>/eliminar', methods=['POST'])
@login_required
def historial_eliminar(vid, hid):
q = request.form.get('_q', '')
desde = request.form.get('_desde', '')
hasta = request.form.get('_hasta', '')
unidad_itv = request.form.get('_unidad_itv', '')
db = get_db()
# Recoger parámetros de navegación
q = request.form.get('_q', '')
desde = request.form.get('_desde', '')
hasta = request.form.get('_hasta', '')
q_itv = request.form.get('_q_itv', '')
origen = request.form.get('_origen', '')
q_viat = request.form.get('_q_viat', '') # ← POST no GET
# 1. Comprobar que el vehículo existe
vehiculo = db.execute('''
SELECT id, m_oficial
@@ -541,16 +561,16 @@ def historial_eliminar(vid, hid):
WHERE id = ?
''', (vid,))
# 7. Confirmar cambios
db.commit()
flash('Entrada eliminada del historial.', 'ok')
# Volver a ITV si venía de ahí
if desde or hasta or unidad_itv:
return redirect(f'/vehiculos/{vid}/editar?desde={desde}&hasta={hasta}&unidad_itv={unidad_itv}')
# return redirect(f'/vehiculos/{vid}/editar?q={q}')
# Redirect según origen
if origen == 'viat':
return redirect(f'/vehiculos/{vid}/editar?origen=viat&q_viat={q_viat}')
if desde or hasta or q_itv:
return redirect(f'/vehiculos/{vid}/editar?desde={desde}&hasta={hasta}&q_itv={q_itv}')
url = f'/vehiculos/{vid}/editar'
if q:
url += f'?q={q}'
@@ -625,7 +645,7 @@ def vehiculos_exportar():
ws = wb.active
ws.title = 'Vehículos'
headers = ['M. Oficial', 'M. Civil', 'Marca', 'Modelo',
headers = ['M. Oficial', 'M. Reservada', 'Marca', 'Modelo',
'Poblacion', 'Unidad', 'Grupo', 'Denominación', 'Situación' ]
header_fill = PatternFill('solid', fgColor='5C6EF8')
header_font = Font(bold=True, color='FFFFFF', size=11)
@@ -684,7 +704,8 @@ def documentos_upload(id):
q_itv = request.form.get('_q_itv', '')
origen = request.form.get('_origen', '')
q_viat = request.form.get('_q_viat', '')
nombre = request.form.get('nombre_doc', '').strip()
nombre = request.form.get('nombre_doc', '').strip() + '.pdf'
if 'pdf' not in request.files:
flash('No se seleccionó ningún archivo.', 'error')
@@ -757,7 +778,7 @@ def documentos_descargar(doc_id):
return send_from_directory(UPLOAD_FOLDER, doc['filename'],
as_attachment=True,
download_name=doc['nombre'])
# download_name=doc['nombre'] + '.pdf')
# download_name=doc['nombre'] + '.pdf'
@app.route('/vehiculos/documentos/<int:doc_id>/eliminar', methods=['POST'])
@login_required
@@ -781,85 +802,6 @@ def documentos_eliminar(doc_id):
# @app.route('/vehiculos/<int:id>/upload', methods=['POST'])
# @login_required
# def vehiculos_upload(id):
# q = request.form.get('_q', '')
# incl_bajas = request.form.get('_incl_bajas', '0')
# desde = request.form.get('_desde', '')
# hasta = request.form.get('_hasta', '')
# q_itv = request.form.get('_q_itv', '')
# origen = request.form.get('_origen', '')
# q_viat = request.form.get('_q_viat', '')
# if 'pdf' not in request.files:
# flash('No se seleccionó ningún archivo.', 'error')
# return redirect(f'/vehiculos/{id}/editar?q={q}&incl_bajas={incl_bajas}')
# file = request.files['pdf']
# if file.filename == '':
# flash('No se seleccionó ningún archivo.', 'error')
# return redirect(f'/vehiculos/{id}/editar?q={q}&incl_bajas={incl_bajas}')
# if file and allowed_file(file.filename):
# # Guardar con nombre único basado en id del vehículo
# os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# filename = f'ficha_tecnica_id_{id}.pdf'
# filepath = os.path.join(UPLOAD_FOLDER, filename)
# file.save(filepath)
# # Guardar referencia en BD
# db = get_db()
# db.execute('UPDATE vehiculos SET pdf=? WHERE id=?', (filename, id))
# db.commit()
# flash('Documento PDF subido correctamente.', 'ok')
# else:
# flash('Solo se permiten archivos PDF.', 'error')
# url = f'/vehiculos/{id}/editar?q={q}&incl_bajas={incl_bajas}'
# if origen == 'viat':
# url = f'/vehiculos/{id}/editar?origen=viat&q_viat={q_viat}'
# elif desde or hasta or q_itv:
# url = f'/vehiculos/{id}/editar?desde={desde}&hasta={hasta}&q_itv={q_itv}'
# return redirect(url)
# @app.route('/vehiculos/<int:id>/pdf')
# @login_required
# def vehiculos_pdf(id):
# from flask import send_from_directory
# db = get_db()
# vehiculo = db.execute('SELECT pdf FROM vehiculos WHERE id=?', (id,)).fetchone()
# if not vehiculo or not vehiculo['pdf']:
# flash('No hay documento PDF para este vehículo.', 'error')
# return redirect(f'/vehiculos/{id}/editar')
# return send_from_directory(UPLOAD_FOLDER, vehiculo['pdf'], as_attachment=False)
# @app.route('/vehiculos/<int:id>/pdf/eliminar', methods=['POST'])
# @login_required
# def vehiculos_pdf_eliminar(id):
# q = request.form.get('_q', '')
# incl_bajas = request.form.get('_incl_bajas', '0')
# db = get_db()
# vehiculo = db.execute('SELECT pdf FROM vehiculos WHERE id=?', (id,)).fetchone()
# if vehiculo and vehiculo['pdf']:
# filepath = os.path.join(UPLOAD_FOLDER, vehiculo['pdf'])
# if os.path.exists(filepath):
# os.remove(filepath)
# db.execute('UPDATE vehiculos SET pdf=NULL WHERE id=?', (id,))
# db.commit()
# flash('Documento PDF eliminado.', 'ok')
# return redirect(f'/vehiculos/{id}/editar?q={q}&incl_bajas={incl_bajas}')
# Ruta API que devuelve unidades según población
@app.route('/api/unidades/<int:poblacion_id>')
@login_required
@@ -978,7 +920,7 @@ def itv_exportar():
ws = wb.active
ws.title = 'ITV'
headers = ['M. Oficial', 'M. Civil', 'Marca', 'Modelo',
headers = ['M. Oficial', 'M. Reservada', 'Marca', 'Modelo',
'Denominación', 'Tipo', 'Unidad', 'Población', 'Fecha ITV']
header_fill = PatternFill('solid', fgColor='5C6EF8')
header_font = Font(bold=True, color='FFFFFF', size=11)
@@ -1432,7 +1374,7 @@ def viat_exportar():
ws = wb.active
ws.title = 'Via-T'
headers = ['Via-T', 'M. Oficial', 'M. Civil', 'Marca',
headers = ['Via-T', 'M. Oficial', 'M. Reservada', 'Marca',
'Modelo', 'Población', 'Unidad', 'Tipo']
header_fill = PatternFill('solid', fgColor='5C6EF8')
header_font = Font(bold=True, color='FFFFFF', size=11)
@@ -1635,4 +1577,4 @@ if __name__ == '__main__':
# f'SELECT id, m_oficial, m_reservada, marca, modelo, poblacion, unidad, grupo, tipo, situacion FROM vehiculos WHERE {where} {filtro_bajas} ORDER BY id',
# params
# ).fetchall()
BIN
View File
Binary file not shown.
Binary file not shown.
+8 -2
View File
@@ -238,8 +238,14 @@ CREATE TABLE "unidades" (
)
Actualización vial
UPDATE vehiculos
SET viat = substr(
notas,
instr(lower(notas), 'viat '),
24
)
WHERE instr(lower(notas), 'viat ') > 0;
----------------------------------------
CONSULTAR TIPOS DE VEHICULO
+247
View File
@@ -0,0 +1,247 @@
DROP TABLE IF EXISTS ACCIDENTES;
DROP TABLE IF EXISTS "CAMBIOS DE ACEITE";
DROP TABLE IF EXISTS CONTRATO;
DROP TABLE IF EXISTS "DEFINICIÓN DE TIPOS";
DROP TABLE IF EXISTS Denominación;
DROP TABLE IF EXISTS "Errores de pegado";
DROP TABLE IF EXISTS "Estado Seguro";
DROP TABLE IF EXISTS FACTURAS;
DROP TABLE IF EXISTS FUNCIONARIOS;
DROP TABLE IF EXISTS "Grupo Asignado";
DROP TABLE IF EXISTS HERRAMIENTAS;
DROP TABLE IF EXISTS "Historico destino";
DROP TABLE IF EXISTS Hoja1;
DROP TABLE IF EXISTS ITV;
DROP TABLE IF EXISTS Incidencias;
DROP TABLE IF EXISTS KILOMETROS;
DROP TABLE IF EXISTS LIQUIDACION;
DROP TABLE IF EXISTS MAQUINARIA;
DROP TABLE IF EXISTS Marcas;
DROP TABLE IF EXISTS Matriculas;
DROP TABLE IF EXISTS Modelo;
DROP TABLE IF EXISTS Multas;
DROP TABLE IF EXISTS Neumaticos;
DROP TABLE IF EXISTS Piezas;
DROP TABLE IF EXISTS POBLACIONES;
DROP TABLE IF EXISTS PROVEEDORES;
DROP TABLE IF EXISTS Peticiones;
DROP TABLE IF EXISTS Plantilla;
DROP TABLE IF EXISTS RECIBO;
DROP TABLE IF EXISTS REPARACIONES;
DROP TABLE IF EXISTS REPUESTOS;
DROP TABLE IF EXISTS "Situación Vehículo";
DROP TABLE IF EXISTS "T_RESUMEN VEHICULOS COMISARIA PROVINCIAL";
DROP TABLE IF EXISTS "T_RESUMEN VEHICULOS COMISARIAS LOCALES";
DROP TABLE IF EXISTS Tipo;
DROP TABLE IF EXISTS Unidades;
DROP TABLE IF EXISTS VACACIONES;
DROP TABLE IF EXISTS "VEHICULOS 10-01-10";
DROP TABLE IF EXISTS "VEHICULOS 28-04-10";
DROP TABLE IF EXISTS VEHICULOS_PTE;
ALTER TABLE VEHICULOS RENAME TO "vehiculos_tmp";
ALTER TABLE "vehiculos_tmp" RENAME TO vehiculos;
ALTER TABLE vehiculos DROP COLUMN "Número de Identificación";
ALTER TABLE vehiculos DROP COLUMN "Nº Cilindros/Cilindrada";
ALTER TABLE vehiculos DROP COLUMN Potencia;
ALTER TABLE vehiculos DROP COLUMN "Medidas neumaticos";
ALTER TABLE vehiculos DROP COLUMN "Fecha Destino/Situación";
ALTER TABLE vehiculos DROP COLUMN Seguro;
ALTER TABLE vehiculos DROP COLUMN Denominación;
ALTER TABLE vehiculos DROP COLUMN Grupo;
ALTER TABLE vehiculos DROP COLUMN Foto_asignada;
ALTER TABLE vehiculos RENAME COLUMN "Matrícula Oficial (DGP)" TO m_oficial;
ALTER TABLE vehiculos RENAME COLUMN "Nº ficha" TO legajo;
ALTER TABLE vehiculos RENAME COLUMN "Matrícula Civil" TO m_reservada;
ALTER TABLE vehiculos RENAME COLUMN PMM TO m_propia;
ALTER TABLE vehiculos RENAME COLUMN Población TO poblacion;
ALTER TABLE vehiculos RENAME COLUMN Marca TO marca;
ALTER TABLE vehiculos RENAME COLUMN Modelo TO modelo;
ALTER TABLE vehiculos RENAME COLUMN Tipo TO tipo;
ALTER TABLE vehiculos RENAME COLUMN Color TO color;
ALTER TABLE vehiculos RENAME COLUMN "Número de bastidor" TO VIN;
ALTER TABLE vehiculos RENAME COLUMN "Fecha de Alta" TO f_alta;
ALTER TABLE vehiculos RENAME COLUMN "Fecha de Baja" TO f_baja;
ALTER TABLE vehiculos RENAME COLUMN "Situación veh" TO situacion;
ALTER TABLE vehiculos RENAME COLUMN Kilometros TO km;
ALTER TABLE vehiculos RENAME COLUMN "Kilometros a dia 1" TO km_1;
ALTER TABLE vehiculos RENAME COLUMN "Tipo de Combustible" TO combustible;
ALTER TABLE vehiculos RENAME COLUMN "Número de plazas" TO plazas;
ALTER TABLE vehiculos RENAME COLUMN "Ultima ITV" TO itv_ultima;
ALTER TABLE vehiculos RENAME COLUMN "Tipo ITV" TO itv;
ALTER TABLE vehiculos RENAME COLUMN Departamento TO unidad;
ALTER TABLE vehiculos RENAME COLUMN "Número de Poliza" TO poliza;
ALTER TABLE vehiculos ADD COLUMN id INTEGER;
ALTER TABLE vehiculos ADD COLUMN lanzadestellos INTEGER;
ALTER TABLE vehiculos ADD COLUMN grupo TEXT;
ALTER TABLE vehiculos ADD COLUMN viat TEXT;
ALTER TABLE vehiculos ADD COLUMN int_operacion TEXT;
ALTER TABLE vehiculos ADD COLUMN int_grupo TEXT;
ALTER TABLE vehiculos ADD COLUMN int_juzgado TEXT;
ALTER TABLE vehiculos ADD COLUMN int_procedimiento TEXT;
ALTER TABLE vehiculos ADD COLUMN notas TEXT;
UPDATE vehiculos SET notas = TRIM(COALESCE(observaciones, '') || ' ' || COALESCE(historial, ''));
ALTER TABLE vehiculos DROP COLUMN observaciones;
ALTER TABLE vehiculos DROP COLUMN historial;
UPDATE vehiculos
SET lanzadestellos = 1
WHERE notas LIKE '%SAMCO%';
UPDATE vehiculos SET f_alta = substr(f_alta, 1, 10);
UPDATE vehiculos SET f_baja = substr(f_baja, 1, 10);
UPDATE vehiculos
SET situacion = CASE
WHEN f_baja IS NULL OR f_baja = '' THEN 'ACTIVO'
ELSE 'BAJA'
END;
UPDATE vehiculos
SET viat = substr(
notas,
instr(lower(notas), 'viat '),
24
)
WHERE instr(lower(notas), 'viat ') > 0;
UPDATE vehiculos SET unidad = 'BPEF' WHERE unidad = 'B.P.E. y F.';
UPDATE vehiculos SET unidad = 'BPI' WHERE unidad = 'B.P.I.';
UPDATE vehiculos SET unidad = 'BPPC' WHERE unidad = 'B.P.P.C.';
UPDATE vehiculos SET unidad = 'BPSC' WHERE unidad = 'B.P.S.C.';
UPDATE vehiculos SET unidad = 'BPSC' WHERE unidad = 'Seg. Ciudadana' AND poblacion = 'MALAGA';
UPDATE vehiculos SET unidad = 'BLSC' WHERE unidad = 'Seg. Ciudadana' AND poblacion != 'MALAGA';
UPDATE vehiculos SET unidad = 'BPSC' WHERE unidad = 'SEG. CIUDADANA';
UPDATE vehiculos SET unidad = 'BPSC' WHERE unidad = 'B.P.S.C. K';
UPDATE vehiculos SET unidad = 'DISTRITO CENTRO' WHERE unidad = 'DTO. CENTRO';
UPDATE vehiculos SET unidad = 'DISTRITO ESTE' WHERE unidad = 'DTO. ESTE';
UPDATE vehiculos SET unidad = 'DISTRITO NORTE' WHERE unidad = 'DTO. NORTE';
UPDATE vehiculos SET unidad = 'DISTRITO OESTE' WHERE unidad = 'DTO. OESTE';
UPDATE vehiculos SET unidad = 'UCOP - GOES' WHERE unidad = 'G.O.E.S.';
UPDATE vehiculos SET unidad = 'UDEF - IPLA' WHERE unidad = 'I.P.L.A.';
UPDATE vehiculos SET unidad = 'SECRETARIA GENERAL - NUCLEO RESERVA' WHERE unidad = 'NUCLEO DE RESERVA';
UPDATE vehiculos SET unidad = 'SECRETARIA GENERAL' WHERE unidad = 'SECRETARIA G.';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'SUSTITUCION';
UPDATE vehiculos SET unidad = 'AUTOMOCION' WHERE unidad = 'TALLER AUTOMOCION';
UPDATE vehiculos SET unidad = 'UCOP - GABINETE TECNICO' WHERE unidad = 'U.C.O.P. - GABINETE TÉCNICO';
UPDATE vehiculos SET unidad = 'UCOP - GOTHAM' WHERE unidad = 'U.C.O.P. - GOTHAM';
UPDATE vehiculos SET unidad = 'UCOP - HELICOPTEROS' WHERE unidad = 'U.C.O.P. - HELICOPTEROS';
UPDATE vehiculos SET unidad = 'UCOP' WHERE unidad = 'U.C.O.P. - JEFES';
UPDATE vehiculos SET unidad = 'UCOP - OMEGA' WHERE unidad = 'U.C.O.P. - OMEGA';
UPDATE vehiculos SET unidad = 'UCOP - SISTEMAS ESPECIALES' WHERE unidad = 'U.C.O.P. - SISTEMAS';
UPDATE vehiculos SET unidad = 'UCOP - UVAO' WHERE unidad = 'U.C.O.P. - UVAO';
UPDATE vehiculos SET unidad = 'UDEF' WHERE unidad = 'U.D.E.F.';
UPDATE vehiculos SET unidad = 'BPPJ - UDEV ' WHERE unidad = 'U.D.E.V.' AND poblacion = 'MALAGA';
UPDATE vehiculos SET unidad = 'BLPJ - UDEV' WHERE unidad = 'U.D.E.V.' AND poblacion != 'MALAGA';
UPDATE vehiculos SET unidad = 'UIP' WHERE unidad = 'U.I.P.';
UPDATE vehiculos SET unidad = 'BPSC - UPR' WHERE unidad = 'U.P.R.' AND poblacion = 'MALAGA';
UPDATE vehiculos SET unidad = 'BLSC - UPR' WHERE unidad = 'U.P.R.' AND poblacion != 'MALAGA';
UPDATE vehiculos SET unidad = 'BPSC - UPR 1' WHERE unidad = 'U.P.R.-1';
UPDATE vehiculos SET unidad = 'BPSC - UPR 2' WHERE unidad = 'U.P.R.-2';
UPDATE vehiculos SET unidad = 'UDYCO' WHERE unidad = 'udyco - Costa del Sol';
UPDATE vehiculos SET unidad = 'BLSC' WHERE unidad = 'B.L.S.C.';
UPDATE vehiculos SET unidad = 'BLPJ' WHERE unidad = 'B.L.P.J.';
UPDATE vehiculos SET unidad = 'BLI' WHERE unidad = 'B.L.I.';
UPDATE vehiculos SET unidad = 'BLPC' WHERE unidad = 'B.L.P.C.';
UPDATE vehiculos SET unidad = 'BLEF' WHERE unidad = 'B.L.E. y F.';
UPDATE vehiculos SET unidad = 'UCOL' WHERE unidad = 'U.C.O.L.';
UPDATE vehiculos SET unidad = 'JEFATURA COMISARIA' WHERE unidad = 'JEFE COMISARÍA';
UPDATE vehiculos SET unidad = 'UDYCO' WHERE unidad = 'udyco - Costa del Sol' AND poblacion != 'MALAGA';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'BAJA';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'ENAJ. DIRECTA MARZO 2025 BAJA ASIA';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'ENAJ. COCHES';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'DESTRUIDO' OR unidad = 'DESTRUCCION';
UPDATE vehiculos SET unidad = '' WHERE unidad = 'BAJA EN ASIA' OR unidad = 'BAJA TEMPORAL' OR unidad = 'BANCO DE VEHCULOS' OR unidad = 'BAJA DEFINITIVA' OR unidad = 'BAJA ASIA Enaj. MOTOS' OR unidad = 'BAJA ASIA Enaj. COCHES';
UPDATE vehiculos SET unidad = '' WHERE unidad LIKE '%CURSO%';
CREATE TABLE documentos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
vehiculo_id INTEGER NOT NULL REFERENCES vehiculos(id) ON DELETE CASCADE,
nombre TEXT,
filename TEXT NOT NULL,
fecha DATETIME DEFAULT (datetime('now','localtime'))
);
CREATE TABLE mensajes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
texto TEXT NOT NULL,
autor TEXT,
fecha DATETIME DEFAULT (datetime('now','localtime'))
);
ALTER TABLE "Historial" RENAME TO "historial_tmp";
ALTER TABLE "historial_tmp" RENAME TO "historial";
ALTER TABLE historial RENAME COLUMN Matricula TO matricula;
ALTER TABLE historial RENAME COLUMN Unidad TO unidad;
ALTER TABLE historial RENAME COLUMN Cuando TO fecha;
ALTER TABLE historial RENAME COLUMN Observaciones TO observaciones;
ALTER TABLE historial ADD COLUMN id INTEGER;
ALTER TABLE historial ADD COLUMN vehiculo_id INTEGER;
ALTER TABLE historial ADD COLUMN situacion TEXT;
ALTER TABLE historial ADD COLUMN poblacion TEXT;
ALTER TABLE historial ADD COLUMN grupo TEXT;
UPDATE historial SET fecha = substr(fecha, 1, 10);
UPDATE vehiculos
SET
m_oficial = NULLIF(m_oficial, 'none'),
m_reservada = NULLIF(m_reservada, 'none'),
m_propia = NULLIF(m_propia, 'none'),
VIN = NULLIF(VIN, 'none'),
poliza = NULLIF(poliza, 'none'),
viat = NULLIF(viat, 'none'),
legajo = NULLIF(legajo, 'none'),
marca = NULLIF(marca, 'none'),
modelo = NULLIF(modelo, 'none'),
tipo = NULLIF(tipo, 'none'),
color = NULLIF(color, 'none'),
combustible = NULLIF(combustible, 'none'),
plazas = NULLIF(plazas, 'none'),
situacion = NULLIF(situacion, 'none'),
poblacion = NULLIF(poblacion, 'none'),
unidad = NULLIF(unidad, 'none'),
grupo = NULLIF(grupo, 'none'),
int_operacion = NULLIF(int_operacion, 'none'),
int_grupo = NULLIF(int_grupo, 'none'),
int_juzgado = NULLIF(int_juzgado, 'none'),
int_procedimiento = NULLIF(int_procedimiento, 'none'),
f_alta = NULLIF(f_alta, 'none'),
f_baja = NULLIF(f_baja, 'none'),
km = NULLIF(km, 'none'),
km_1 = NULLIF(km_1, 'none'),
itv_ultima = NULLIF(itv_ultima, 'none'),
itv = NULLIF(itv, 'none'),
notas = NULLIF(notas, 'none');
————————————————————————
Después:
1- Poner id autoincremental en tabla vehículos
2. Poner id autoincremental en tabla historial
3- Hacer el update:
UPDATE historial
SET vehiculo_id = (
SELECT id
FROM vehiculos
WHERE vehiculos.m_oficial = historial.matricula
);
4- Ordenar los campos de las tablas, con este orden:
+4
View File
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="#currentColor" viewBox="0 0 16 16">
<path d="M4 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0m10 0a1 1 0 1 1-2 0 1 1 0 0 1 2 0M6 8a1 1 0 0 0 0 2h4a1 1 0 1 0 0-2zM4.862 4.276 3.906 6.19a.51.51 0 0 0 .497.731c.91-.073 2.35-.17 3.597-.17s2.688.097 3.597.17a.51.51 0 0 0 .497-.731l-.956-1.913A.5.5 0 0 0 10.691 4H5.309a.5.5 0 0 0-.447.276"/>
<path d="M2.52 3.515A2.5 2.5 0 0 1 4.82 2h6.362c1 0 1.904.596 2.298 1.515l.792 1.848c.075.175.21.319.38.404.5.25.855.715.965 1.262l.335 1.679q.05.242.049.49v.413c0 .814-.39 1.543-1 1.997V13.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-1.338c-1.292.048-2.745.088-4 .088s-2.708-.04-4-.088V13.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-1.892c-.61-.454-1-1.183-1-1.997v-.413a2.5 2.5 0 0 1 .049-.49l.335-1.68c.11-.546.465-1.012.964-1.261a.8.8 0 0 0 .381-.404l.792-1.848ZM4.82 3a1.5 1.5 0 0 0-1.379.91l-.792 1.847a1.8 1.8 0 0 1-.853.904.8.8 0 0 0-.43.564L1.03 8.904a1.5 1.5 0 0 0-.03.294v.413c0 .796.62 1.448 1.408 1.484 1.555.07 3.786.155 5.592.155s4.037-.084 5.592-.155A1.48 1.48 0 0 0 15 9.611v-.413q0-.148-.03-.294l-.335-1.68a.8.8 0 0 0-.43-.563 1.8 1.8 0 0 1-.853-.904l-.792-1.848A1.5 1.5 0 0 0 11.18 3z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+55
View File
@@ -0,0 +1,55 @@
id,tipo,denominacion
1,AUTOCAR 21 A 40 PAX,
2,AUTOCAR > 40 PAX,
3,FURGON,
4,"CAMION < 3,5 TM",
5,"CAMION > 3,5 TM",
6,CANIOB DE CABALLOS,
7,CELULAR,
8,CICLOMOTOR,
9,CTRL. MOVIL FRONTERA,
10,EMBARCACION,
11,ESTACIONES ITV,
12,FURGON APOLO,
13,FURGON EDEX,
14,FURGON G.CANINOS,
15,FURGON GOES,
16,FURGON MINI APOLO,
17,FURGON U.P.R.,
18,FURGON UNIPOL F-8,
19,FURGONETA COMBI,
20,FURGONETA DE CARGA,
21,FURGONETA DNI,
22,FURGONETA DNI RURAL,
23,FURGONETA IZ,
24,FURGONETA LABORATORIO DE DOCUMENTOS FALSOS,
25,FURGONETA MIXTA,
26,FURGONETA P.CIENTIFICA,
27,FURGONETA SUBSUELO,
28,GRUA,
29,GRUPO ELECTROGENO,
30,LANZA-AGUA,
31,MAXI-Z,
32,MICROBUS 10 A 20 PAX,
33,MOTOCICLETA TIPO K,
34,MOTOCICLETA TIPO Q,
35,MOTOCICLETA UNIFORMADA,
36,POLICIA TECN.ESPECIALIDAD,
37,PUESTO DE MANDO AVANZADO,
38,REMOLQUE <750 KG,
39,REMOLQUE >750 KG,
40,TANQUETA,
41,TODO CAMINO,
42,TODO TERRENO,
43,TRACTOR TIPO EINSA,
44,TRANSPORTE SANITARIO,
45,TRASLADO EXTRANJEROS,
46,TURISMO K,
47,TURISMO Q,
48,TURISMO Z,
49,TURISMO Z COORDINACION,
50,UNIDAD MOVIL DE DOCUMENTACION (VIDOC),
51,UNIDAD MOVIL FRONTERAS,
52,VARIOS SIN CLASIFICAR,
53,VEHICULO ELECTRICO NO HOMOLOGADO,
54,VEHICULO ELECTRICO UNIF. HOMOLOGADO,
1 id tipo denominacion
2 1 AUTOCAR 21 A 40 PAX
3 2 AUTOCAR > 40 PAX
4 3 FURGON
5 4 CAMION < 3,5 TM
6 5 CAMION > 3,5 TM
7 6 CANIOB DE CABALLOS
8 7 CELULAR
9 8 CICLOMOTOR
10 9 CTRL. MOVIL FRONTERA
11 10 EMBARCACION
12 11 ESTACIONES ITV
13 12 FURGON APOLO
14 13 FURGON EDEX
15 14 FURGON G.CANINOS
16 15 FURGON GOES
17 16 FURGON MINI APOLO
18 17 FURGON U.P.R.
19 18 FURGON UNIPOL F-8
20 19 FURGONETA COMBI
21 20 FURGONETA DE CARGA
22 21 FURGONETA DNI
23 22 FURGONETA DNI RURAL
24 23 FURGONETA IZ
25 24 FURGONETA LABORATORIO DE DOCUMENTOS FALSOS
26 25 FURGONETA MIXTA
27 26 FURGONETA P.CIENTIFICA
28 27 FURGONETA SUBSUELO
29 28 GRUA
30 29 GRUPO ELECTROGENO
31 30 LANZA-AGUA
32 31 MAXI-Z
33 32 MICROBUS 10 A 20 PAX
34 33 MOTOCICLETA TIPO K
35 34 MOTOCICLETA TIPO Q
36 35 MOTOCICLETA UNIFORMADA
37 36 POLICIA TECN.ESPECIALIDAD
38 37 PUESTO DE MANDO AVANZADO
39 38 REMOLQUE <750 KG
40 39 REMOLQUE >750 KG
41 40 TANQUETA
42 41 TODO CAMINO
43 42 TODO TERRENO
44 43 TRACTOR TIPO EINSA
45 44 TRANSPORTE SANITARIO
46 45 TRASLADO EXTRANJEROS
47 46 TURISMO K
48 47 TURISMO Q
49 48 TURISMO Z
50 49 TURISMO Z COORDINACION
51 50 UNIDAD MOVIL DE DOCUMENTACION (VIDOC)
52 51 UNIDAD MOVIL FRONTERAS
53 52 VARIOS SIN CLASIFICAR
54 53 VEHICULO ELECTRICO NO HOMOLOGADO
55 54 VEHICULO ELECTRICO UNIF. HOMOLOGADO
@@ -1,55 +0,0 @@
tipo,denominacion
AUTOCAR 21 A 40 PAX,
AUTOCAR > 40 PAX,
FURGON,
"CAMION < 3,5 TM",
"CAMION > 3,5 TM",
CANIOB DE CABALLOS,
CELULAR,
CICLOMOTOR,
CTRL. MOVIL FRONTERA,
EMBARCACION,
ESTACIONES ITV,
FURGON APOLO,
FURGON EDEX,
FURGON G.CANINOS,
FURGON GOES,
FURGON MINI APOLO,
FURGON U.P.R.,
FURGON UNIPOL F-8,
FURGONETA COMBI,
FURGONETA DE CARGA,
FURGONETA DNI,
FURGONETA DNI RURAL,
FURGONETA IZ,
FURGONETA LABORATORIO DE DOCUMENTOS FALSOS,
FURGONETA MIXTA,
FURGONETA P.CIENTIFICA,
FURGONETA SUBSUELO,
GRUA,
GRUPO ELECTROGENO,
LANZA-AGUA,
MAXI-Z,
MICROBUS 10 A 20 PAX,
MOTOCICLETA TIPO K,
MOTOCICLETA TIPO Q,
MOTOCICLETA UNIFORMADA,
POLICIA TECN.ESPECIALIDAD,
PUESTO DE MANDO AVANZADO,
REMOLQUE <750 KG,
REMOLQUE >750 KG,
TANQUETA,
TODO CAMINO,
TODO TERRENO,
TRACTOR TIPO EINSA,
TRANSPORTE SANITARIO,
TRASLADO EXTRANJEROS,
TURISMO K,
TURISMO Q,
TURISMO Z,
TURISMO Z COORDINACION,
UNIDAD MOVIL DE DOCUMENTACION (VIDOC),
UNIDAD MOVIL FRONTERAS,
VARIOS SIN CLASIFICAR ,
VEHICULO ELECTRICO NO HOMOLOGADO ,
VEHICULO ELECTRICO UNIF. HOMOLOGADO
1 tipo denominacion
2 AUTOCAR 21 A 40 PAX
3 AUTOCAR > 40 PAX
4 FURGON
5 CAMION < 3,5 TM
6 CAMION > 3,5 TM
7 CANIOB DE CABALLOS
8 CELULAR
9 CICLOMOTOR
10 CTRL. MOVIL FRONTERA
11 EMBARCACION
12 ESTACIONES ITV
13 FURGON APOLO
14 FURGON EDEX
15 FURGON G.CANINOS
16 FURGON GOES
17 FURGON MINI APOLO
18 FURGON U.P.R.
19 FURGON UNIPOL F-8
20 FURGONETA COMBI
21 FURGONETA DE CARGA
22 FURGONETA DNI
23 FURGONETA DNI RURAL
24 FURGONETA IZ
25 FURGONETA LABORATORIO DE DOCUMENTOS FALSOS
26 FURGONETA MIXTA
27 FURGONETA P.CIENTIFICA
28 FURGONETA SUBSUELO
29 GRUA
30 GRUPO ELECTROGENO
31 LANZA-AGUA
32 MAXI-Z
33 MICROBUS 10 A 20 PAX
34 MOTOCICLETA TIPO K
35 MOTOCICLETA TIPO Q
36 MOTOCICLETA UNIFORMADA
37 POLICIA TECN.ESPECIALIDAD
38 PUESTO DE MANDO AVANZADO
39 REMOLQUE <750 KG
40 REMOLQUE >750 KG
41 TANQUETA
42 TODO CAMINO
43 TODO TERRENO
44 TRACTOR TIPO EINSA
45 TRANSPORTE SANITARIO
46 TRASLADO EXTRANJEROS
47 TURISMO K
48 TURISMO Q
49 TURISMO Z
50 TURISMO Z COORDINACION
51 UNIDAD MOVIL DE DOCUMENTACION (VIDOC)
52 UNIDAD MOVIL FRONTERAS
53 VARIOS SIN CLASIFICAR
54 VEHICULO ELECTRICO NO HOMOLOGADO
55 VEHICULO ELECTRICO UNIF. HOMOLOGADO
+242 -248
View File
@@ -1,248 +1,242 @@
id,unidad,poblacion_id
1,AEROPUERTO,1
2,AUTOMOCION,1
32,BPEF,1
33,BPEF - PUERTO,1
34,BPEF - UCRIF 1,1
35,BPEF - UCRIF 2,1
36,BPEF - UCRIF 3,1
37,BPEF - UCRIF 4,1
38,BPEF - UCRIF 5 EXPULSIONES,1
39,BPEF - UCRIF 6,1
40,BPEF - UDEX,1
41,BPI,1
42,BPI - INFORMACION 1,1
43,BPI - INFORMACION 2,1
44,BPI - INFORMACION 3,1
45,BPI - INFORMACION 4,1
46,BPI - INFORMACION 5,1
47,BPI - TEDAX NRBQ,1
48,BPPC,1
49,BPPJ,1
50,BPPJ - UDEV ATRACOS,1
51,BPPJ - UDEV AUDIENCIA PROVINCIAL,1
52,BPPJ - UDEV CIBERDELINCUENCIA 1,1
53,BPPJ - UDEV CIBERDELINCUENCIA 2,1
54,BPPJ - UDEV HOMICIDIOS,1
55,BPPJ - UDEV HURTOS,1
56,BPPJ - UDEV JEFE,1
57,BPPJ - UDEV JEFE SECCION,1
58,BPPJ - UDEV ROBOS 1,1
59,BPPJ - UDEV ROBOS 2,1
60,BPPJ - UDEV UFAM GRUME,1
61,BPPJ - UDEV UFAM PROTECCION,1
62,BPSC,1
63,BPSC - BRIGADA MOVIL,1
64,BPSC - CELULAR CONDUCCIONES,1
65,BPSC - ESCOLTAS,1
66,BPSC - GUIAS CANINOS,1
67,BPSC - INIDAD TERROTORIAL DE SEGURIDAD PRIVADA,1
68,BPSC - PARTICIPACION CIUDADANA,1
69,BPSC - PLANIFICACION,1
70,BPSC - SALA 091,1
71,BPSC - SUBSUELO,1
72,BPSC - UPR 1,1
73,BPSC - UPR 2,1
74,BPSC - UPS,1
75,DISTRITO CENTRO,1
76,DISTRITO ESTE,1
77,DISTRITO NORTE,1
78,DISTRITO NORTE - GRUPO 1,1
79,DISTRITO NORTE - GRUPO 2,1
80,DISTRITO OESTE,1
81,DISTRITO OESTE - GRUPO 1,1
82,DISTRITO OESTE - GRUPO 2,1
83,JEFATURA COMISARIO PRINCIPAL,1
84,JEFATURA COMISARIA,1
85,SECRETARIA,1
86,SECRETARIA GENERAL,1
87,SECRETARIA GENERAL - ASUNTOS LEGALES,1
88,SECRETARIA GENERAL - INFORMATICA,1
89,SECRETARIA GENERAL - INSTALACIONES,1
90,SECRETARIA GENERAL - MATERIAL,1
91,SECRETARIA GENERAL - TELECOMUNICACIONES,1
92,SECRETARIA GENERAL- NUCLEO RESERVA,1
96,UCOP,1
97,UCOP - GABINETE TECNICO,1
98,UCOP - GOES,1
99,UCOP - GOTHAM,1
100,UCOP - HELICOPTEROS,1
101,UCOP - OMEGA,1
102,UCOP - RICO 20,1
103,UCOP - SISTEMAS ESPECIALES 1,1
104,UCOP - SISTEMAS ESPECIALES 2,1
105,UCOP - UVAO,1
106,UDEF,1
107,UDEF - BLANQUEO 1,1
108,UDEF - BLANQUEO 2,1
109,UDEF - BLANQUEO 3,1
110,UDEF - DELITOS ECONOMICOS 1,1
111,UDEF - DELITOS ECONOMICOS 2,1
112,UDEF - IPLA,1
113,UDYCO,1
114,UDYCO - APOLO,1
115,UDYCO - CRIMEN ORGANIZADO 1,1
116,UDYCO - CRIMEN ORGANIZADO 2,1
117,UDYCO - CRIMEN ORGANIZADO 3,1
118,UDYCO - CRIMEN ORGANIZADO 4,1
119,UDYCO - ESTUPEFACIENTES,1
120,UDYCO - ESTUPEFACIENTES 1,1
121,UDYCO - ESTUPEFACIENTES 2,1
122,UDYCO - ESTUPEFACIENTES 3,1
123,UDYCO - ESTUPEFACIENTES 4,1
124,UDYCO - FUENTES,1
125,UIP,1
143,BLEF,2
145,BLI,2
147,BLPC,2
148,BLPJ,2
149,BLPJ - PATRIMONIO,2
151,BLPJ - DELINCUENCIA ECONOMICA,2
152,BLPJ - DELINCUENCIA URBANA,2
156,BLPJ - FRAUDES,2
157,BLPJ - HURTOS,2
158,BLPJ - INFORMES,2
159,BLPJ - JEFATURA,2
160,BLPJ - PATRIMONIO,2
161,BLPJ - PEQUEÑO TRAFICO,2
162,BLPJ - PERSONAS,2
163,BLPJ - ROBOS,2
165,BLPJ - UDEV,2
168,BLPJ - UFAM,2
170,BLSC,2
171,BLSC - UPR,2
172,JEFATURA COMISARIA,2
173,SECRETARIA,2
174,UCOL,2
175,BLEF,3
176,BLI,3
177,BLPC,3
178,BLPJ,3
179,BLPJ - PATRIMONIO,3
180,BLPJ - DELINCUENCIA ECONOMICA,3
181,BLPJ - DELINCUENCIA URBANA,3
183,BLPJ - FRAUDES,3
184,BLPJ - HURTOS,3
185,BLPJ - INFORMES,3
186,BLPJ - JEFATURA,3
187,BLPJ - PATRIMONIO,3
188,BLPJ - PEQUEÑO TRAFICO,3
189,BLPJ - PERSONAS,3
190,BLPJ - ROBOS,3
191,BLPJ - UDEV,3
192,BLPJ - UFAM,3
193,BLSC,3
194,BLSC - UPR,3
195,JEFATURA COMISARIA,3
196,SECRETARIA,3
197,UCOL,3
198,BLEF,4
199,BLI,4
200,BLPC,4
201,BLPJ,4
202,BLPJ - PATRIMONIO,4
203,BLPJ - DELINCUENCIA ECONOMICA,4
205,BLPJ - DELINCUENCIA URBANA,4
206,BLPJ - FRAUDES,4
207,BLPJ - HURTOS,4
208,BLPJ - INFORMES,4
209,BLPJ - JEFATURA,4
210,BLPJ - PATRIMONIO,4
211,BLPJ - PEQUEÑO TRAFICO,4
212,BLPJ - PERSONAS,4
213,BLPJ - ROBOS,4
214,BLPJ - UDEV,4
215,BLPJ - UFAM,4
216,BLSC,4
217,BLSC - UPR,4
218,JEFATURA COMISARIA,4
219,SECRETARIA,4
220,UCOL,4
221,BLEF,5
222,BLI,5
223,BLPC,5
224,BLPJ,5
225,BLPJ - PATRIMONIO,5
226,BLPJ - DELINCUENCIA ECONOMICA,5
228,BLPJ - DELINCUENCIA URBANA,5
229,BLPJ - FRAUDES,5
230,BLPJ - HURTOS,5
231,BLPJ - INFORMES,5
232,BLPJ - JEFATURA,5
233,BLPJ - PATRIMONIO,5
234,BLPJ - PEQUEÑO TRAFICO,5
235,BLPJ - PERSONAS,5
236,BLPJ - ROBOS,5
237,BLPJ - UDEV,5
238,BLPJ - UFAM,5
239,BLSC,5
240,BLSC - UPR,5
241,JEFATURA COMISARIA,5
242,SECRETARIA,5
243,UCOL,5
244,BLEF,6
245,BLI,6
246,BLPC,6
247,BLPJ,6
248,BLPJ - PATRIMONIO,6
249,BLPJ - DELINCUENCIA ECONOMICA,6
251,BLPJ - DELINCUENCIA URBANA,6
252,BLPJ - FRAUDES,6
253,BLPJ - HURTOS,6
254,BLPJ - INFORMES,6
255,BLPJ - JEFATURA,6
256,BLPJ - PATRIMONIO,6
257,BLPJ - PEQUEÑO TRAFICO,6
258,BLPJ - PERSONAS,6
259,BLPJ - ROBOS,6
260,BLPJ - UDEV,6
261,BLPJ - UFAM,6
262,BLSC,6
263,BLSC - UPR,6
264,JEFATURA COMISARIA,6
265,SECRETARIA,6
266,UCOL,6
267,BLEF,7
268,BLI,7
269,BLPC,7
270,BLPJ,7
271,BLPJ - PATRIMONIO,7
272,BLPJ - DELINCUENCIA ECONOMICA,7
274,BLPJ - DELINCUENCIA URBANA,7
275,BLPJ - FRAUDES,7
276,BLPJ - HURTOS,7
277,BLPJ - INFORMES,7
278,BLPJ - JEFATURA,7
279,BLPJ - PATRIMONIO,7
280,BLPJ - PEQUEÑO TRAFICO,7
281,BLPJ - PERSONAS,7
282,BLPJ - ROBOS,7
283,BLPJ - UDEV,7
284,BLPJ - UFAM,7
285,BLSC,7
286,BLSC - UPR,7
287,JEFATURA COMISARIA,7
288,SECRETARIA,7
289,UCOL,7
290,BLEF,8
291,BLI,8
292,BLPC,8
293,BLPJ,8
294,BLPJ - PATRIMONIO,8
295,BLPJ - DELINCUENCIA ECONOMICA,8
297,BLPJ - DELINCUENCIA URBANA,8
298,BLPJ - FRAUDES,8
299,BLPJ - HURTOS,8
300,BLPJ - INFORMES,8
301,BLPJ - JEFATURA,8
302,BLPJ - PATRIMONIO,8
303,BLPJ - PEQUEÑO TRAFICO,8
304,BLPJ - PERSONAS,8
305,BLPJ - ROBOS,8
306,BLPJ - UDEV,8
307,BLPJ - UFAM,8
308,BLSC,8
309,BLSC - UPR,8
310,JEFATURA COMISARIA,8
311,SECRETARIA,8
312,UCOL,8
id,unidad,poblacion_id
1,AEROPUERTO,1
2,AUTOMOCION,1
32,BPEF,1
33,BPEF - PUERTO,1
34,BPEF - UCRIF 1,1
35,BPEF - UCRIF 2,1
36,BPEF - UCRIF 3,1
37,BPEF - UCRIF 4,1
38,BPEF - UCRIF 5 EXPULSIONES,1
39,BPEF - UCRIF 6,1
40,BPEF - UDEX,1
41,BPI,1
42,BPI - INFORMACION 1,1
43,BPI - INFORMACION 2,1
44,BPI - INFORMACION 3,1
45,BPI - INFORMACION 4,1
46,BPI - INFORMACION 5,1
47,BPI - TEDAX NRBQ,1
48,BPPC,1
49,BPPJ,1
313,BPPJ - UDEV,1
50,BPPJ - UDEV ATRACOS,1
51,BPPJ - UDEV AUDIENCIA PROVINCIAL,1
52,BPPJ - UDEV CIBERDELINCUENCIA 1,1
53,BPPJ - UDEV CIBERDELINCUENCIA 2,1
54,BPPJ - UDEV HOMICIDIOS,1
55,BPPJ - UDEV HURTOS,1
56,BPPJ - UDEV JEFATURA,1
57,BPPJ - UDEV JEFATURA SECCION,1
58,BPPJ - UDEV ROBOS 1,1
59,BPPJ - UDEV ROBOS 2,1
60,BPPJ - UDEV UFAM GRUME,1
61,BPPJ - UDEV UFAM PROTECCION,1
62,BPSC,1
63,BPSC - BRIGADA MOVIL,1
64,BPSC - CELULAR CONDUCCIONES,1
65,BPSC - ESCOLTAS,1
66,BPSC - GUIAS CANINOS,1
67,BPSC - INIDAD TERROTORIAL DE SEGURIDAD PRIVADA,1
68,BPSC - PARTICIPACION CIUDADANA,1
69,BPSC - PLANIFICACION,1
70,BPSC - SALA 091,1
71,BPSC - SUBSUELO,1
72,BPSC - UPR 1,1
73,BPSC - UPR 2,1
74,BPSC - UPS,1
75,DISTRITO CENTRO,1
76,DISTRITO ESTE,1
77,DISTRITO NORTE,1
78,DISTRITO NORTE - GRUPO 1,1
79,DISTRITO NORTE - GRUPO 2,1
80,DISTRITO OESTE,1
81,DISTRITO OESTE - GRUPO 1,1
82,DISTRITO OESTE - GRUPO 2,1
83,JEFATURA COMISARIO PRINCIPAL,1
84,JEFATURA COMISARIA,1
85,SECRETARIA,1
86,SECRETARIA GENERAL,1
87,SECRETARIA GENERAL - ASUNTOS LEGALES,1
88,SECRETARIA GENERAL - INFORMATICA,1
89,SECRETARIA GENERAL - INSTALACIONES,1
90,SECRETARIA GENERAL - MATERIAL,1
91,SECRETARIA GENERAL - TELECOMUNICACIONES,1
92,SECRETARIA GENERAL - NUCLEO RESERVA,1
96,UCOP,1
97,UCOP - GABINETE TECNICO,1
98,UCOP - GOES,1
99,UCOP - GOTHAM,1
100,UCOP - HELICOPTEROS,1
101,UCOP - OMEGA,1
102,UCOP - RICO 20,1
103,UCOP - SISTEMAS ESPECIALES 1,1
104,UCOP - SISTEMAS ESPECIALES 2,1
105,UCOP - UVAO,1
106,UDEF,1
107,UDEF - BLANQUEO 1,1
108,UDEF - BLANQUEO 2,1
109,UDEF - BLANQUEO 3,1
110,UDEF - DELITOS ECONOMICOS 1,1
111,UDEF - DELITOS ECONOMICOS 2,1
112,UDEF - IPLA,1
113,UDYCO,1
114,UDYCO - APOLO,1
115,UDYCO - CRIMEN ORGANIZADO 1,1
116,UDYCO - CRIMEN ORGANIZADO 2,1
117,UDYCO - CRIMEN ORGANIZADO 3,1
118,UDYCO - CRIMEN ORGANIZADO 4,1
119,UDYCO - ESTUPEFACIENTES,1
120,UDYCO - ESTUPEFACIENTES 1,1
121,UDYCO - ESTUPEFACIENTES 2,1
122,UDYCO - ESTUPEFACIENTES 3,1
123,UDYCO - ESTUPEFACIENTES 4,1
124,UDYCO - FUENTES,1
125,UIP,1
143,BLEF,2
145,BLI,2
147,BLPC,2
148,BLPJ,2
149,BLPJ - PATRIMONIO,2
151,BLPJ - DELINCUENCIA ECONOMICA,2
152,BLPJ - DELINCUENCIA URBANA,2
156,BLPJ - FRAUDES,2
157,BLPJ - HURTOS,2
158,BLPJ - INFORMES,2
159,BLPJ - JEFATURA,2
161,BLPJ - PEQUEÑO TRAFICO,2
162,BLPJ - PERSONAS,2
163,BLPJ - ROBOS,2
165,BLPJ - UDEV,2
168,BLPJ - UFAM,2
170,BLSC,2
171,BLSC - UPR,2
172,JEFATURA COMISARIA,2
173,SECRETARIA,2
174,UCOL,2
175,BLEF,3
176,BLI,3
177,BLPC,3
178,BLPJ,3
180,BLPJ - DELINCUENCIA ECONOMICA,3
181,BLPJ - DELINCUENCIA URBANA,3
183,BLPJ - FRAUDES,3
184,BLPJ - HURTOS,3
185,BLPJ - INFORMES,3
186,BLPJ - JEFATURA,3
187,BLPJ - PATRIMONIO,3
188,BLPJ - PEQUEÑO TRAFICO,3
189,BLPJ - PERSONAS,3
190,BLPJ - ROBOS,3
191,BLPJ - UDEV,3
192,BLPJ - UFAM,3
193,BLSC,3
194,BLSC - UPR,3
195,JEFATURA COMISARIA,3
196,SECRETARIA,3
197,UCOL,3
198,BLEF,4
199,BLI,4
200,BLPC,4
201,BLPJ,4
203,BLPJ - DELINCUENCIA ECONOMICA,4
205,BLPJ - DELINCUENCIA URBANA,4
206,BLPJ - FRAUDES,4
207,BLPJ - HURTOS,4
208,BLPJ - INFORMES,4
209,BLPJ - JEFATURA,4
210,BLPJ - PATRIMONIO,4
211,BLPJ - PEQUEÑO TRAFICO,4
212,BLPJ - PERSONAS,4
213,BLPJ - ROBOS,4
214,BLPJ - UDEV,4
215,BLPJ - UFAM,4
216,BLSC,4
217,BLSC - UPR,4
218,JEFATURA COMISARIA,4
219,SECRETARIA,4
220,UCOL,4
221,BLEF,5
222,BLI,5
223,BLPC,5
224,BLPJ,5
226,BLPJ - DELINCUENCIA ECONOMICA,5
228,BLPJ - DELINCUENCIA URBANA,5
229,BLPJ - FRAUDES,5
230,BLPJ - HURTOS,5
231,BLPJ - INFORMES,5
232,BLPJ - JEFATURA,5
233,BLPJ - PATRIMONIO,5
234,BLPJ - PEQUEÑO TRAFICO,5
235,BLPJ - PERSONAS,5
236,BLPJ - ROBOS,5
237,BLPJ - UDEV,5
238,BLPJ - UFAM,5
239,BLSC,5
240,BLSC - UPR,5
241,JEFATURA COMISARIA,5
242,SECRETARIA,5
243,UCOL,5
244,BLEF,6
245,BLI,6
246,BLPC,6
247,BLPJ,6
249,BLPJ - DELINCUENCIA ECONOMICA,6
251,BLPJ - DELINCUENCIA URBANA,6
252,BLPJ - FRAUDES,6
253,BLPJ - HURTOS,6
254,BLPJ - INFORMES,6
255,BLPJ - JEFATURA,6
256,BLPJ - PATRIMONIO,6
257,BLPJ - PEQUEÑO TRAFICO,6
258,BLPJ - PERSONAS,6
259,BLPJ - ROBOS,6
260,BLPJ - UDEV,6
261,BLPJ - UFAM,6
262,BLSC,6
263,BLSC - UPR,6
264,JEFATURA COMISARIA,6
265,SECRETARIA,6
266,UCOL,6
267,BLEF,7
268,BLI,7
269,BLPC,7
270,BLPJ,7
272,BLPJ - DELINCUENCIA ECONOMICA,7
274,BLPJ - DELINCUENCIA URBANA,7
275,BLPJ - FRAUDES,7
276,BLPJ - HURTOS,7
277,BLPJ - INFORMES,7
278,BLPJ - JEFATURA,7
279,BLPJ - PATRIMONIO,7
280,BLPJ - PEQUEÑO TRAFICO,7
281,BLPJ - PERSONAS,7
282,BLPJ - ROBOS,7
283,BLPJ - UDEV,7
284,BLPJ - UFAM,7
285,BLSC,7
286,BLSC - UPR,7
287,JEFATURA COMISARIA,7
288,SECRETARIA,7
289,UCOL,7
290,BLEF,8
291,BLI,8
292,BLPC,8
293,BLPJ,8
295,BLPJ - DELINCUENCIA ECONOMICA,8
297,BLPJ - DELINCUENCIA URBANA,8
298,BLPJ - FRAUDES,8
299,BLPJ - HURTOS,8
300,BLPJ - INFORMES,8
301,BLPJ - JEFATURA,8
302,BLPJ - PATRIMONIO,8
303,BLPJ - PEQUEÑO TRAFICO,8
304,BLPJ - PERSONAS,8
305,BLPJ - ROBOS,8
306,BLPJ - UDEV,8
307,BLPJ - UFAM,8
308,BLSC,8
309,BLSC - UPR,8
310,JEFATURA COMISARIA,8
311,SECRETARIA,8
312,UCOL,8
1 id unidad poblacion_id
2 1 AEROPUERTO 1
3 2 AUTOMOCION 1
4 32 BPEF 1
5 33 BPEF - PUERTO 1
6 34 BPEF - UCRIF 1 1
7 35 BPEF - UCRIF 2 1
8 36 BPEF - UCRIF 3 1
9 37 BPEF - UCRIF 4 1
10 38 BPEF - UCRIF 5 EXPULSIONES 1
11 39 BPEF - UCRIF 6 1
12 40 BPEF - UDEX 1
13 41 BPI 1
14 42 BPI - INFORMACION 1 1
15 43 BPI - INFORMACION 2 1
16 44 BPI - INFORMACION 3 1
17 45 BPI - INFORMACION 4 1
18 46 BPI - INFORMACION 5 1
19 47 BPI - TEDAX NRBQ 1
20 48 BPPC 1
21 49 BPPJ 1
22 50 313 BPPJ - UDEV ATRACOS BPPJ - UDEV 1
23 51 50 BPPJ - UDEV AUDIENCIA PROVINCIAL BPPJ - UDEV ATRACOS 1
24 52 51 BPPJ - UDEV CIBERDELINCUENCIA 1 BPPJ - UDEV AUDIENCIA PROVINCIAL 1
25 53 52 BPPJ - UDEV CIBERDELINCUENCIA 2 BPPJ - UDEV CIBERDELINCUENCIA 1 1
26 54 53 BPPJ - UDEV HOMICIDIOS BPPJ - UDEV CIBERDELINCUENCIA 2 1
27 55 54 BPPJ - UDEV HURTOS BPPJ - UDEV HOMICIDIOS 1
28 56 55 BPPJ - UDEV JEFE BPPJ - UDEV HURTOS 1
29 57 56 BPPJ - UDEV JEFE SECCION BPPJ - UDEV JEFATURA 1
30 58 57 BPPJ - UDEV ROBOS 1 BPPJ - UDEV JEFATURA SECCION 1
31 59 58 BPPJ - UDEV ROBOS 2 BPPJ - UDEV ROBOS 1 1
32 60 59 BPPJ - UDEV UFAM GRUME BPPJ - UDEV ROBOS 2 1
33 61 60 BPPJ - UDEV UFAM PROTECCION BPPJ - UDEV UFAM GRUME 1
34 62 61 BPSC BPPJ - UDEV UFAM PROTECCION 1
35 63 62 BPSC - BRIGADA MOVIL BPSC 1
36 64 63 BPSC - CELULAR CONDUCCIONES BPSC - BRIGADA MOVIL 1
37 65 64 BPSC - ESCOLTAS BPSC - CELULAR CONDUCCIONES 1
38 66 65 BPSC - GUIAS CANINOS BPSC - ESCOLTAS 1
39 67 66 BPSC - INIDAD TERROTORIAL DE SEGURIDAD PRIVADA BPSC - GUIAS CANINOS 1
40 68 67 BPSC - PARTICIPACION CIUDADANA BPSC - INIDAD TERROTORIAL DE SEGURIDAD PRIVADA 1
41 69 68 BPSC - PLANIFICACION BPSC - PARTICIPACION CIUDADANA 1
42 70 69 BPSC - SALA 091 BPSC - PLANIFICACION 1
43 71 70 BPSC - SUBSUELO BPSC - SALA 091 1
44 72 71 BPSC - UPR 1 BPSC - SUBSUELO 1
45 73 72 BPSC - UPR 2 BPSC - UPR 1 1
46 74 73 BPSC - UPS BPSC - UPR 2 1
47 75 74 DISTRITO CENTRO BPSC - UPS 1
48 76 75 DISTRITO ESTE DISTRITO CENTRO 1
49 77 76 DISTRITO NORTE DISTRITO ESTE 1
50 78 77 DISTRITO NORTE - GRUPO 1 DISTRITO NORTE 1
51 79 78 DISTRITO NORTE - GRUPO 2 DISTRITO NORTE - GRUPO 1 1
52 80 79 DISTRITO OESTE DISTRITO NORTE - GRUPO 2 1
53 81 80 DISTRITO OESTE - GRUPO 1 DISTRITO OESTE 1
54 82 81 DISTRITO OESTE - GRUPO 2 DISTRITO OESTE - GRUPO 1 1
55 83 82 JEFATURA COMISARIO PRINCIPAL DISTRITO OESTE - GRUPO 2 1
56 84 83 JEFATURA COMISARIA JEFATURA COMISARIO PRINCIPAL 1
57 85 84 SECRETARIA JEFATURA COMISARIA 1
58 86 85 SECRETARIA GENERAL SECRETARIA 1
59 87 86 SECRETARIA GENERAL - ASUNTOS LEGALES SECRETARIA GENERAL 1
60 88 87 SECRETARIA GENERAL - INFORMATICA SECRETARIA GENERAL - ASUNTOS LEGALES 1
61 89 88 SECRETARIA GENERAL - INSTALACIONES SECRETARIA GENERAL - INFORMATICA 1
62 90 89 SECRETARIA GENERAL - MATERIAL SECRETARIA GENERAL - INSTALACIONES 1
63 91 90 SECRETARIA GENERAL - TELECOMUNICACIONES SECRETARIA GENERAL - MATERIAL 1
64 92 91 SECRETARIA GENERAL- NUCLEO RESERVA SECRETARIA GENERAL - TELECOMUNICACIONES 1
65 96 92 UCOP SECRETARIA GENERAL - NUCLEO RESERVA 1
66 97 96 UCOP - GABINETE TECNICO UCOP 1
67 98 97 UCOP - GOES UCOP - GABINETE TECNICO 1
68 99 98 UCOP - GOTHAM UCOP - GOES 1
69 100 99 UCOP - HELICOPTEROS UCOP - GOTHAM 1
70 101 100 UCOP - OMEGA UCOP - HELICOPTEROS 1
71 102 101 UCOP - RICO 20 UCOP - OMEGA 1
72 103 102 UCOP - SISTEMAS ESPECIALES 1 UCOP - RICO 20 1
73 104 103 UCOP - SISTEMAS ESPECIALES 2 UCOP - SISTEMAS ESPECIALES 1 1
74 105 104 UCOP - UVAO UCOP - SISTEMAS ESPECIALES 2 1
75 106 105 UDEF UCOP - UVAO 1
76 107 106 UDEF - BLANQUEO 1 UDEF 1
77 108 107 UDEF - BLANQUEO 2 UDEF - BLANQUEO 1 1
78 109 108 UDEF - BLANQUEO 3 UDEF - BLANQUEO 2 1
79 110 109 UDEF - DELITOS ECONOMICOS 1 UDEF - BLANQUEO 3 1
80 111 110 UDEF - DELITOS ECONOMICOS 2 UDEF - DELITOS ECONOMICOS 1 1
81 112 111 UDEF - IPLA UDEF - DELITOS ECONOMICOS 2 1
82 113 112 UDYCO UDEF - IPLA 1
83 114 113 UDYCO - APOLO UDYCO 1
84 115 114 UDYCO - CRIMEN ORGANIZADO 1 UDYCO - APOLO 1
85 116 115 UDYCO - CRIMEN ORGANIZADO 2 UDYCO - CRIMEN ORGANIZADO 1 1
86 117 116 UDYCO - CRIMEN ORGANIZADO 3 UDYCO - CRIMEN ORGANIZADO 2 1
87 118 117 UDYCO - CRIMEN ORGANIZADO 4 UDYCO - CRIMEN ORGANIZADO 3 1
88 119 118 UDYCO - ESTUPEFACIENTES UDYCO - CRIMEN ORGANIZADO 4 1
89 120 119 UDYCO - ESTUPEFACIENTES 1 UDYCO - ESTUPEFACIENTES 1
90 121 120 UDYCO - ESTUPEFACIENTES 2 UDYCO - ESTUPEFACIENTES 1 1
91 122 121 UDYCO - ESTUPEFACIENTES 3 UDYCO - ESTUPEFACIENTES 2 1
92 123 122 UDYCO - ESTUPEFACIENTES 4 UDYCO - ESTUPEFACIENTES 3 1
93 124 123 UDYCO - FUENTES UDYCO - ESTUPEFACIENTES 4 1
94 125 124 UIP UDYCO - FUENTES 1
95 143 125 BLEF UIP 2 1
96 145 143 BLI BLEF 2
97 147 145 BLPC BLI 2
98 148 147 BLPJ BLPC 2
99 149 148 BLPJ - PATRIMONIO BLPJ 2
100 151 149 BLPJ - DELINCUENCIA ECONOMICA BLPJ - PATRIMONIO 2
101 152 151 BLPJ - DELINCUENCIA URBANA BLPJ - DELINCUENCIA ECONOMICA 2
102 156 152 BLPJ - FRAUDES BLPJ - DELINCUENCIA URBANA 2
103 157 156 BLPJ - HURTOS BLPJ - FRAUDES 2
104 158 157 BLPJ - INFORMES BLPJ - HURTOS 2
105 159 158 BLPJ - JEFATURA BLPJ - INFORMES 2
106 160 159 BLPJ - PATRIMONIO BLPJ - JEFATURA 2
107 161 BLPJ - PEQUEÑO TRAFICO 2
108 162 BLPJ - PERSONAS 2
109 163 BLPJ - ROBOS 2
110 165 BLPJ - UDEV 2
111 168 BLPJ - UFAM 2
112 170 BLSC 2
113 171 BLSC - UPR 2
114 172 JEFATURA COMISARIA 2
115 173 SECRETARIA 2
116 174 UCOL 2
117 175 BLEF 3
118 176 BLI 3
119 177 BLPC 3
120 178 BLPJ 3
121 179 180 BLPJ - PATRIMONIO BLPJ - DELINCUENCIA ECONOMICA 3
122 180 181 BLPJ - DELINCUENCIA ECONOMICA BLPJ - DELINCUENCIA URBANA 3
123 181 183 BLPJ - DELINCUENCIA URBANA BLPJ - FRAUDES 3
124 183 184 BLPJ - FRAUDES BLPJ - HURTOS 3
125 184 185 BLPJ - HURTOS BLPJ - INFORMES 3
126 185 186 BLPJ - INFORMES BLPJ - JEFATURA 3
127 186 187 BLPJ - JEFATURA BLPJ - PATRIMONIO 3
128 187 188 BLPJ - PATRIMONIO BLPJ - PEQUEÑO TRAFICO 3
129 188 189 BLPJ - PEQUEÑO TRAFICO BLPJ - PERSONAS 3
130 189 190 BLPJ - PERSONAS BLPJ - ROBOS 3
131 190 191 BLPJ - ROBOS BLPJ - UDEV 3
132 191 192 BLPJ - UDEV BLPJ - UFAM 3
133 192 193 BLPJ - UFAM BLSC 3
134 193 194 BLSC BLSC - UPR 3
135 194 195 BLSC - UPR JEFATURA COMISARIA 3
136 195 196 JEFATURA COMISARIA SECRETARIA 3
137 196 197 SECRETARIA UCOL 3
138 197 198 UCOL BLEF 3 4
139 198 199 BLEF BLI 4
140 199 200 BLI BLPC 4
141 200 201 BLPC BLPJ 4
142 201 203 BLPJ BLPJ - DELINCUENCIA ECONOMICA 4
143 202 205 BLPJ - PATRIMONIO BLPJ - DELINCUENCIA URBANA 4
144 203 206 BLPJ - DELINCUENCIA ECONOMICA BLPJ - FRAUDES 4
145 205 207 BLPJ - DELINCUENCIA URBANA BLPJ - HURTOS 4
146 206 208 BLPJ - FRAUDES BLPJ - INFORMES 4
147 207 209 BLPJ - HURTOS BLPJ - JEFATURA 4
148 208 210 BLPJ - INFORMES BLPJ - PATRIMONIO 4
149 209 211 BLPJ - JEFATURA BLPJ - PEQUEÑO TRAFICO 4
150 210 212 BLPJ - PATRIMONIO BLPJ - PERSONAS 4
151 211 213 BLPJ - PEQUEÑO TRAFICO BLPJ - ROBOS 4
152 212 214 BLPJ - PERSONAS BLPJ - UDEV 4
153 213 215 BLPJ - ROBOS BLPJ - UFAM 4
154 214 216 BLPJ - UDEV BLSC 4
155 215 217 BLPJ - UFAM BLSC - UPR 4
156 216 218 BLSC JEFATURA COMISARIA 4
157 217 219 BLSC - UPR SECRETARIA 4
158 218 220 JEFATURA COMISARIA UCOL 4
159 219 221 SECRETARIA BLEF 4 5
160 220 222 UCOL BLI 4 5
161 221 223 BLEF BLPC 5
162 222 224 BLI BLPJ 5
163 223 226 BLPC BLPJ - DELINCUENCIA ECONOMICA 5
164 224 228 BLPJ BLPJ - DELINCUENCIA URBANA 5
165 225 229 BLPJ - PATRIMONIO BLPJ - FRAUDES 5
166 226 230 BLPJ - DELINCUENCIA ECONOMICA BLPJ - HURTOS 5
167 228 231 BLPJ - DELINCUENCIA URBANA BLPJ - INFORMES 5
168 229 232 BLPJ - FRAUDES BLPJ - JEFATURA 5
169 230 233 BLPJ - HURTOS BLPJ - PATRIMONIO 5
170 231 234 BLPJ - INFORMES BLPJ - PEQUEÑO TRAFICO 5
171 232 235 BLPJ - JEFATURA BLPJ - PERSONAS 5
172 233 236 BLPJ - PATRIMONIO BLPJ - ROBOS 5
173 234 237 BLPJ - PEQUEÑO TRAFICO BLPJ - UDEV 5
174 235 238 BLPJ - PERSONAS BLPJ - UFAM 5
175 236 239 BLPJ - ROBOS BLSC 5
176 237 240 BLPJ - UDEV BLSC - UPR 5
177 238 241 BLPJ - UFAM JEFATURA COMISARIA 5
178 239 242 BLSC SECRETARIA 5
179 240 243 BLSC - UPR UCOL 5
180 241 244 JEFATURA COMISARIA BLEF 5 6
181 242 245 SECRETARIA BLI 5 6
182 243 246 UCOL BLPC 5 6
183 244 247 BLEF BLPJ 6
184 245 249 BLI BLPJ - DELINCUENCIA ECONOMICA 6
185 246 251 BLPC BLPJ - DELINCUENCIA URBANA 6
186 247 252 BLPJ BLPJ - FRAUDES 6
187 248 253 BLPJ - PATRIMONIO BLPJ - HURTOS 6
188 249 254 BLPJ - DELINCUENCIA ECONOMICA BLPJ - INFORMES 6
189 251 255 BLPJ - DELINCUENCIA URBANA BLPJ - JEFATURA 6
190 252 256 BLPJ - FRAUDES BLPJ - PATRIMONIO 6
191 253 257 BLPJ - HURTOS BLPJ - PEQUEÑO TRAFICO 6
192 254 258 BLPJ - INFORMES BLPJ - PERSONAS 6
193 255 259 BLPJ - JEFATURA BLPJ - ROBOS 6
194 256 260 BLPJ - PATRIMONIO BLPJ - UDEV 6
195 257 261 BLPJ - PEQUEÑO TRAFICO BLPJ - UFAM 6
196 258 262 BLPJ - PERSONAS BLSC 6
197 259 263 BLPJ - ROBOS BLSC - UPR 6
198 260 264 BLPJ - UDEV JEFATURA COMISARIA 6
199 261 265 BLPJ - UFAM SECRETARIA 6
200 262 266 BLSC UCOL 6
201 263 267 BLSC - UPR BLEF 6 7
202 264 268 JEFATURA COMISARIA BLI 6 7
203 265 269 SECRETARIA BLPC 6 7
204 266 270 UCOL BLPJ 6 7
205 267 272 BLEF BLPJ - DELINCUENCIA ECONOMICA 7
206 268 274 BLI BLPJ - DELINCUENCIA URBANA 7
207 269 275 BLPC BLPJ - FRAUDES 7
208 270 276 BLPJ BLPJ - HURTOS 7
209 271 277 BLPJ - PATRIMONIO BLPJ - INFORMES 7
210 272 278 BLPJ - DELINCUENCIA ECONOMICA BLPJ - JEFATURA 7
211 274 279 BLPJ - DELINCUENCIA URBANA BLPJ - PATRIMONIO 7
212 275 280 BLPJ - FRAUDES BLPJ - PEQUEÑO TRAFICO 7
213 276 281 BLPJ - HURTOS BLPJ - PERSONAS 7
214 277 282 BLPJ - INFORMES BLPJ - ROBOS 7
215 278 283 BLPJ - JEFATURA BLPJ - UDEV 7
216 279 284 BLPJ - PATRIMONIO BLPJ - UFAM 7
217 280 285 BLPJ - PEQUEÑO TRAFICO BLSC 7
218 281 286 BLPJ - PERSONAS BLSC - UPR 7
219 282 287 BLPJ - ROBOS JEFATURA COMISARIA 7
220 283 288 BLPJ - UDEV SECRETARIA 7
221 284 289 BLPJ - UFAM UCOL 7
222 285 290 BLSC BLEF 7 8
223 286 291 BLSC - UPR BLI 7 8
224 287 292 JEFATURA COMISARIA BLPC 7 8
225 288 293 SECRETARIA BLPJ 7 8
226 289 295 UCOL BLPJ - DELINCUENCIA ECONOMICA 7 8
227 290 297 BLEF BLPJ - DELINCUENCIA URBANA 8
228 291 298 BLI BLPJ - FRAUDES 8
229 292 299 BLPC BLPJ - HURTOS 8
230 293 300 BLPJ BLPJ - INFORMES 8
231 294 301 BLPJ - PATRIMONIO BLPJ - JEFATURA 8
232 295 302 BLPJ - DELINCUENCIA ECONOMICA BLPJ - PATRIMONIO 8
233 297 303 BLPJ - DELINCUENCIA URBANA BLPJ - PEQUEÑO TRAFICO 8
234 298 304 BLPJ - FRAUDES BLPJ - PERSONAS 8
235 299 305 BLPJ - HURTOS BLPJ - ROBOS 8
236 300 306 BLPJ - INFORMES BLPJ - UDEV 8
237 301 307 BLPJ - JEFATURA BLPJ - UFAM 8
238 302 308 BLPJ - PATRIMONIO BLSC 8
239 303 309 BLPJ - PEQUEÑO TRAFICO BLSC - UPR 8
240 304 310 BLPJ - PERSONAS JEFATURA COMISARIA 8
241 305 311 BLPJ - ROBOS SECRETARIA 8
242 306 312 BLPJ - UDEV UCOL 8
307 BLPJ - UFAM 8
308 BLSC 8
309 BLSC - UPR 8
310 JEFATURA COMISARIA 8
311 SECRETARIA 8
312 UCOL 8
+81 -16
View File
@@ -10,6 +10,7 @@
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='car-front.svg') }}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/animate.min.css') }}">
@@ -18,17 +19,19 @@
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* original */
:root {
--bg: #0d0f14;
--surface: #13161e;
--nav-bg: #0a0c10;
--border: #1e2230;
--accent: #5c6ef8;
--accent2: #8b5cf6;
--text: #e2e6f0;
--muted: #5a607a;
--pill-bg: #1a1f2e;
--success: #34d399;
--bg: #0a111f;
--surface: #101a2e;
--nav-bg: #080e19;
--border: #1d2b45;
--accent: #3b82f6;
--accent2: #06b6d4;
--text: #e8f0ff;
--muted: #71819c;
--pill-bg: #17243a;
--success: #22c7e8;
--nav-w: 220px;
--radius: 12px;
}
@@ -38,14 +41,73 @@
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #e3e6ef;
--accent: #5c6ef8;
--accent2: #8b5cf6;
--accent: #2563eb;
--accent2: #4f8df7;
--text: #1a1d29;
--muted: #8a8fa3;
--pill-bg: #eef0f8;
--success: #10b981;
--success: #159dcc;
}
/* azul profundo + azul eléctrico + cyan */
/* :root {
--bg: #0d0f14;
--surface: #13161e;
--nav-bg: #0a0c10;
--border: #1e2230;
--accent: #3b82f6;
--accent2: #06b6d4;
--text: #e2e6f0;
--muted: #5a607a;
--pill-bg: #1a1f2e;
--success: #34b9e8;
--nav-w: 220px;
--radius: 12px;
}
[data-theme="light"] {
--bg: #f4f8fd;
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #dce6f2;
--accent: #2563eb;
--accent2: #0891b2;
--text: #172033;
--muted: #718096;
--pill-bg: #eaf2fc;
--success: #0891b2;
} */
/* Ambar + coral */
/* :root {
--bg: #12110f;
--surface: #1b1916;
--nav-bg: #0e0d0b;
--border: #302b25;
--accent: #f59e0b;
--accent2: #f97316;
--text: #f3eee6;
--muted: #8e877d;
--pill-bg: #28231d;
--success: #34d399;
--nav-w: 220px;
--radius: 12px;
}
[data-theme="light"] {
--bg: #faf8f4;
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #e8e1d7;
--accent: #d97706;
--accent2: #ea580c;
--text: #29251f;
--muted: #8a8278;
--pill-bg: #f6eee1;
--success: #059669;
} */
body {
background: var(--bg);
color: var(--text);
@@ -132,7 +194,10 @@
}
.nav-links a:hover { background: var(--border); color: var(--text); }
.nav-links a.active {
background: linear-gradient(135deg, rgba(92,110,248,.18), rgba(139,92,246,.1));
background: linear-gradient(135deg, rgba(30, 144, 255, 0.08), rgba(0, 51, 204, 0.25));
/* background: linear-gradient(135deg, rgba(92,110,248,.18), rgba(139,92,246,.1)); */
/* background: linear-gradient(135deg, rgba(30, 144, 255, 0.25), rgba(0, 51, 204, 0.75)); */
color: var(--text);
border: 1px solid rgba(92,110,248,.25);
}
@@ -645,7 +710,7 @@
</div>
<div class="nav-logo">
<span></span><h3>PyFleet</h3>
<span></span>PyFleet
</div>
<div class="theme-switch-row">
@@ -683,7 +748,7 @@
{% if session.get('mensaje') and page == 'contacto' %}<span class="msg-badge">!</span>{% endif %}
</a>
<div class="nav-submenu" style="margin-top: 100px;">
<div class="nav-submenu">
<hr style="opacity: 0.5;margin-bottom: 5px;">
<button class="nav-submenu-toggle {% if page in ['poblaciones','unidades','tipo'] %}active{% endif %}"
onclick="toggleSubmenu(this)">
+1 -1
View File
@@ -19,7 +19,7 @@
--bg: #f5f6fa;
--surface: #ffffff;
--border: #e3e6ef;
--accent: #5c6ef8;
--accent: #2563eb;
--text: #1a1d29;
--muted: #8a8fa3;
--error-bg: rgba(248,113,113,.1);
+12 -8
View File
@@ -333,17 +333,17 @@
<div class="form-actions" style="margin-top:28px">
<button type="submit" class="btn btn-primary"> <i class="bi bi-floppy" style="font-size: 1rem;"></i>
{{ 'GUARDAR CAMBIOS' if vehiculo else '✚ Registrar vehículo' }}
{{ 'GUARDAR CAMBIOS' if vehiculo else ' Registrar vehículo' }}
</button>
{# Cancelar #}
{% if origen == 'viat' %}
<a href="/viat?q={{ q_viat }}" class="btn btn-ghost">Cancelar</a>
<a href="/viat?q={{ q_viat }}" class="btn btn-ghost" style="background-color: gray; color: white;"><i class="bi bi-x-lg"></i>CANCELAR</a>
{% elif desde or hasta or q_itv %}
<a href="/itv?desde={{ desde }}&hasta={{ hasta }}&q_itv={{ q_itv }}" class="btn btn-ghost">Cancelar</a>
<a href="/itv?desde={{ desde }}&hasta={{ hasta }}&q_itv={{ q_itv }}" class="btn btn-ghost" style="background-color: gray; color: white;"><i class="bi bi-x-lg"></i>CANCELAR</a>
{% else %}
<a href="{{ url_for('vehiculos_list', q=q) if q else url_for('vehiculos_list') }}" class="btn btn-ghost">Cancelar</a>
<a href="{{ url_for('vehiculos_list', q=q) if q else url_for('vehiculos_list') }}" class="btn btn-ghost" style="background-color: gray; color: white;"><i class="bi bi-x-lg"></i>CANCELAR</a>
{% endif %}
<!-- <div style="display:flex;justify-content:space-between;align-items:center;margin-top:12px;"> -->
@@ -409,10 +409,12 @@
<td style="text-align:right">
<form method="POST"
action="{{ url_for('historial_eliminar', vid=vehiculo['id'], hid=h['id']) }}">
<input type="hidden" name="_q" value="{{ q|default('') }}">
<input type="hidden" name="_desde" value="{{ desde|default('') }}">
<input type="hidden" name="_hasta" value="{{ hasta|default('') }}">
<input type="hidden" name="_unidad_itv" value="{{ unidad_itv|default('') }}">
<input type="hidden" name="_q" value="{{ q|default('') }}">
<input type="hidden" name="_desde" value="{{ desde|default('') }}">
<input type="hidden" name="_hasta" value="{{ hasta|default('') }}">
<input type="hidden" name="_q_itv" value="{{ q_itv|default('') }}">
<input type="hidden" name="_origen" value="{{ origen|default('') }}">
<input type="hidden" name="_q_viat" value="{{ q_viat|default('') }}">
<button type="button" class="btn btn-danger btn-sm"
onclick="confirmarEliminar(this)">Eliminar</button>
</form>
@@ -438,6 +440,8 @@
<input type="hidden" name="_desde" value="{{ desde|default('') }}">
<input type="hidden" name="_hasta" value="{{ hasta|default('') }}">
<input type="hidden" name="_unidad_itv" value="{{ unidad_itv|default('') }}">
<input type="hidden" name="_origen" value="{{ origen|default('') }}">
<input type="hidden" name="_q_viat" value="{{ q_viat|default('') }}">
<div class="form-grid" style="margin-bottom:12px;">
<div class="form-group" style="margin-bottom:0">
+1 -1
View File
@@ -7,7 +7,7 @@
<div class="page-header">
<div class="page-eyebrow">Base de datos</div>
<div class="page-title"><i class="bi bi-taxi-front"></i> Vehículos</div>
<div class="page-subtitle">Gestión del parque móvil. Búsqueda por m.oficial, m.reservada, VIN, marca, modelo, poblacion, unidad, denominación, tipo, operacion, situacion, lanzadestellos.</div>
<div class="page-subtitle">Gestión del parque móvil. Búsqueda por m.oficial, m.reservada, VIN, marca, modelo, poblacion, unidad, tipo, situacion, lanzadestellos.</div>
</div>
<div class="crud-toolbar">
+880
View File
@@ -0,0 +1,880 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{% block title %}App{% endblock %} · PyFleet</title>
<script>
(function() {
var theme = localStorage.getItem('nexus-theme') || 'light';
document.documentElement.setAttribute('data-theme', theme);
})();
</script>
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='car-front.svg') }}">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Space+Grotesk:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/animate.min.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap-icons-1.13.1/bootstrap-icons.css') }}">
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* original */
:root {
--bg: #0a111f;
--surface: #101a2e;
--nav-bg: #080e19;
--border: #1d2b45;
--accent: #3b82f6;
--accent2: #06b6d4;
--text: #e8f0ff;
--muted: #71819c;
--pill-bg: #17243a;
--success: #22c7e8;
--nav-w: 220px;
--radius: 12px;
}
[data-theme="light"] {
--bg: #f5f6fa;
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #e3e6ef;
--accent: #2563eb;
--accent2: #4f8df7;
--text: #1a1d29;
--muted: #8a8fa3;
--pill-bg: #eef0f8;
--success: #159dcc;
}
/* azul profundo + azul eléctrico + cyan */
/* :root {
--bg: #0d0f14;
--surface: #13161e;
--nav-bg: #0a0c10;
--border: #1e2230;
--accent: #3b82f6;
--accent2: #06b6d4;
--text: #e2e6f0;
--muted: #5a607a;
--pill-bg: #1a1f2e;
--success: #34b9e8;
--nav-w: 220px;
--radius: 12px;
}
[data-theme="light"] {
--bg: #f4f8fd;
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #dce6f2;
--accent: #2563eb;
--accent2: #0891b2;
--text: #172033;
--muted: #718096;
--pill-bg: #eaf2fc;
--success: #0891b2;
} */
/* Ambar + coral */
/* :root {
--bg: #12110f;
--surface: #1b1916;
--nav-bg: #0e0d0b;
--border: #302b25;
--accent: #f59e0b;
--accent2: #f97316;
--text: #f3eee6;
--muted: #8e877d;
--pill-bg: #28231d;
--success: #34d399;
--nav-w: 220px;
--radius: 12px;
}
[data-theme="light"] {
--bg: #faf8f4;
--surface: #ffffff;
--nav-bg: #ffffff;
--border: #e8e1d7;
--accent: #d97706;
--accent2: #ea580c;
--text: #29251f;
--muted: #8a8278;
--pill-bg: #f6eee1;
--success: #059669;
} */
body {
background: var(--bg);
color: var(--text);
font-family: 'Inter', sans-serif;
font-size: 15px;
display: flex;
min-height: 100vh;
transition: background .2s ease, color .2s ease;
}
.input-disabled-look {
background-color: #f5f5f5;
color: #6c757d;
border: 1px solid #ced4da;
cursor: not-allowed;
opacity: 0.7;
pointer-events: none;
}
nav, .card, .msg-banner, .msg-form input, .nav-links a {
transition: background .2s ease, border-color .2s ease, color .2s ease;
}
/* ── NAVBAR ── */
nav {
width: var(--nav-w);
background: var(--nav-bg);
border-right: 1px solid var(--border);
display: flex;
flex-direction: column;
padding: 28px 16px 24px;
position: fixed;
top: 0; left: 0; bottom: 0;
z-index: 10;
}
.nav-logo {
font-family: 'Space Grotesk', sans-serif;
font-size: 20px;
font-weight: 700;
color: var(--text);
letter-spacing: -0.5px;
padding: 0 8px 28px;
display: flex;
align-items: center;
gap: 40px;
}
.nav-logo span.dot {
width: 8px; height: 8px;
background: var(--accent);
border-radius: 50%;
display: inline-block;
box-shadow: 0 0 8px var(--accent);
}
.nav-section-label {
font-size: 10px;
font-weight: 600;
letter-spacing: 1.2px;
text-transform: uppercase;
color: var(--muted);
padding: 0 8px 10px;
}
.nav-links {
display: flex;
flex-direction: column;
gap: 4px;
flex: 1;
}
.nav-links a {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border-radius: 8px;
text-decoration: none;
color: var(--muted);
font-size: 14px;
font-weight: 500;
transition: background 0.15s, color 0.15s;
}
.nav-links a:hover { background: var(--border); color: var(--text); }
.nav-links a.active {
background: linear-gradient(135deg, rgba(30, 144, 255, 0.08), rgba(0, 51, 204, 0.25));
/* background: linear-gradient(135deg, rgba(92,110,248,.18), rgba(139,92,246,.1)); */
/* background: linear-gradient(135deg, rgba(30, 144, 255, 0.25), rgba(0, 51, 204, 0.75)); */
color: var(--text);
border: 1px solid rgba(92,110,248,.25);
}
.nav-links a .icon {
width: 18px; height: 18px;
opacity: .6;
flex-shrink: 0;
}
.nav-links a.active .icon { opacity: 1; }
/* indicator bar */
.nav-links a.active::before {
content: '';
position: absolute;
left: 16px;
width: 3px; height: 18px;
background: var(--accent);
border-radius: 2px;
margin-left: -12px;
}
.nav-links a { position: relative; }
/* message badge in nav */
.msg-badge {
margin-left: auto;
background: var(--accent);
color: #fff;
font-size: 10px;
font-weight: 600;
padding: 2px 7px;
border-radius: 20px;
}
.nav-footer {
padding-top: 16px;
border-top: 1px solid var(--border);
font-size: 12px;
color: var(--muted);
padding-left: 8px;
}
/* ── THEME SWITCH ── */
.theme-switch-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 8px 16px;
margin-bottom: 4px;
border-bottom: 1px solid var(--border);
}
.theme-switch-label {
font-size: 12px;
font-weight: 500;
color: var(--muted);
display: flex;
align-items: center;
gap: 6px;
}
.theme-toggle {
position: relative;
width: 42px;
height: 23px;
background: var(--pill-bg);
border: 1px solid var(--border);
border-radius: 20px;
cursor: pointer;
flex-shrink: 0;
padding: 0;
}
.theme-toggle::after {
content: '☾';
position: absolute;
top: 1px; left: 1px;
width: 17px; height: 17px;
background: var(--accent);
border-radius: 50%;
transition: transform .25s cubic-bezier(.4,0,.2,1), background .2s;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
line-height: 1;
color: #fff;
}
[data-theme="light"] .theme-toggle::after {
content: '☀';
transform: translateX(19px);
background: #f59e0b;
}
/* ── MAIN CONTENT ── */
main {
margin-left: var(--nav-w);
flex: 1;
padding: 40px 48px;
min-height: 100vh;
}
.page-header {
margin-bottom: 36px;
}
.page-eyebrow {
font-size: 11px;
font-weight: 600;
letter-spacing: 1.4px;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 8px;
}
.page-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 28px;
font-weight: 700;
color: var(--text);
letter-spacing: -0.5px;
}
.page-subtitle {
margin-top: 6px;
color: var(--muted);
font-size: 14px;
}
/* ── MENSAJES MÚLTIPLES ── */
.msg-banner-wrap {
background: linear-gradient(135deg, rgba(92,110,248,.1), rgba(139,92,246,.06));
border: 1px solid rgba(92,110,248,.25);
border-radius: var(--radius);
margin-bottom: 24px;
overflow: hidden;
animation: slideIn .25s ease;
}
.msg-banner-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
border-bottom: 1px solid rgba(92,110,248,.15);
font-size: 11px;
font-weight: 600;
letter-spacing: .7px;
text-transform: uppercase;
color: var(--accent);
}
.msg-clear-all {
background: none;
border: 1px solid rgba(92,110,248,.3);
border-radius: 6px;
color: var(--muted);
font-size: 11px;
padding: 3px 10px;
cursor: pointer;
transition: color .15s, border-color .15s;
}
.msg-clear-all:hover { color: var(--text); border-color: var(--muted); }
.msg-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 16px;
border-bottom: 1px solid rgba(92,110,248,.08);
gap: 12px;
}
.msg-item:last-child { border-bottom: none; }
.msg-fecha {
font-size: 10px;
color: var(--muted);
margin-bottom: 2px;
}
.msg-texto { font-size: 13px; color: var(--text); }
.msg-del-btn {
background: none;
border: none;
color: var(--muted);
cursor: pointer;
font-size: 13px;
padding: 4px 8px;
border-radius: 6px;
flex-shrink: 0;
transition: color .15s, background .15s;
}
.msg-del-btn:hover { color: #f87171; background: rgba(248,113,113,.1); }
/* ── MESSAGE BANNER ── */
.msg-banner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
background: linear-gradient(135deg, rgba(92,110,248,.12), rgba(139,92,246,.08));
border: 1px solid rgba(92,110,248,.3);
border-radius: var(--radius);
padding: 14px 18px;
margin-bottom: 28px;
animation: slideIn .25s ease;
}
@keyframes slideIn {
from { opacity:0; transform: translateY(-6px); }
to { opacity:1; transform: translateY(0); }
}
.msg-banner .label {
font-size: 11px;
font-weight: 600;
letter-spacing: .8px;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 3px;
}
.msg-banner .text { color: var(--text); font-size: 14px; }
.msg-banner a.clear-btn {
color: var(--muted);
font-size: 12px;
text-decoration: none;
white-space: nowrap;
padding: 5px 10px;
border: 1px solid var(--border);
border-radius: 6px;
transition: color .15s, border-color .15s;
flex-shrink: 0;
}
.msg-banner a.clear-btn:hover { color: var(--text); border-color: var(--muted); }
/* ── MESSAGE FORM ── */
.msg-form {
display: flex;
gap: 10px;
margin-top: 28px;
max-width: 560px;
}
.msg-form input {
flex: 1;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
font-family: 'Inter', sans-serif;
font-size: 14px;
padding: 10px 14px;
outline: none;
transition: border-color .15s;
}
.msg-form input::placeholder { color: var(--muted); }
.msg-form input:focus { border-color: var(--accent); }
.msg-form button {
background: var(--accent);
color: #fff;
border: none;
border-radius: 8px;
font-family: 'Inter', sans-serif;
font-size: 13px;
font-weight: 600;
padding: 10px 20px;
cursor: pointer;
transition: opacity .15s;
white-space: nowrap;
}
.msg-form button:hover { opacity: .85; }
/* ── CARDS ── */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 16px;
margin-top: 28px;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 20px;
transition: border-color .2s;
}
.card:hover { border-color: rgba(92,110,248,.35); }
.card-icon {
font-size: 22px;
margin-bottom: 12px;
}
.card-title {
font-family: 'Space Grotesk', sans-serif;
font-size: 14px;
font-weight: 600;
margin-bottom: 6px;
}
.card-desc { font-size: 13px; color: var(--muted); line-height: 1.5; }
/* ── SELECT / DROPDOWN ── */
.select-wrap {
position: relative;
}
.form-select {
appearance: none;
-webkit-appearance: none;
cursor: pointer;
padding-right: 38px;
}
.form-select option {
background: var(--surface);
color: var(--text);
}
.select-arrow {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
color: var(--muted);
pointer-events: none;
transition: transform .2s;
}
.select-wrap:focus-within .select-arrow {
transform: translateY(-50%) rotate(180deg);
color: var(--accent);
}
.form-select:focus {
border-color: var(--accent);
}
{% block extra_css %}{% endblock %}
thead th {
position: relative;
transition: background .15s, color .15s;
}
thead th:hover {
background: var(--border);
color: var(--text);
}
thead th:hover .sort-icon {
opacity: .7 !important;
}
/* ── CRUD TABLE ── */
.crud-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.search-wrap {
position: relative;
flex: 1;
max-width: 360px;
}
.search-wrap > svg:first-child {
/* .search-wrap svg { */
position: absolute;
left: 12px; top: 50%;
transform: translateY(-50%);
width: 16px; height: 16px;
color: var(--muted);
pointer-events: none;
}
.search-wrap input {
width: 100%;
padding: 9px 14px 9px 38px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
font-family: 'Inter', sans-serif;
font-size: 13px;
outline: none;
transition: border-color .15s;
}
.search-wrap input::placeholder { color: var(--muted); }
.search-wrap input:focus { border-color: var(--accent); }
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 9px 18px; border-radius: 8px; font-family: 'Inter', sans-serif; font-size: 13px; font-weight: 600; cursor: pointer; border: none; text-decoration: none; transition: opacity .15s, background .15s; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { opacity: .85; }
.btn-ghost { background: var(--surface); color: var(--text); border: 1px solid var(--border); }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn-danger { background: transparent; color: #f87171; border: 1px solid rgba(248,113,113,.35); }
.btn-danger:hover { background: rgba(248,113,113,.08); }
.btn-sm { padding: 5px 12px; font-size: 12px; }
.table-wrap {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
overflow: hidden;
}
table { width: 100%; border-collapse: collapse; }
thead tr { background: var(--pill-bg); }
th {
padding: 12px 16px;
text-align: left;
font-size: 11px;
font-weight: 600;
letter-spacing: .8px;
text-transform: uppercase;
color: var(--muted);
}
td {
padding: 13px 16px;
font-size: 13px;
border-top: 1px solid var(--border);
color: var(--text);
}
tbody tr { transition: background .12s; padding-bottom: }
tbody tr:hover { background: var(--pill-bg); }
.td-id { font-family: monospace; color: var(--muted); font-size: 12px; }
.td-actions { display: flex; gap: 8px; align-items: center; }
.empty-state {
text-align: center;
padding: 48px 24px;
color: var(--muted);
font-size: 14px;
}
.empty-state svg { width: 40px; height: 40px; margin-bottom: 12px; opacity: .3; }
/* ── FORM ── */
.form-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 32px;
max-width: 1560px; /* aqui se establece el ancho de los formularios */
}
.form-group { margin-bottom: 5px; }
.form-label {
display: block;
font-size: 12px;
font-weight: 600;
letter-spacing: .5px;
color: var(--muted);
margin-bottom: 7px;
text-transform: uppercase;
}
.form-input {
width: 100%;
background: var(--bg);
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
font-family: 'Inter', sans-serif;
font-size: 14px;
padding: 10px 14px;
outline: none;
transition: border-color .15s;
}
.nav-submenu-toggle {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
padding: 10px 12px;
border-radius: 8px;
background: none;
border: none;
color: var(--muted);
font-family: 'Inter', sans-serif;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background .15s, color .15s;
}
.nav-submenu-toggle:hover,
.nav-submenu-toggle.active { background: var(--border); color: var(--text); }
.nav-submenu-items {
display: none;
flex-direction: column;
gap: 2px;
padding-left: 16px;
margin-top: 2px;
}
.nav-submenu-items.open { display: flex; }
.nav-submenu-items a {
font-size: 13px;
padding: 8px 12px;
}
.form-input::placeholder { color: var(--muted); }
.form-input:focus { border-color: var(--accent); }
.form-input:disabled { opacity: .5; cursor: not-allowed; }
.form-actions { display: flex; gap: 10px; margin-top: 28px; }
/* ── FLASH ── */
.flash { padding: 11px 16px; border-radius: 8px; font-size: 13px; margin-bottom: 20px; animation: slideIn .2s ease; }
.flash.ok { background: rgba(52,211,153,.12); border: 1px solid rgba(52,211,153,.3); color: #34d399; }
.flash.error { background: rgba(248,113,113,.1); border: 1px solid rgba(248,113,113,.3); color: #f87171; }
</style>
</head>
<body>
<!-- class="animate__animated animate__backInLeft" -->
<nav id="navbar"
{% if session.pop("animate_navbar", None) %}
class="animate__animated animate__backInUp"
{% endif %}>
<div style="padding: 0 8px 20px; text-align:center;">
<img src="{{ url_for('static', filename='img/logo.png') }}"
alt="Logo"
style="max-width:160px; width:100%; height:auto;">
</div>
<div class="nav-logo">
<span></span><h3>PyFleet</h3>
</div>
<div class="theme-switch-row">
<span class="theme-switch-label">Tema</span>
<button class="theme-toggle" id="themeToggle" aria-label="Cambiar tema claro/oscuro" type="button"></button>
</div>
<div class="nav-section-label">Navegación</div>
<div class="nav-links">
<a href="{{ url_for('index') }}" class="{% if page == 'inicio' %}active{% endif %}">
<i class="bi bi-house"style="font-size: 1rem;"></i>
Inicio
<!-- {% if session.get('mensaje') and page == 'inicio' %}<span class="msg-badge">!</span>{% endif %} -->
</a>
<a href="{{ url_for('vehiculos_list') }}" class="{% if page == 'vehiculos' %}active{% endif %}">
<i class="bi bi-car-front" style="font-size: 1rem;"></i>
Vehículos
</a>
<a href="{{ url_for('itv_list') }}" class="{% if page == 'itv' %}active{% endif %}">
<i class="bi bi-calendar-check" style="font-size: 1rem;"></i>
ITV
</a>
<a href="{{ url_for('viat_list') }}" class="{% if page == 'viat' %}active{% endif %}">
<i class="bi bi-broadcast" style="font-size: 1rem;"></i>
Via-T
</a>
<a href="{{ url_for('contacto') }}" class="{% if page == 'contacto' %}active{% endif %}">
<i class="bi bi-person-vcard" style="font-size: 1rem;"></i>
Contacto
{% if session.get('mensaje') and page == 'contacto' %}<span class="msg-badge">!</span>{% endif %}
</a>
<div class="nav-submenu" style="margin-top: 100px;">
<hr style="opacity: 0.5;margin-bottom: 5px;">
<button class="nav-submenu-toggle {% if page in ['poblaciones','unidades','tipo'] %}active{% endif %}"
onclick="toggleSubmenu(this)">
<i class="bi bi-database-check" style="font-size: 1rem;"></i>
Configuración
<svg class="chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" style="margin-top:10px;margin-left:auto;transition:transform .2s">
<polyline points="6 9 12 15 18 9"/>
</svg>
</button>
<div class="nav-submenu-items {% if page in ['poblaciones','unidades','tipo'] %}open{% endif %}">
<a href="{{ url_for('unidades_list') }}" class="{% if page == 'unidades' %}active{% endif %}">
<i class="bi bi-building"></i>
Unidades
</a>
<a href="{{ url_for('tipo_list') }}" class="{% if page == 'tipo' %}active{% endif %}">
<i class="bi bi-bus-front"></i>
Tipo vehiculo
</a>
</div>
</div>
</div>
<div class="nav-footer">
{% if mensajes %}
<a href="{{ url_for('index') }}" style="
display:flex;align-items:center;gap:6px;
color:var(--accent);text-decoration:none;font-size:12px;
padding:6px 8px;border-radius:7px;transition:background .15s;
margin-bottom:4px;"
onmouseover="this.style.background='var(--border)'"
onmouseout="this.style.background=''">
💬 {{ mensajes|length }} mensaje{{ 's' if mensajes|length != 1 }} activo{{ 's' if mensajes|length != 1 }}
</a>
{% else %}
<span style="font-size:12px;padding:6px 8px;display:block;">Sin mensajes</span>
{% endif %}
<a href="{{ url_for('logout') }}" style="
display:flex;align-items:center;gap:8px;margin-top:12px;
color:var(--muted);font-size:13px;text-decoration:none;
padding:7px 8px;border-radius:7px;transition:background .15s,color .15s;
" onmouseover="this.style.background='var(--border)';this.style.color='var(--text)'"
onmouseout="this.style.background='';this.style.color='var(--muted)'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4"/>
<polyline points="16 17 21 12 16 7"/>
<line x1="21" y1="12" x2="9" y2="12"/>
</svg>
Cerrar sesión
</a>
</div>
</nav>
<main>
{# Mensajes solo en página de inicio #}
{% if page == 'inicio' %}
{% if mensajes %}
<div class="msg-banner-wrap">
<div class="msg-banner-header">
<div style="display:flex;align-items:center;gap:8px;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
</svg>
<span>{{ mensajes|length }} mensaje{{ 's' if mensajes|length != 1 }}</span>
</div>
<form method="POST" action="{{ url_for('mensajes_eliminar_todos') }}"
onsubmit="return confirm('¿Eliminar todos los mensajes?')">
<button type="submit" class="msg-clear-all">✕ Eliminar todos</button>
</form>
</div>
{% for m in mensajes %}
<div class="msg-item">
<div>
<div class="msg-fecha">{{ m['fecha'] | fecha_es_hora }}</div>
<div class="msg-texto">{{ m['texto'] }}</div>
</div>
<form method="POST" action="{{ url_for('mensaje_eliminar', id=m['id']) }}">
<button type="submit" class="msg-del-btn" title="Eliminar este mensaje">✕</button>
</form>
</div>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="flash {{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<script>
var toggle = document.getElementById('themeToggle');
var html = document.documentElement;
function applyTheme(theme) {
html.setAttribute('data-theme', theme);
localStorage.setItem('nexus-theme', theme);
}
// Sync button state on load
applyTheme(localStorage.getItem('nexus-theme') || 'light');
toggle.addEventListener('click', function() {
var current = html.getAttribute('data-theme') === 'light' ? 'light' : 'dark';
var next = current === 'light' ? 'dark' : 'light';
applyTheme(next);
});
function toggleSubmenu(btn) {
var items = btn.nextElementSibling;
items.classList.toggle('open');
btn.querySelector('.chevron').style.transform =
items.classList.contains('open') ? 'rotate(180deg)' : '';
}
</script>
</body>
</html>
Binary file not shown.
Binary file not shown.