Files
RutasDBUS/RutasDBUS/Components/Pages/PlanificadorRutas.ModelosHorarios.cs
Pedro 7b52dd2c73 - Rediseñada la configuración de pendientes con un panel compacto accesible desde la rueda.
- Corregida la posición del panel para que no salga fuera de la pantalla.
- Renombrado el interruptor a Visualizar Pendientes.
- Aplicado el porcentaje de subida como umbral para calcular el esfuerzo.
- Mostrado el umbral de subida utilizado dentro de la tabla de elevación.
- Añadido al aviso el total de distancia con pendiente y la altura subida en metros y pisos.
- Evitada la duplicación de acumulados al repintar las pendientes.
- Cambiados los valores por defecto a subida 2 %, bajada 5 % y coeficiente 8,2.
- Añadida la distancia equilibrada andando al detalle técnico.
- Mostradas las distancias en kilómetros con tres decimales.
- Mostrada la fecha del ZIP activo en el acceso de gestión del modelo DBUS.
- Añadidas migraciones para actualizar los antiguos valores predeterminados.
2026-07-20 15:29:25 +02:00

278 lines
8.5 KiB
C#

using System.Globalization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.JSInterop;
using RutasDBUS.Modelos.Importacion;
namespace RutasDBUS.Components.Pages;
public partial class PlanificadorRutas
{
private const long MaxModeloHorarioUploadBytes = 250L * 1024 * 1024;
private IReadOnlyList<ModeloHorarioDbusInfo> _modelosHorarios = Array.Empty<ModeloHorarioDbusInfo>();
private string _modeloHorarioSeleccionadoId = "";
private string _mensajeModelosHorarios = "";
private bool _modelosHorariosCargando = false;
private bool _mostrarModelosHorariosPanel = false;
private ModeloHorarioDbusInfo? ModeloHorarioActivo =>
_modelosHorarios.FirstOrDefault(modelo => modelo.Activo);
private string FechaModeloHorarioActivo =>
FormatearFechaModeloHorario(ModeloHorarioActivo?.NombreArchivo);
private static string FormatearFechaModeloHorario(string? nombreArchivo)
{
if (string.IsNullOrWhiteSpace(nombreArchivo))
return "Sin modelo cargado";
for (var indice = nombreArchivo.Length - 8; indice >= 0; indice--)
{
if (indice > 0 && char.IsDigit(nombreArchivo[indice - 1]))
continue;
var fin = indice + 8;
if (fin < nombreArchivo.Length && char.IsDigit(nombreArchivo[fin]))
continue;
var candidata = nombreArchivo.Substring(indice, 8);
if (DateTime.TryParseExact(
candidata,
"yyyyMMdd",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out _))
{
return candidata;
}
}
return "Fecha no disponible";
}
private void AbrirModelosHorariosPanel()
{
_mostrarModelosHorariosPanel = true;
}
private void CerrarModelosHorariosPanel()
{
_mostrarModelosHorariosPanel = false;
}
private async Task CargarModelosHorariosAsync()
{
_modelosHorariosCargando = true;
try
{
_modelosHorarios = await ArchivoImportacionDbus.ListarModelosAsync();
var activo = ModeloHorarioActivo ?? _modelosHorarios.FirstOrDefault();
_modeloHorarioSeleccionadoId = activo?.Id ?? "";
}
catch (Exception ex)
{
_modelosHorarios = Array.Empty<ModeloHorarioDbusInfo>();
_modeloHorarioSeleccionadoId = "";
_mensajeModelosHorarios = "No se han podido leer los modelos: " + ex.Message;
}
finally
{
_modelosHorariosCargando = false;
}
}
private async Task ActualizarModelosHorariosAsync()
{
_mensajeModelosHorarios = "";
await CargarModelosHorariosAsync();
if (string.IsNullOrWhiteSpace(_mensajeModelosHorarios))
_mensajeModelosHorarios = _modelosHorarios.Count == 0
? "No hay ZIPs disponibles."
: "Lista actualizada.";
}
private async Task SeleccionarModeloHorarioAsync()
{
if (string.IsNullOrWhiteSpace(_modeloHorarioSeleccionadoId))
{
_mensajeModelosHorarios = "Selecciona un ZIP.";
return;
}
var seleccionado = _modelosHorarios
.FirstOrDefault(modelo => string.Equals(modelo.Id, _modeloHorarioSeleccionadoId, StringComparison.OrdinalIgnoreCase));
if (seleccionado?.Activo == true)
{
_mensajeModelosHorarios = "Ese modelo ya esta cargado.";
return;
}
_modelosHorariosCargando = true;
_mensajeModelosHorarios = "Cargando modelo...";
try
{
await ArchivoImportacionDbus.SeleccionarModeloAsync(_modeloHorarioSeleccionadoId);
await RecargarModeloHorarioActivoAsync();
await CargarModelosHorariosAsync();
var activo = ModeloHorarioActivo;
_mensajeModelosHorarios = activo is null
? "Modelo cargado."
: "Cargado: " + activo.NombreArchivo;
}
catch (Exception ex)
{
_mensajeModelosHorarios = "No se ha podido cargar el modelo: " + ex.Message;
}
finally
{
_modelosHorariosCargando = false;
}
}
private async Task SubirModeloHorarioAsync(InputFileChangeEventArgs e)
{
var archivo = e.File;
if (archivo is null)
return;
if (!archivo.Name.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
{
_mensajeModelosHorarios = "Solo se pueden subir archivos .zip.";
return;
}
_modelosHorariosCargando = true;
_mensajeModelosHorarios = "Subiendo ZIP...";
try
{
await using var stream = archivo.OpenReadStream(MaxModeloHorarioUploadBytes);
var modelo = await ArchivoImportacionDbus.GuardarModeloSubidoAsync(archivo.Name, stream);
_modeloHorarioSeleccionadoId = modelo.Id;
await RecargarModeloHorarioActivoAsync();
await CargarModelosHorariosAsync();
_mensajeModelosHorarios = "Subido y cargado: " + modelo.NombreArchivo;
}
catch (Exception ex)
{
_mensajeModelosHorarios = "No se ha podido subir el ZIP: " + ex.Message;
}
finally
{
_modelosHorariosCargando = false;
}
}
private async Task LimpiarDatosLocalesAsync()
{
bool confirmado;
try
{
confirmado = await JS.InvokeAsync<bool>(
"confirm",
"¿Seguro que quieres limpiar los datos locales de este navegador? Se borrarán historial, configuración guardada, cachés y datos locales de este sitio.");
}
catch (JSException)
{
return;
}
if (!confirmado)
return;
_modelosHorariosCargando = true;
_mensajeModelosHorarios = "Limpiando datos locales...";
try
{
await JS.InvokeVoidAsync("rt.clearLocalBrowserData");
_mensajeModelosHorarios = "Datos locales borrados. Recargando...";
await InvokeAsync(StateHasChanged);
await Task.Delay(250);
await JS.InvokeVoidAsync("rt.reloadPage");
}
catch (Exception ex)
{
_mensajeModelosHorarios = "No se han podido limpiar los datos locales: " + ex.Message;
}
finally
{
_modelosHorariosCargando = false;
}
}
private async Task RecargarModeloHorarioActivoAsync()
{
_ctsCalculo?.Cancel();
IniciarNuevaVersionPintadoRuta();
await CerrarTodasLasPreviewsAsync();
await CerrarPopupsAsync();
if (_mapa is not null)
{
await ClearRoutesJsAsync();
try { await _mapa.Geometric.DisplayPolylinesFromArray.deleteConnectors(); } catch { }
}
ResetEstadoRuta(limpiarOpciones: true);
PlanificadorRutasServicio.InvalidarCachesModelo();
_busFilteredCache.Clear();
InvalidarBusIndex();
_itItems.Clear();
_itSeleccionadoId = null;
_itFiltro = "";
_selectItKey++;
_nextDeps.Clear();
_horariosOk = false;
_horariosError = null;
_tareaCargaRed = RedBusServicio.CargarRedAsync();
await _tareaCargaRed;
if (_usarHorariosTeoricos)
await EnsureHorariosLoadedAsync();
if (RedBusServicio.Paradas.Count > 0)
{
EnsureBusIndexBuilt();
BuildItinerariosDropdown();
SincronizarSeleccionItinerarioConFiltro();
}
_paradasPintadas = false;
if (_mapa is not null)
{
if (_mostrarParadas)
await DibujarParadasAsync();
else
await OcultarParadasAsync();
await SincronizarMarcadoresOrigenDestinoJsAsync();
_paradasPintadas = _mostrarParadas;
}
StateHasChanged();
}
private static string FormatearTamanoModelo(long bytes)
{
if (bytes >= 1024L * 1024L)
return (bytes / 1024d / 1024d).ToString("0.0", CultureInfo.InvariantCulture) + " MB";
if (bytes >= 1024L)
return (bytes / 1024d).ToString("0", CultureInfo.InvariantCulture) + " KB";
return bytes.ToString(CultureInfo.InvariantCulture) + " B";
}
private static string FormatearFechaModelo(DateTime fechaUtc)
=> fechaUtc.ToLocalTime().ToString("dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture);
}