- Click del punto Z prevalece
- Añadida info del punto z anterior
+ Titulo cambiado
+ Direccion
+ Distancia andando
- Lugares reubicados en el modal del punto Z
- Añadida Configuracion completa al json del historial
- Modo por defecto añadido al switch de configuracion de historial
- Foco añadido a las versiones andando
This commit is contained in:
@@ -54,7 +54,7 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
try { await JS.InvokeVoidAsync("rt.initMobileMapControls"); } catch (Exception ex) { Console.WriteLine("rt.initMobileMapControls: " + ex); }
|
||||
try { await JS.InvokeVoidAsync("rt.initDraggablePopups"); } catch (Exception ex) { Console.WriteLine("rt.initDraggablePopups: " + ex); }
|
||||
await CargarConfiguracionLocalAsync();
|
||||
await CargarPreferenciaParametrosActualesHistorialAsync();
|
||||
await CargarModoConfiguracionHistorialAsync();
|
||||
await AsegurarHistorialLocalCargadoAsync();
|
||||
await CargarHistorialCompartidoAsync();
|
||||
await CargarModelosHorariosAsync();
|
||||
@@ -280,6 +280,9 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
[JSInvokable]
|
||||
public async Task OnPreviewItinerarioClick(string previewId)
|
||||
{
|
||||
if (_inspectorActivo)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(previewId))
|
||||
return;
|
||||
|
||||
@@ -371,9 +374,27 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
if (!_paradaByCode.TryGetValue(codigoParada, out var parada))
|
||||
return;
|
||||
|
||||
if (_inspectorActivo)
|
||||
{
|
||||
await MostrarInspectorAsync(parada.Latitud, parada.Longitud);
|
||||
return;
|
||||
}
|
||||
|
||||
await MostrarPopupParadaAsync(parada);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Abre exclusivamente el inspector Z desde un elemento interactivo superpuesto al mapa.
|
||||
/// </summary>
|
||||
[JSInvokable]
|
||||
public async Task OnInspectorOverlayClick(double latitud, double longitud)
|
||||
{
|
||||
if (!double.IsFinite(latitud) || !double.IsFinite(longitud))
|
||||
return;
|
||||
|
||||
await MostrarInspectorAsync(latitud, longitud);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gestiona inspector activo.
|
||||
/// </summary>
|
||||
@@ -381,6 +402,16 @@ public partial class PlanificadorRutas : ComponentBase, IDisposable
|
||||
public void SetInspectorActivo(bool activo)
|
||||
{
|
||||
_inspectorActivo = activo;
|
||||
|
||||
if (activo)
|
||||
{
|
||||
_ctsDobleClick?.Cancel();
|
||||
_ctsDobleClick?.Dispose();
|
||||
_ctsDobleClick = null;
|
||||
_primerClickPendiente = null;
|
||||
_paradaPrimerClickPendiente = null;
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Globalization;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using RutasDBUS.Modelos.Historial;
|
||||
|
||||
@@ -12,8 +12,11 @@ public partial class PlanificadorRutas
|
||||
{
|
||||
private const string ClaveHistorialLocal = "rutasdbus.planificador.routeHistory.v1";
|
||||
private const string ClaveRespaldoHistorialLocal = "rutasdbus.planificador.routeHistory.recovery.v1";
|
||||
private const string ClavePreferenciaParametrosActualesHistorial =
|
||||
private const string ClavePreferenciaParametrosActualesHistorialLegacy =
|
||||
"rutasdbus.planificador.history.useCurrentConfig.v1";
|
||||
private const string ClaveModoConfiguracionHistorial =
|
||||
"rutasdbus.planificador.history.configMode.v2";
|
||||
private const string PrefijoHistorialLocalComprimido = "gz1:";
|
||||
private const int MaxItemsHistorialLocal = 25;
|
||||
private const int MaxBytesHistorialLocal = 24 * 1024;
|
||||
private const int IntervaloRefrescoHistorialCompartidoSegundos = 3;
|
||||
@@ -43,11 +46,11 @@ public partial class PlanificadorRutas
|
||||
private bool _refrescandoHistorialCompartido = false;
|
||||
private bool _omitirRegistroHistorialEnSiguienteCalculo = false;
|
||||
private bool _aplicandoRegistroHistorial = false;
|
||||
private bool _usarParametrosActualesHistorial = true;
|
||||
private ModoConfiguracionHistorial _modoConfiguracionHistorial = ModoConfiguracionHistorial.Actual;
|
||||
private bool _cambiandoParametrosHistorial = false;
|
||||
private string? _historialCompartidoPendienteEliminarId;
|
||||
private ConfiguracionLocalPlanificador? _configuracionTemporalPreviaHistorial;
|
||||
private ConfiguracionLocalPlanificador? _configuracionParametrosActualesHistorial;
|
||||
private ConfiguracionHistorialRuta? _configuracionTemporalPreviaHistorial;
|
||||
private ConfiguracionHistorialRuta? _configuracionParametrosActualesHistorial;
|
||||
private Task<bool>? _tareaCargaHistorialLocal;
|
||||
private bool _historialLocalCargado = false;
|
||||
private bool _historialLocalCargando = false;
|
||||
@@ -63,6 +66,13 @@ public partial class PlanificadorRutas
|
||||
Compartido
|
||||
}
|
||||
|
||||
private enum ModoConfiguracionHistorial
|
||||
{
|
||||
Actual,
|
||||
Guardada,
|
||||
Predeterminada
|
||||
}
|
||||
|
||||
private sealed record PasoDerivacionHistorial(
|
||||
int Numero,
|
||||
DateTime FechaUtc,
|
||||
@@ -243,16 +253,18 @@ public partial class PlanificadorRutas
|
||||
return false;
|
||||
}
|
||||
|
||||
var json = resultadoLectura.Value;
|
||||
if (!resultadoLectura.Found || string.IsNullOrWhiteSpace(json))
|
||||
var valorHistorial = resultadoLectura.Value;
|
||||
if (!resultadoLectura.Found || string.IsNullOrWhiteSpace(valorHistorial))
|
||||
{
|
||||
FinalizarCargaHistorialLocal(Array.Empty<RegistroHistorialRuta>());
|
||||
LimpiarErrorHistorialLocal();
|
||||
return true;
|
||||
}
|
||||
|
||||
var json = valorHistorial;
|
||||
try
|
||||
{
|
||||
json = DecodificarHistorialLocal(valorHistorial);
|
||||
var items = DeserializarHistorialLocal(
|
||||
json,
|
||||
out var registrosOmitidos,
|
||||
@@ -262,7 +274,7 @@ public partial class PlanificadorRutas
|
||||
if (registrosOmitidos > 0)
|
||||
{
|
||||
var recuperacionGuardada = await GuardarHistorialLocalRecuperadoAsync(
|
||||
json,
|
||||
valorHistorial,
|
||||
resultadoLectura.RespaldoGuardado);
|
||||
var detalleFalloRecuperacion = recuperacionGuardada
|
||||
? null
|
||||
@@ -303,13 +315,15 @@ public partial class PlanificadorRutas
|
||||
}
|
||||
catch (Exception ex) when (
|
||||
ex is JsonException or
|
||||
InvalidDataException or
|
||||
FormatException or
|
||||
NotSupportedException or
|
||||
InvalidOperationException or
|
||||
ArgumentException)
|
||||
{
|
||||
FinalizarCargaHistorialLocal(Array.Empty<RegistroHistorialRuta>());
|
||||
var recuperacionGuardada = await GuardarHistorialLocalRecuperadoAsync(
|
||||
json,
|
||||
valorHistorial,
|
||||
resultadoLectura.RespaldoGuardado);
|
||||
var detalleFalloRecuperacion = recuperacionGuardada
|
||||
? null
|
||||
@@ -413,6 +427,11 @@ public partial class PlanificadorRutas
|
||||
? $"{item.DestinoLatitud.ToString("0.000000", CultureInfo.InvariantCulture)}, {item.DestinoLongitud.ToString("0.000000", CultureInfo.InvariantCulture)}"
|
||||
: item.DestinoTexto.Trim();
|
||||
item.LineasPermitidas = NormalizarLineasHistorial(item.LineasPermitidas).ToList();
|
||||
if (item.Configuracion is not null)
|
||||
{
|
||||
item.Configuracion.LineasPermitidas =
|
||||
NormalizarLineasHistorial(item.Configuracion.LineasPermitidas).ToList();
|
||||
}
|
||||
|
||||
if (item.FechaCreacionUtc == default)
|
||||
item.FechaCreacionUtc = item.FechaActualizacionUtc == default ? DateTime.UtcNow : item.FechaActualizacionUtc;
|
||||
@@ -444,19 +463,45 @@ public partial class PlanificadorRutas
|
||||
IEnumerable<RegistroHistorialRuta> origen)
|
||||
{
|
||||
var items = origen.Take(MaxItemsHistorialLocal).ToList();
|
||||
var json = JsonSerializer.Serialize(items);
|
||||
var json = SerializarHistorialLocal(items);
|
||||
var bytes = Encoding.UTF8.GetByteCount(json);
|
||||
|
||||
while (items.Count > 0 && bytes > MaxBytesHistorialLocal)
|
||||
{
|
||||
items.RemoveAt(items.Count - 1);
|
||||
json = JsonSerializer.Serialize(items);
|
||||
json = SerializarHistorialLocal(items);
|
||||
bytes = Encoding.UTF8.GetByteCount(json);
|
||||
}
|
||||
|
||||
return (items, json, bytes);
|
||||
}
|
||||
|
||||
private static string SerializarHistorialLocal(IEnumerable<RegistroHistorialRuta> items)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(items);
|
||||
var entrada = Encoding.UTF8.GetBytes(json);
|
||||
using var salida = new MemoryStream();
|
||||
using (var gzip = new GZipStream(salida, CompressionLevel.Fastest, leaveOpen: true))
|
||||
{
|
||||
gzip.Write(entrada, 0, entrada.Length);
|
||||
}
|
||||
|
||||
return PrefijoHistorialLocalComprimido + Convert.ToBase64String(salida.ToArray());
|
||||
}
|
||||
|
||||
private static string DecodificarHistorialLocal(string valor)
|
||||
{
|
||||
if (!valor.StartsWith(PrefijoHistorialLocalComprimido, StringComparison.Ordinal))
|
||||
return valor;
|
||||
|
||||
var datos = Convert.FromBase64String(valor[PrefijoHistorialLocalComprimido.Length..]);
|
||||
using var entrada = new MemoryStream(datos);
|
||||
using var gzip = new GZipStream(entrada, CompressionMode.Decompress);
|
||||
using var salida = new MemoryStream();
|
||||
gzip.CopyTo(salida);
|
||||
return Encoding.UTF8.GetString(salida.ToArray());
|
||||
}
|
||||
|
||||
private async Task<bool> GuardarHistorialLocalRecuperadoAsync(
|
||||
string jsonOriginal,
|
||||
bool respaldoOriginalYaGuardado)
|
||||
@@ -485,7 +530,7 @@ public partial class PlanificadorRutas
|
||||
return;
|
||||
|
||||
var itemsOriginales = _historialLocal.ToList();
|
||||
var jsonOriginal = JsonSerializer.Serialize(itemsOriginales);
|
||||
var jsonOriginal = SerializarHistorialLocal(itemsOriginales);
|
||||
var preparado = PrepararHistorialLocalParaGuardar(itemsOriginales);
|
||||
var fueRecortado = preparado.Items.Count != itemsOriginales.Count;
|
||||
|
||||
@@ -771,6 +816,7 @@ public partial class PlanificadorRutas
|
||||
existente.FactorEquilibradoAndarBus = actual.FactorEquilibradoAndarBus;
|
||||
existente.ActivarFiltroLineas = actual.ActivarFiltroLineas;
|
||||
existente.LineasPermitidas = actual.LineasPermitidas.ToList();
|
||||
existente.Configuracion = actual.Configuracion?.Clonar();
|
||||
existente.FechaActualizacionUtc = DateTime.UtcNow;
|
||||
|
||||
_historialLocal.Remove(existente);
|
||||
@@ -854,18 +900,13 @@ public partial class PlanificadorRutas
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task CambiarUsoParametrosActualesHistorialAsync(ChangeEventArgs e)
|
||||
private async Task CambiarModoConfiguracionHistorialAsync(ModoConfiguracionHistorial modo)
|
||||
{
|
||||
if (_cambiandoParametrosHistorial)
|
||||
return;
|
||||
|
||||
var usarParametrosActuales = e.Value switch
|
||||
{
|
||||
bool valor => valor,
|
||||
string texto when bool.TryParse(texto, out var valor) => valor,
|
||||
_ => !_usarParametrosActualesHistorial
|
||||
};
|
||||
if (usarParametrosActuales == _usarParametrosActualesHistorial)
|
||||
if (!Enum.IsDefined(typeof(ModoConfiguracionHistorial), modo) ||
|
||||
modo == _modoConfiguracionHistorial)
|
||||
return;
|
||||
|
||||
_cambiandoParametrosHistorial = true;
|
||||
@@ -873,23 +914,34 @@ public partial class PlanificadorRutas
|
||||
{
|
||||
var itemSeleccionado = ObtenerRegistroHistorialSeleccionado();
|
||||
|
||||
if (!usarParametrosActuales && _usarParametrosActualesHistorial)
|
||||
if (_modoConfiguracionHistorial == ModoConfiguracionHistorial.Actual &&
|
||||
modo != ModoConfiguracionHistorial.Actual)
|
||||
{
|
||||
CapturarConfiguracionTemporalAntesDeHistorial();
|
||||
_configuracionParametrosActualesHistorial = CrearConfiguracionLocal();
|
||||
}
|
||||
|
||||
_usarParametrosActualesHistorial = usarParametrosActuales;
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
_modoConfiguracionHistorial = modo;
|
||||
await PersistirModoConfiguracionHistorialAsync();
|
||||
|
||||
if (usarParametrosActuales && _configuracionParametrosActualesHistorial is not null)
|
||||
if (modo == ModoConfiguracionHistorial.Actual &&
|
||||
_configuracionParametrosActualesHistorial is not null)
|
||||
{
|
||||
AplicarConfiguracionLocal(_configuracionParametrosActualesHistorial);
|
||||
}
|
||||
|
||||
if (itemSeleccionado is null)
|
||||
return;
|
||||
|
||||
await AplicarRegistroHistorialAsync(itemSeleccionado);
|
||||
MostrarMensajeHistorial(
|
||||
usarParametrosActuales
|
||||
? "Ruta recalculada con los parámetros actuales."
|
||||
: "Ruta recalculada con los parámetros guardados.");
|
||||
MostrarMensajeHistorial(modo switch
|
||||
{
|
||||
ModoConfiguracionHistorial.Actual =>
|
||||
"Ruta recalculada con la configuración actual.",
|
||||
ModoConfiguracionHistorial.Guardada =>
|
||||
"Ruta recalculada con la configuración guardada en el historial.",
|
||||
_ => "Ruta recalculada con la configuración predeterminada."
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -906,29 +958,44 @@ public partial class PlanificadorRutas
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CargarPreferenciaParametrosActualesHistorialAsync()
|
||||
private async Task CargarModoConfiguracionHistorialAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
var valor = await JS.InvokeAsync<string?>(
|
||||
"rt.loadLocalValue",
|
||||
ClavePreferenciaParametrosActualesHistorial);
|
||||
if (bool.TryParse(valor, out var usarConfiguracionActual))
|
||||
_usarParametrosActualesHistorial = usarConfiguracionActual;
|
||||
ClaveModoConfiguracionHistorial);
|
||||
if (Enum.TryParse<ModoConfiguracionHistorial>(valor, ignoreCase: true, out var modo) &&
|
||||
Enum.IsDefined(typeof(ModoConfiguracionHistorial), modo))
|
||||
{
|
||||
_modoConfiguracionHistorial = modo;
|
||||
return;
|
||||
}
|
||||
|
||||
var valorLegacy = await JS.InvokeAsync<string?>(
|
||||
"rt.loadLocalValue",
|
||||
ClavePreferenciaParametrosActualesHistorialLegacy);
|
||||
if (bool.TryParse(valorLegacy, out var usarConfiguracionActual))
|
||||
{
|
||||
_modoConfiguracionHistorial = usarConfiguracionActual
|
||||
? ModoConfiguracionHistorial.Actual
|
||||
: ModoConfiguracionHistorial.Guardada;
|
||||
await PersistirModoConfiguracionHistorialAsync();
|
||||
}
|
||||
}
|
||||
catch (JSException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task PersistirPreferenciaParametrosActualesHistorialAsync()
|
||||
private async Task PersistirModoConfiguracionHistorialAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await JS.InvokeVoidAsync(
|
||||
"rt.saveLocalValue",
|
||||
ClavePreferenciaParametrosActualesHistorial,
|
||||
_usarParametrosActualesHistorial.ToString(CultureInfo.InvariantCulture));
|
||||
ClaveModoConfiguracionHistorial,
|
||||
_modoConfiguracionHistorial.ToString());
|
||||
}
|
||||
catch (JSException)
|
||||
{
|
||||
@@ -1268,10 +1335,18 @@ public partial class PlanificadorRutas
|
||||
FactorEquilibradoAndarBus = item.FactorEquilibradoAndarBus,
|
||||
ActivarFiltroLineas = item.ActivarFiltroLineas,
|
||||
LineasPermitidas = item.LineasPermitidas.ToList(),
|
||||
Configuracion = item.Configuracion?.Clonar(),
|
||||
FechaCreacionUtc = item.FechaCreacionUtc,
|
||||
FechaActualizacionUtc = item.FechaActualizacionUtc
|
||||
};
|
||||
|
||||
private RegistroHistorialRuta PrepararRegistroParaCompartir(RegistroHistorialRuta item)
|
||||
{
|
||||
var compartible = ClonarEscenarioHistorial(item);
|
||||
compartible.Configuracion ??= CrearConfiguracionGuardadaHistorial(item);
|
||||
return compartible;
|
||||
}
|
||||
|
||||
private async Task CompartirEscenarioActualAsync()
|
||||
{
|
||||
var actual = ConstruirRegistroHistorialActual()
|
||||
@@ -1285,7 +1360,7 @@ public partial class PlanificadorRutas
|
||||
|
||||
try
|
||||
{
|
||||
await HistorialRutasCompartidoService.GuardarAsync(actual);
|
||||
await HistorialRutasCompartidoService.GuardarAsync(PrepararRegistroParaCompartir(actual));
|
||||
await CargarHistorialCompartidoAsync();
|
||||
MostrarMensajeHistorial("Combinacion enviada al historial compartido.");
|
||||
}
|
||||
@@ -1306,7 +1381,7 @@ public partial class PlanificadorRutas
|
||||
|
||||
try
|
||||
{
|
||||
await HistorialRutasCompartidoService.GuardarAsync(item);
|
||||
await HistorialRutasCompartidoService.GuardarAsync(PrepararRegistroParaCompartir(item));
|
||||
await CargarHistorialCompartidoAsync();
|
||||
MostrarMensajeHistorial("Combinacion enviada al historial compartido.");
|
||||
}
|
||||
@@ -1439,6 +1514,7 @@ public partial class PlanificadorRutas
|
||||
try
|
||||
{
|
||||
CapturarConfiguracionTemporalAntesDeHistorial();
|
||||
var mostrarParadasAntes = _mostrarParadas;
|
||||
|
||||
_omitirRegistroHistorialEnSiguienteCalculo = true;
|
||||
_textoBusquedaOrigen = item.OrigenTexto;
|
||||
@@ -1446,40 +1522,33 @@ public partial class PlanificadorRutas
|
||||
_coordenadasOrigen = new[] { item.OrigenLatitud, item.OrigenLongitud };
|
||||
_coordenadasDestino = new[] { item.DestinoLatitud, item.DestinoLongitud };
|
||||
|
||||
if (!_usarParametrosActualesHistorial)
|
||||
var configuracionHistorial = _modoConfiguracionHistorial switch
|
||||
{
|
||||
_usarHorariosTeoricos = item.UsarHorariosTeoricos;
|
||||
_usarHoraSimulada = item.UsarHoraSimulada;
|
||||
ModoConfiguracionHistorial.Guardada => CrearConfiguracionGuardadaHistorial(item),
|
||||
ModoConfiguracionHistorial.Predeterminada => CrearConfiguracionPredeterminadaHistorial(),
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (DateOnly.TryParse(item.FechaSimulada, out var fecha))
|
||||
_fechaSimulada = fecha;
|
||||
|
||||
if (TimeOnly.TryParse(item.HoraSimulada, out var hora))
|
||||
_horaSimulada = hora;
|
||||
|
||||
_criterioPrioritarioRuta = NormalizarCriterioRuta(item.CriterioPrioritarioRuta, item.PreferenciaEtiquetaRuta);
|
||||
SincronizarPreferenciaDesdeCriterioRuta();
|
||||
|
||||
if (item.FactorEquilibradoAndarBus is { } factorEquilibrado &&
|
||||
double.IsFinite(factorEquilibrado) &&
|
||||
factorEquilibrado > 0)
|
||||
if (configuracionHistorial is not null)
|
||||
{
|
||||
_factorEquilibradoAndarBus = factorEquilibrado;
|
||||
SincronizarTextosPenalizacionPie();
|
||||
AplicarConfiguracionLocal(configuracionHistorial);
|
||||
|
||||
if (_configuracionTemporalPreviaHistorial is not null)
|
||||
_configuracionTemporalPreviaHistorial.FactorEquilibradoAndarBus = _factorEquilibradoAndarBus;
|
||||
// El factor cargado desde un historial ya se conservaba al cerrar el panel.
|
||||
if (_modoConfiguracionHistorial == ModoConfiguracionHistorial.Guardada &&
|
||||
_configuracionTemporalPreviaHistorial is not null)
|
||||
{
|
||||
_configuracionTemporalPreviaHistorial.FactorEquilibradoAndarBus =
|
||||
_factorEquilibradoAndarBus;
|
||||
_configuracionTemporalPreviaHistorial.VersionFactorEquilibrado =
|
||||
VersionPersistenciaFactorEquilibrado;
|
||||
}
|
||||
|
||||
_activarRangoLineas = item.ActivarFiltroLineas;
|
||||
_lineasPermitidas.Clear();
|
||||
foreach (var linea in NormalizarLineasHistorial(item.LineasPermitidas))
|
||||
_lineasPermitidas.Add(linea);
|
||||
}
|
||||
|
||||
_busFilteredCache.Clear();
|
||||
|
||||
SincronizarSegundosPorParadaConHorarios();
|
||||
if (_usarHorariosTeoricos)
|
||||
await EnsureHorariosLoadedAsync();
|
||||
|
||||
StopClock();
|
||||
if (_usarHoraSimulada)
|
||||
@@ -1495,6 +1564,14 @@ public partial class PlanificadorRutas
|
||||
{
|
||||
try { await _mapa.Geometric.DisplayPolylinesFromArray.deleteConnectors(); } catch { }
|
||||
await ClearRoutesJsAsync();
|
||||
|
||||
if (mostrarParadasAntes != _mostrarParadas)
|
||||
{
|
||||
if (_mostrarParadas)
|
||||
await DibujarParadasAsync();
|
||||
else
|
||||
await OcultarParadasAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await SincronizarMarcadoresOrigenDestinoJsAsync();
|
||||
@@ -1506,6 +1583,30 @@ public partial class PlanificadorRutas
|
||||
}
|
||||
}
|
||||
|
||||
private ConfiguracionHistorialRuta CrearConfiguracionGuardadaHistorial(RegistroHistorialRuta item)
|
||||
{
|
||||
if (item.Configuracion is not null)
|
||||
return item.Configuracion.Clonar();
|
||||
|
||||
// Los JSON anteriores no incluían una instantánea completa. Conservamos los
|
||||
// parámetros actuales para lo desconocido y superponemos todos los que sí viajaban.
|
||||
var configuracion = (_configuracionParametrosActualesHistorial ??
|
||||
_configuracionTemporalPreviaHistorial ??
|
||||
CrearConfiguracionLocal()).Clonar();
|
||||
|
||||
configuracion.UsarHorariosTeoricos = item.UsarHorariosTeoricos;
|
||||
configuracion.UsarHoraSimulada = item.UsarHoraSimulada;
|
||||
configuracion.FechaSimulada = item.FechaSimulada;
|
||||
configuracion.HoraSimulada = item.HoraSimulada;
|
||||
configuracion.CriterioPrioritarioRuta = item.CriterioPrioritarioRuta;
|
||||
configuracion.PreferenciaEtiquetaRuta = item.PreferenciaEtiquetaRuta;
|
||||
configuracion.FactorEquilibradoAndarBus = item.FactorEquilibradoAndarBus;
|
||||
configuracion.VersionFactorEquilibrado = VersionPersistenciaFactorEquilibrado;
|
||||
configuracion.ActivarRangoLineas = item.ActivarFiltroLineas;
|
||||
configuracion.LineasPermitidas = NormalizarLineasHistorial(item.LineasPermitidas).ToList();
|
||||
return configuracion;
|
||||
}
|
||||
|
||||
private void CapturarConfiguracionTemporalAntesDeHistorial()
|
||||
{
|
||||
if (_configuracionTemporalPreviaHistorial is not null)
|
||||
@@ -1524,8 +1625,19 @@ public partial class PlanificadorRutas
|
||||
if (configuracionPrevia is null)
|
||||
return;
|
||||
|
||||
var mostrarParadasAntes = _mostrarParadas;
|
||||
AplicarConfiguracionLocal(configuracionPrevia);
|
||||
|
||||
if (_mapa is not null && mostrarParadasAntes != _mostrarParadas)
|
||||
{
|
||||
if (_mostrarParadas)
|
||||
await DibujarParadasAsync();
|
||||
else
|
||||
await OcultarParadasAsync();
|
||||
|
||||
await SincronizarMarcadoresOrigenDestinoJsAsync();
|
||||
}
|
||||
|
||||
StopClock();
|
||||
if (_usarHoraSimulada)
|
||||
await RefrescarHoraUIAsync();
|
||||
@@ -1541,6 +1653,11 @@ public partial class PlanificadorRutas
|
||||
return null;
|
||||
|
||||
var ahora = _ultimaHoraReferenciaRuta ?? AhoraLocal();
|
||||
var configuracion = CrearConfiguracionLocal();
|
||||
configuracion.FechaSimulada = DateOnly.FromDateTime(ahora)
|
||||
.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
||||
configuracion.HoraSimulada = TimeOnly.FromDateTime(ahora)
|
||||
.ToString("HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
|
||||
return new RegistroHistorialRuta
|
||||
{
|
||||
@@ -1563,6 +1680,7 @@ public partial class PlanificadorRutas
|
||||
: FactorEquilibradoAndarBusPorDefecto,
|
||||
ActivarFiltroLineas = _activarRangoLineas,
|
||||
LineasPermitidas = ObtenerLineasPermitidasSeleccionadas().ToList(),
|
||||
Configuracion = configuracion,
|
||||
FechaCreacionUtc = DateTime.UtcNow,
|
||||
FechaActualizacionUtc = DateTime.UtcNow
|
||||
};
|
||||
|
||||
@@ -12,7 +12,10 @@ public partial class PlanificadorRutas
|
||||
double? ElevacionIdee,
|
||||
double? ElevacionLocal5,
|
||||
double? ElevacionLocal2,
|
||||
double? ElevacionLocal1);
|
||||
double? ElevacionLocal1,
|
||||
string Direccion,
|
||||
double? DistanciaAndandoMetros,
|
||||
bool CalculandoDatosAdicionales);
|
||||
|
||||
private double? ObtenerElevacionPuntoInspectorAnterior(PuntoInspectorAnterior punto)
|
||||
=> UsarElevacionLocal1ParaCalculo
|
||||
@@ -23,6 +26,15 @@ public partial class PlanificadorRutas
|
||||
? punto.ElevacionLocal5
|
||||
: punto.ElevacionIdee;
|
||||
|
||||
private double? ObtenerElevacionPuntoInspectorActual()
|
||||
=> UsarElevacionLocal1ParaCalculo
|
||||
? _inspectorElevLocal1
|
||||
: UsarElevacionLocal2ParaCalculo
|
||||
? _inspectorElevLocal2
|
||||
: UsarElevacionLocal5ParaCalculo
|
||||
? _inspectorElevLocal5
|
||||
: _inspectorElevIdee;
|
||||
|
||||
private static string FormatearDistanciaPuntoInspector(double distanciaMetros)
|
||||
=> distanciaMetros < 1000
|
||||
? distanciaMetros.ToString("0.0", CultureInfo.InvariantCulture) + " m"
|
||||
@@ -32,4 +44,79 @@ public partial class PlanificadorRutas
|
||||
=> altura is { } valor
|
||||
? valor.ToString("0.00", CultureInfo.InvariantCulture) + " m"
|
||||
: "-";
|
||||
|
||||
private static string FormatearDiferenciaAlturaPuntoInspector(
|
||||
double? alturaActual,
|
||||
double? alturaAnterior)
|
||||
=> alturaActual is { } actual && alturaAnterior is { } anterior
|
||||
? (actual - anterior).ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture) + " m"
|
||||
: "-";
|
||||
|
||||
private string ObtenerDireccionPuntoInspectorActual()
|
||||
=> FormatearLugarCallejeroResumen(_inspectorLugaresCercanos.FirstOrDefault());
|
||||
|
||||
private async Task<string> ResolverDireccionPuntoInspectorAnteriorAsync(PuntoInspectorAnterior punto)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(punto.Direccion))
|
||||
return punto.Direccion;
|
||||
|
||||
try
|
||||
{
|
||||
var cercano = await GeocodificadorLocal.BuscarMasCercanoAsync(
|
||||
punto.Latitud,
|
||||
punto.Longitud,
|
||||
CancellationToken.None);
|
||||
return FormatearLugarCallejeroResumen(cercano);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompletarDatosPuntoInspectorAnteriorAsync(
|
||||
PuntoInspectorAnterior punto,
|
||||
int versionInspector)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tareaDireccion = ResolverDireccionPuntoInspectorAnteriorAsync(punto);
|
||||
var tareaCaminata = WalkCached(
|
||||
punto.Latitud,
|
||||
punto.Longitud,
|
||||
_inspectorLat,
|
||||
_inspectorLon);
|
||||
|
||||
await Task.WhenAll(tareaDireccion, tareaCaminata);
|
||||
|
||||
if (versionInspector != _versionInspector || _inspectorPuntoAnterior is not { } puntoVigente ||
|
||||
puntoVigente.Latitud != punto.Latitud || puntoVigente.Longitud != punto.Longitud)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var caminata = await tareaCaminata;
|
||||
_inspectorPuntoAnterior = puntoVigente with
|
||||
{
|
||||
Direccion = await tareaDireccion,
|
||||
DistanciaAndandoMetros = caminata.line is not null && caminata.dist > 0
|
||||
? caminata.dist
|
||||
: null,
|
||||
CalculandoDatosAdicionales = false
|
||||
};
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (versionInspector != _versionInspector || _inspectorPuntoAnterior is not { } puntoVigente ||
|
||||
puntoVigente.Latitud != punto.Latitud || puntoVigente.Longitud != punto.Longitud)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_inspectorPuntoAnterior = puntoVigente with { CalculandoDatosAdicionales = false };
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +531,9 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
/// </summary>
|
||||
private async Task MostrarPopupParadaAsync(Parada paradaDetectada)
|
||||
{
|
||||
if (_inspectorActivo)
|
||||
return;
|
||||
|
||||
var myToken = Interlocked.Increment(ref _paradaPopupToken);
|
||||
|
||||
_paradaClicada = null;
|
||||
@@ -1095,23 +1098,31 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Construye un texto de trayecto usando la primera y la ultima parada de la variante.
|
||||
/// Construye un texto de recorrido usando la primera y la ultima parada de la variante.
|
||||
/// </summary>
|
||||
private string ConstruirTextoRecorridoVariante(InfoVariante? variante)
|
||||
private string ConstruirTextoRecorridoVariante(
|
||||
InfoVariante? variante,
|
||||
bool incluirCodigosParada = false)
|
||||
{
|
||||
if (variante?.CodigosParadas is null || variante.CodigosParadas.Count == 0)
|
||||
return "";
|
||||
|
||||
string NombreParada(string codigo)
|
||||
string TextoParada(string codigo)
|
||||
{
|
||||
var codigoFormateado = CodigoParadaFormateado(codigo);
|
||||
if (_paradaByCode.TryGetValue(codigo, out var parada) && !string.IsNullOrWhiteSpace(parada.Nombre))
|
||||
return parada.Nombre.Trim();
|
||||
|
||||
return CodigoParadaFormateado(codigo);
|
||||
{
|
||||
var nombre = parada.Nombre.Trim();
|
||||
return incluirCodigosParada && !string.IsNullOrWhiteSpace(codigoFormateado)
|
||||
? $"{nombre} ({codigoFormateado})"
|
||||
: nombre;
|
||||
}
|
||||
|
||||
var origen = NombreParada(variante.CodigosParadas[0]);
|
||||
var destino = NombreParada(variante.CodigosParadas[^1]);
|
||||
return codigoFormateado;
|
||||
}
|
||||
|
||||
var origen = TextoParada(variante.CodigosParadas[0]);
|
||||
var destino = TextoParada(variante.CodigosParadas[^1]);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(origen))
|
||||
return destino;
|
||||
@@ -1389,7 +1400,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
private bool _elevPopupMinimizado = false;
|
||||
|
||||
|
||||
private const string _versionApp = "(v-20260902d)";
|
||||
private const string _versionApp = "(v-20260903b)";
|
||||
|
||||
|
||||
private double? _paradaElevIdee;
|
||||
@@ -1518,9 +1529,9 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene el codigo y el nombre de la linea del itinerario clicado.
|
||||
/// Obtiene el identificador completo y el nombre de la linea del itinerario clicado.
|
||||
/// </summary>
|
||||
private string GetTextoLineaItinerarioClicado(InfoVariante? vReal)
|
||||
private string GetNombreLineaItinerarioClicado(InfoVariante? vReal)
|
||||
{
|
||||
if (_itinerarioClicado is null)
|
||||
return "";
|
||||
@@ -1528,19 +1539,18 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
if (vReal is null)
|
||||
return _itinerarioClicado.Text;
|
||||
|
||||
var linea = vReal.Linea?.Codigo?.ToString() ?? "?";
|
||||
var itin = vReal.CodigoItinerario;
|
||||
var sentido = NormalizarSentidoCodigo(vReal.Sentido?.Codigo); // I / V
|
||||
var linea = vReal.Linea?.Codigo?.ToString()?.Trim() ?? "?";
|
||||
var sentido = NormalizarSentidoCodigo(vReal.Sentido?.Codigo);
|
||||
var identificador = $"{linea}.{vReal.CodigoItinerario}-{sentido}";
|
||||
var nombre = vReal.Linea?.Nombre?.Trim() ?? "";
|
||||
var codigo = $"{linea}.{itin}-{sentido}";
|
||||
|
||||
return string.IsNullOrWhiteSpace(nombre)
|
||||
? codigo
|
||||
: $"{codigo} ({nombre})";
|
||||
? identificador
|
||||
: $"{identificador} {nombre}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene la parada final del itinerario clicado.
|
||||
/// Obtiene el destino indicado por las expediciones del itinerario clicado.
|
||||
/// </summary>
|
||||
private string GetDestinoItinerarioClicado(InfoVariante? vReal)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using Microsoft.JSInterop;
|
||||
using RutasDBUS.Modelos.Historial;
|
||||
using RutasDBUS.Modelos.Planificacion;
|
||||
|
||||
namespace RutasDBUS.Components.Pages;
|
||||
@@ -17,66 +18,6 @@ public partial class PlanificadorRutas
|
||||
private bool _configuracionLocalCargada = false;
|
||||
private bool _mostrarConfirmacionRestablecer = false;
|
||||
|
||||
/// <summary>
|
||||
/// Instantánea persistida de la configuración del planificador.
|
||||
/// </summary>
|
||||
private sealed class ConfiguracionLocalPlanificador
|
||||
{
|
||||
public bool? MostrarParadas { get; set; }
|
||||
public bool UsarHorariosTeoricos { get; set; }
|
||||
public int SegundosPorParadaBusManual { get; set; }
|
||||
public bool ActivarRangoLineas { get; set; }
|
||||
public int LineaMin { get; set; }
|
||||
public int LineaMax { get; set; }
|
||||
public List<int>? LineasPermitidas { get; set; }
|
||||
public bool ActivarRangoItinerarios { get; set; }
|
||||
public int ItinerarioMin { get; set; }
|
||||
public int ItinerarioMax { get; set; }
|
||||
public string? FiltroSentidoItinerario { get; set; }
|
||||
public bool ActivarRangoTransbordos { get; set; }
|
||||
public int MinTransbordosPermitidos { get; set; }
|
||||
public int MaxTransbordosPermitidos { get; set; }
|
||||
public bool UsarHoraSimulada { get; set; }
|
||||
public string? FechaSimulada { get; set; }
|
||||
public string? HoraSimulada { get; set; }
|
||||
public double? FactorPenalizacionDistanciaPie { get; set; }
|
||||
public int? VersionFactorPenalizacionPie { get; set; }
|
||||
public double? ParametroPenalizacionDistanciaPieMetros { get; set; }
|
||||
public double? CoeficienteEsfuerzoAltura { get; set; }
|
||||
public int? VersionCoeficienteEsfuerzo { get; set; }
|
||||
public double? PesoTransbordoRankingMinutos { get; set; }
|
||||
public double? FactorEquilibradoAndarBus { get; set; }
|
||||
public int? VersionFactorEquilibrado { get; set; }
|
||||
public bool? MostrarElevacionesRuta { get; set; }
|
||||
public string? FuenteElevacionCalculo { get; set; }
|
||||
public int? VersionFuenteElevacion { get; set; }
|
||||
public int? VersionPendientes { get; set; }
|
||||
public int? VersionColoresPendientes { get; set; }
|
||||
public double? UmbralPendienteSubidaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaMediaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaFuerteRuta { get; set; }
|
||||
public string? ColorPendienteBajadaRuta { get; set; }
|
||||
public string? ColorPendienteLlanoRuta { get; set; }
|
||||
public string? ColorPendienteSubidaSuaveRuta { get; set; }
|
||||
public string? ColorPendienteSubidaMediaRuta { get; set; }
|
||||
public string? ColorPendienteSubidaFuerteRuta { get; set; }
|
||||
public double? UmbralPendienteBajadaRuta { get; set; }
|
||||
public double? UmbralAlturaAlertaPendienteRutaMetros { get; set; }
|
||||
// Compatibilidad con configuraciones guardadas cuando el umbral se expresaba en pisos.
|
||||
public double? UmbralPisosPendienteRuta { get; set; }
|
||||
public double VelocidadPieKmH { get; set; }
|
||||
public double VelocidadBusKmH { get; set; }
|
||||
public int ElevMaxPuntosPorTramo { get; set; }
|
||||
public int RadioCandidatasMetros { get; set; }
|
||||
public int MargenTransbordoSegundos { get; set; }
|
||||
public string? WalkProvider { get; set; }
|
||||
public int NivelBrilloMapa { get; set; }
|
||||
public bool UsarColorRealLineaEnItinerarios { get; set; }
|
||||
public bool UsarOsrmParaRanking { get; set; }
|
||||
public string? CriterioPrioritarioRuta { get; set; }
|
||||
public string? PreferenciaEtiquetaRuta { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Carga la configuración persistida del navegador y la aplica al estado actual.
|
||||
/// </summary>
|
||||
@@ -88,7 +29,7 @@ public partial class PlanificadorRutas
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return;
|
||||
|
||||
var config = JsonSerializer.Deserialize<ConfiguracionLocalPlanificador>(json);
|
||||
var config = JsonSerializer.Deserialize<ConfiguracionHistorialRuta>(json);
|
||||
if (config is null)
|
||||
return;
|
||||
|
||||
@@ -146,9 +87,10 @@ public partial class PlanificadorRutas
|
||||
/// <summary>
|
||||
/// Construye la instantánea persistible a partir del estado actual.
|
||||
/// </summary>
|
||||
private ConfiguracionLocalPlanificador CrearConfiguracionLocal()
|
||||
private ConfiguracionHistorialRuta CrearConfiguracionLocal()
|
||||
=> new()
|
||||
{
|
||||
Version = 1,
|
||||
MostrarParadas = _mostrarParadas,
|
||||
UsarHorariosTeoricos = _usarHorariosTeoricos,
|
||||
SegundosPorParadaBusManual = Math.Max(0, _segundosPorParadaBusManual),
|
||||
@@ -193,6 +135,8 @@ public partial class PlanificadorRutas
|
||||
VelocidadBusKmH = _velocidadBusKmH,
|
||||
ElevMaxPuntosPorTramo = _elevMaxPuntosPorTramo,
|
||||
RadioCandidatasMetros = _radioCandidatasMetros,
|
||||
MaxCandidatasPorLado = _maxCandidatasPorLado,
|
||||
MinutosTransbordo = _minutosTransbordo,
|
||||
MargenTransbordoSegundos = _margenTransbordoSegundos,
|
||||
WalkProvider = _walkProvider.ToString(),
|
||||
NivelBrilloMapa = _nivelBrilloMapa,
|
||||
@@ -202,10 +146,72 @@ public partial class PlanificadorRutas
|
||||
PreferenciaEtiquetaRuta = _preferenciaEtiquetaRuta
|
||||
};
|
||||
|
||||
private static ConfiguracionHistorialRuta CrearConfiguracionPredeterminadaHistorial()
|
||||
{
|
||||
var ahora = DateTime.Now;
|
||||
return new ConfiguracionHistorialRuta
|
||||
{
|
||||
Version = 1,
|
||||
MostrarParadas = true,
|
||||
UsarHorariosTeoricos = true,
|
||||
SegundosPorParadaBusManual = 30,
|
||||
ActivarRangoLineas = false,
|
||||
LineaMin = 1,
|
||||
LineaMax = 200,
|
||||
LineasPermitidas = new List<int>(),
|
||||
ActivarRangoItinerarios = true,
|
||||
ItinerarioMin = 1,
|
||||
ItinerarioMax = 99,
|
||||
FiltroSentidoItinerario = FiltroSentidoItinerario.Ambos.ToString(),
|
||||
ActivarRangoTransbordos = true,
|
||||
MinTransbordosPermitidos = 0,
|
||||
MaxTransbordosPermitidos = 3,
|
||||
UsarHoraSimulada = true,
|
||||
FechaSimulada = DateOnly.FromDateTime(ahora).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
|
||||
HoraSimulada = TimeOnly.FromDateTime(ahora).ToString("HH:mm:ss", CultureInfo.InvariantCulture),
|
||||
FactorPenalizacionDistanciaPie = FactorPenalizacionDistanciaPiePorDefecto,
|
||||
VersionFactorPenalizacionPie = VersionPersistenciaFactorPenalizacionPie,
|
||||
ParametroPenalizacionDistanciaPieMetros = ParametroPenalizacionDistanciaPieMetrosPorDefecto,
|
||||
CoeficienteEsfuerzoAltura = CoeficienteEsfuerzoAlturaPorDefecto,
|
||||
VersionCoeficienteEsfuerzo = VersionPersistenciaCoeficienteEsfuerzo,
|
||||
PesoTransbordoRankingMinutos = 4.0,
|
||||
FactorEquilibradoAndarBus = FactorEquilibradoAndarBusPorDefecto,
|
||||
VersionFactorEquilibrado = VersionPersistenciaFactorEquilibrado,
|
||||
MostrarElevacionesRuta = true,
|
||||
FuenteElevacionCalculo = FuenteElevacionLocal5,
|
||||
VersionFuenteElevacion = VersionPersistenciaFuenteElevacion,
|
||||
VersionPendientes = VersionPersistenciaPendientes,
|
||||
VersionColoresPendientes = VersionPersistenciaColoresPendientes,
|
||||
UmbralPendienteSubidaRuta = UmbralPendienteSubidaRutaPorDefecto,
|
||||
UmbralPendienteSubidaMediaRuta = UmbralPendienteSubidaMediaRutaPorDefecto,
|
||||
UmbralPendienteSubidaFuerteRuta = UmbralPendienteSubidaFuerteRutaPorDefecto,
|
||||
ColorPendienteBajadaRuta = ColorPendienteBajadaRutaPorDefecto,
|
||||
ColorPendienteLlanoRuta = ColorPendienteLlanoRutaPorDefecto,
|
||||
ColorPendienteSubidaSuaveRuta = ColorPendienteSubidaSuaveRutaPorDefecto,
|
||||
ColorPendienteSubidaMediaRuta = ColorPendienteSubidaMediaRutaPorDefecto,
|
||||
ColorPendienteSubidaFuerteRuta = ColorPendienteSubidaFuerteRutaPorDefecto,
|
||||
UmbralPendienteBajadaRuta = UmbralPendienteBajadaRutaPorDefecto,
|
||||
UmbralAlturaAlertaPendienteRutaMetros = UmbralAlturaAlertaPendienteRutaMetrosPorDefecto,
|
||||
VelocidadPieKmH = 3.6,
|
||||
VelocidadBusKmH = 16.0,
|
||||
ElevMaxPuntosPorTramo = 999,
|
||||
RadioCandidatasMetros = 1200,
|
||||
MaxCandidatasPorLado = 12,
|
||||
MinutosTransbordo = 5,
|
||||
MargenTransbordoSegundos = 120,
|
||||
WalkProvider = ProveedorCaminata.Valhalla.ToString(),
|
||||
NivelBrilloMapa = 0,
|
||||
UsarColorRealLineaEnItinerarios = false,
|
||||
UsarOsrmParaRanking = false,
|
||||
CriterioPrioritarioRuta = CriterioRutaEquilibrado,
|
||||
PreferenciaEtiquetaRuta = null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aplica al componente una configuración previamente persistida.
|
||||
/// </summary>
|
||||
private void AplicarConfiguracionLocal(ConfiguracionLocalPlanificador config)
|
||||
private void AplicarConfiguracionLocal(ConfiguracionHistorialRuta config)
|
||||
{
|
||||
_mostrarParadas = config.MostrarParadas ?? true;
|
||||
_usarHorariosTeoricos = config.UsarHorariosTeoricos;
|
||||
@@ -353,6 +359,8 @@ public partial class PlanificadorRutas
|
||||
120.0);
|
||||
_elevMaxPuntosPorTramo = Math.Clamp(config.ElevMaxPuntosPorTramo, 2, 999);
|
||||
_radioCandidatasMetros = Math.Clamp(config.RadioCandidatasMetros, 200, 3500);
|
||||
_maxCandidatasPorLado = Math.Clamp(config.MaxCandidatasPorLado ?? 12, 3, 20);
|
||||
_minutosTransbordo = Math.Clamp(config.MinutosTransbordo ?? 5, 0, 180);
|
||||
_margenTransbordoSegundos = Math.Clamp(config.MargenTransbordoSegundos, 0, 1800);
|
||||
_nivelBrilloMapa = Math.Clamp(config.NivelBrilloMapa, 0, 4);
|
||||
_usarColorRealLineaEnItinerarios = config.UsarColorRealLineaEnItinerarios;
|
||||
@@ -475,7 +483,7 @@ public partial class PlanificadorRutas
|
||||
_nivelBrilloMapa = 0;
|
||||
_usarColorRealLineaEnItinerarios = false;
|
||||
_usarOsrmParaRanking = false;
|
||||
_usarParametrosActualesHistorial = true;
|
||||
_modoConfiguracionHistorial = ModoConfiguracionHistorial.Actual;
|
||||
|
||||
if (_usarHoraSimulada)
|
||||
StopClock();
|
||||
@@ -485,7 +493,7 @@ public partial class PlanificadorRutas
|
||||
SincronizarSegundosPorParadaConHorarios();
|
||||
await RefrescarHoraUIAsync();
|
||||
await PersistirConfiguracionAsync();
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
await PersistirModoConfiguracionHistorialAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -537,7 +545,7 @@ public partial class PlanificadorRutas
|
||||
_nivelBrilloMapa = 0;
|
||||
_usarColorRealLineaEnItinerarios = false;
|
||||
_usarOsrmParaRanking = false;
|
||||
_usarParametrosActualesHistorial = true;
|
||||
_modoConfiguracionHistorial = ModoConfiguracionHistorial.Actual;
|
||||
|
||||
if (_usarHoraSimulada)
|
||||
StopClock();
|
||||
@@ -547,7 +555,7 @@ public partial class PlanificadorRutas
|
||||
SincronizarSegundosPorParadaConHorarios();
|
||||
await RefrescarHoraUIAsync();
|
||||
await PersistirConfiguracionAsync();
|
||||
await PersistirPreferenciaParametrosActualesHistorialAsync();
|
||||
await PersistirModoConfiguracionHistorialAsync();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1461,7 +1461,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
}
|
||||
|
||||
if (_coordenadasOrigen is not null && _coordenadasDestino is not null)
|
||||
await CalcularRutaCompletaAsync();
|
||||
await CalcularRutaCompletaAsync(conservarSeleccionSoloAPie: true);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
@@ -1512,7 +1512,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
|
||||
await CerrarTodasLasPreviewsAsync();
|
||||
await CerrarPopupsAsync();
|
||||
await CalcularRutaCompletaAsync();
|
||||
await CalcularRutaCompletaAsync(conservarSeleccionSoloAPie: true);
|
||||
}
|
||||
/// <summary>
|
||||
/// Muestra inspector.
|
||||
@@ -1526,7 +1526,10 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
_inspectorElevIdee,
|
||||
_inspectorElevLocal5,
|
||||
_inspectorElevLocal2,
|
||||
_inspectorElevLocal1)
|
||||
_inspectorElevLocal1,
|
||||
ObtenerDireccionPuntoInspectorActual(),
|
||||
DistanciaAndandoMetros: null,
|
||||
CalculandoDatosAdicionales: true)
|
||||
: null;
|
||||
|
||||
var versionInspector = ++_versionInspector;
|
||||
@@ -1554,6 +1557,9 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
await ActualizarMarcadoresInspectorJsAsync();
|
||||
StateHasChanged();
|
||||
|
||||
if (_inspectorPuntoAnterior is { } puntoAnterior)
|
||||
_ = CompletarDatosPuntoInspectorAnteriorAsync(puntoAnterior, versionInspector);
|
||||
|
||||
var tareaLugares = GeocodificadorLocal.BuscarCercanosAsync(
|
||||
lat,
|
||||
lon,
|
||||
@@ -1788,7 +1794,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
|
||||
await SincronizarMarcadoresOrigenDestinoJsAsync();
|
||||
|
||||
await CalcularRutaCompletaAsync();
|
||||
await CalcularRutaCompletaAsync(conservarSeleccionSoloAPie: true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1801,7 +1807,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
await SincronizarMarcadoresOrigenDestinoJsAsync();
|
||||
}
|
||||
|
||||
await CalcularRutaCompletaAsync();
|
||||
await CalcularRutaCompletaAsync(conservarSeleccionSoloAPie: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1841,7 +1847,7 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
|
||||
if (_coordenadasOrigen is not null && _coordenadasDestino is not null)
|
||||
{
|
||||
await CalcularRutaCompletaAsync();
|
||||
await CalcularRutaCompletaAsync(conservarSeleccionSoloAPie: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1862,11 +1868,16 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
/// <summary>
|
||||
/// Calcula ruta completa.
|
||||
/// </summary>
|
||||
private async Task CalcularRutaCompletaAsync()
|
||||
private async Task CalcularRutaCompletaAsync(bool conservarSeleccionSoloAPie = false)
|
||||
{
|
||||
if (_mapa is null || _coordenadasOrigen is null || _coordenadasDestino is null)
|
||||
return;
|
||||
|
||||
var restaurarSeleccionSoloAPie = conservarSeleccionSoloAPie &&
|
||||
_indiceAlternativaSeleccionada >= 0 &&
|
||||
_indiceAlternativaSeleccionada < _opcionesRuta.Count &&
|
||||
_opcionesRuta[_indiceAlternativaSeleccionada].EsSoloAPie;
|
||||
|
||||
_mostrarElevacionesRuta = _mostrarElevacionesRutaConfiguracion;
|
||||
|
||||
var confirmarDerivacionHistorial = !_aplicandoRegistroHistorial &&
|
||||
@@ -1983,9 +1994,15 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
return;
|
||||
}
|
||||
|
||||
var idxPreferida = BuscarIndicePreferidoPorCriterio(_criterioPrioritarioRuta);
|
||||
var idxPreferida = restaurarSeleccionSoloAPie
|
||||
? _opcionesRuta.FindIndex(opcion => opcion.EsSoloAPie)
|
||||
: BuscarIndicePreferidoPorCriterio(_criterioPrioritarioRuta);
|
||||
if (idxPreferida < 0 || idxPreferida >= _opcionesRuta.Count)
|
||||
{
|
||||
idxPreferida = BuscarIndicePreferidoPorCriterio(_criterioPrioritarioRuta);
|
||||
if (idxPreferida < 0 || idxPreferida >= _opcionesRuta.Count)
|
||||
idxPreferida = 0;
|
||||
}
|
||||
|
||||
_indiceAlternativaSeleccionada = idxPreferida;
|
||||
ResetEstadoRuta(limpiarOpciones: false, limpiarMensaje: false);
|
||||
|
||||
@@ -550,11 +550,10 @@ public partial class PlanificadorRutas : ComponentBase
|
||||
|
||||
private string ObtenerNombreDestinoItinerario(InfoVariante variante)
|
||||
{
|
||||
if (variante.CodigosParadas.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var ultimaParada = ResolverParadaFisica(variante.CodigosParadas[^1]);
|
||||
return ultimaParada.Nombre?.Trim() ?? string.Empty;
|
||||
var destino = variante.Variante?.Destino?.Trim();
|
||||
return UtilidadesTransitoDbus.DestinoDescriptivoEsValido(destino)
|
||||
? destino!
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
private double? ElevacionPreferidaMapa(MuestraElevacion muestra)
|
||||
|
||||
@@ -367,25 +367,20 @@
|
||||
@if (_itinerarioClicado is not null)
|
||||
{
|
||||
var vReal = GetVarianteRealClicada();
|
||||
var textoLineaItinerario = GetTextoLineaItinerarioClicado(vReal);
|
||||
var nombreLineaItinerario = GetNombreLineaItinerarioClicado(vReal);
|
||||
var destinoItinerario = GetDestinoItinerarioClicado(vReal);
|
||||
|
||||
<div class="popup-parada popup-slot popup-itinerario draggable-popup" data-drag-key="popup-itinerario">
|
||||
<div class="popup-parada-header popup-itinerario-header draggable-popup-handle">
|
||||
<span>@textoLineaItinerario</span>
|
||||
@if (!string.IsNullOrWhiteSpace(destinoItinerario))
|
||||
{
|
||||
<span class="popup-itinerario-header__destination">
|
||||
<span aria-hidden="true">→</span> @destinoItinerario
|
||||
</span>
|
||||
}
|
||||
<span>@nombreLineaItinerario</span>
|
||||
</div>
|
||||
<div class="popup-parada-body popup-itinerario-body">
|
||||
@if (vReal is not null)
|
||||
{
|
||||
<div style="margin-top:.25rem;">
|
||||
<div><b>Destino:</b> @(string.IsNullOrWhiteSpace(destinoItinerario) ? "-" : destinoItinerario)</div>
|
||||
<div><b>Paradas:</b> @(vReal.CodigosParadas?.Count ?? 0)</div>
|
||||
<div><b>Recorrido:</b> @ConstruirTextoRecorridoVariante(vReal)</div>
|
||||
<div><b>Recorrido:</b> @ConstruirTextoRecorridoVariante(vReal, incluirCodigosParada: true)</div>
|
||||
<div><b>Longitud:</b> @FormatearDistanciaVariante(vReal)</div>
|
||||
</div>
|
||||
}
|
||||
@@ -451,29 +446,6 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (_inspectorPuntoAnterior is { } puntoAnterior)
|
||||
{
|
||||
var distanciaPuntoAnterior = CalcularDistanciaMetros(
|
||||
puntoAnterior.Latitud,
|
||||
puntoAnterior.Longitud,
|
||||
_inspectorLat,
|
||||
_inspectorLon);
|
||||
var elevacionPuntoAnterior = ObtenerElevacionPuntoInspectorAnterior(puntoAnterior);
|
||||
|
||||
<div class="inspector-previous-point">
|
||||
<div class="inspector-previous-point__distance">
|
||||
<b>Distancia al punto Z anterior:</b>
|
||||
@FormatearDistanciaPuntoInspector(distanciaPuntoAnterior)
|
||||
</div>
|
||||
<div class="inspector-previous-point__details">
|
||||
<span>Punto anterior</span>
|
||||
<span>Lat: @puntoAnterior.Latitud.ToString("0.000000", CultureInfo.InvariantCulture)</span>
|
||||
<span>Lon: @puntoAnterior.Longitud.ToString("0.000000", CultureInfo.InvariantCulture)</span>
|
||||
<span>@EtiquetaFuenteElevacionCalculo: @FormatearAlturaPuntoInspector(elevacionPuntoAnterior)</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (_inspectorLugaresCercanos.Count > 0)
|
||||
{
|
||||
<div class="inspector-address-list">
|
||||
@@ -487,6 +459,47 @@
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (_inspectorPuntoAnterior is { } puntoAnterior)
|
||||
{
|
||||
var distanciaPuntoAnterior = CalcularDistanciaMetros(
|
||||
puntoAnterior.Latitud,
|
||||
puntoAnterior.Longitud,
|
||||
_inspectorLat,
|
||||
_inspectorLon);
|
||||
var elevacionPuntoAnterior = ObtenerElevacionPuntoInspectorAnterior(puntoAnterior);
|
||||
var elevacionPuntoActual = ObtenerElevacionPuntoInspectorActual();
|
||||
var direccionPuntoAnterior = string.IsNullOrWhiteSpace(puntoAnterior.Direccion)
|
||||
? (puntoAnterior.CalculandoDatosAdicionales ? "Calculando..." : "-")
|
||||
: puntoAnterior.Direccion;
|
||||
|
||||
<div class="inspector-previous-point">
|
||||
<div class="inspector-previous-point__title">Datos del punto anterior</div>
|
||||
<div class="inspector-previous-point__details">
|
||||
<span class="inspector-previous-point__detail--full">Dirección: @direccionPuntoAnterior</span>
|
||||
<span>Lat: @puntoAnterior.Latitud.ToString("0.000000", CultureInfo.InvariantCulture)</span>
|
||||
<span>Lon: @puntoAnterior.Longitud.ToString("0.000000", CultureInfo.InvariantCulture)</span>
|
||||
<span>@EtiquetaFuenteElevacionCalculo: @FormatearAlturaPuntoInspector(elevacionPuntoAnterior)</span>
|
||||
<span class="inspector-previous-point__detail--full">
|
||||
Diferencia de altura: @FormatearDiferenciaAlturaPuntoInspector(elevacionPuntoActual, elevacionPuntoAnterior)
|
||||
</span>
|
||||
<span class="inspector-previous-point__detail--full">
|
||||
Distancia en línea recta: @FormatearDistanciaPuntoInspector(distanciaPuntoAnterior)
|
||||
</span>
|
||||
<span class="inspector-previous-point__detail--full">
|
||||
Distancia andando:
|
||||
@if (puntoAnterior.CalculandoDatosAdicionales)
|
||||
{
|
||||
<span>Calculando...</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@(puntoAnterior.DistanciaAndandoMetros is { } distanciaAndando ? FormatearDistanciaPuntoInspector(distanciaAndando) : "-")</span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<button class="popup-parada-cerrar" @onclick="CerrarInspectorAsync">×</button>
|
||||
@@ -1126,17 +1139,40 @@
|
||||
</div>
|
||||
|
||||
<div class="history-panel-body">
|
||||
<label class="history-parameters-toggle @(_usarParametrosActualesHistorial ? "history-parameters-toggle--active" : "")"
|
||||
title="Recalcular las rutas del historial con la configuración actual">
|
||||
<span class="history-parameters-toggle__label">Usar configuración actual</span>
|
||||
<input type="checkbox"
|
||||
checked="@_usarParametrosActualesHistorial"
|
||||
<div class="history-config-mode">
|
||||
<span class="history-config-mode__label">Configuración para recalcular</span>
|
||||
<div class="history-config-mode__options"
|
||||
role="radiogroup"
|
||||
aria-label="Configuración usada al cargar una ruta del historial">
|
||||
<button type="button"
|
||||
class="history-config-mode__option @(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Actual ? "history-config-mode__option--active" : "")"
|
||||
role="radio"
|
||||
aria-checked="@(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Actual)"
|
||||
title="Usar la configuración actual"
|
||||
disabled="@(_aplicandoRegistroHistorial || _cambiandoParametrosHistorial)"
|
||||
@onchange="CambiarUsoParametrosActualesHistorialAsync" />
|
||||
<span class="history-parameters-toggle__track" aria-hidden="true">
|
||||
<span class="history-parameters-toggle__thumb"></span>
|
||||
</span>
|
||||
</label>
|
||||
@onclick="() => CambiarModoConfiguracionHistorialAsync(ModoConfiguracionHistorial.Actual)">
|
||||
Actual
|
||||
</button>
|
||||
<button type="button"
|
||||
class="history-config-mode__option @(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Guardada ? "history-config-mode__option--active" : "")"
|
||||
role="radio"
|
||||
aria-checked="@(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Guardada)"
|
||||
title="Usar la configuración guardada con la ruta"
|
||||
disabled="@(_aplicandoRegistroHistorial || _cambiandoParametrosHistorial)"
|
||||
@onclick="() => CambiarModoConfiguracionHistorialAsync(ModoConfiguracionHistorial.Guardada)">
|
||||
Guardada
|
||||
</button>
|
||||
<button type="button"
|
||||
class="history-config-mode__option @(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Predeterminada ? "history-config-mode__option--active" : "")"
|
||||
role="radio"
|
||||
aria-checked="@(_modoConfiguracionHistorial == ModoConfiguracionHistorial.Predeterminada)"
|
||||
title="Usar los valores predeterminados de fábrica"
|
||||
disabled="@(_aplicandoRegistroHistorial || _cambiandoParametrosHistorial)"
|
||||
@onclick="() => CambiarModoConfiguracionHistorialAsync(ModoConfiguracionHistorial.Predeterminada)">
|
||||
Predeterminada
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="history-section">
|
||||
<label class="history-section-label">Personal:</label>
|
||||
|
||||
70
RutasDBUS/Modelos/Historial/ConfiguracionHistorialRuta.cs
Normal file
70
RutasDBUS/Modelos/Historial/ConfiguracionHistorialRuta.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
namespace RutasDBUS.Modelos.Historial;
|
||||
|
||||
/// <summary>
|
||||
/// Instantánea completa de la configuración con la que se calculó una ruta.
|
||||
/// </summary>
|
||||
public sealed class ConfiguracionHistorialRuta
|
||||
{
|
||||
public int Version { get; set; } = 1;
|
||||
public bool? MostrarParadas { get; set; }
|
||||
public bool UsarHorariosTeoricos { get; set; }
|
||||
public int SegundosPorParadaBusManual { get; set; }
|
||||
public bool ActivarRangoLineas { get; set; }
|
||||
public int LineaMin { get; set; }
|
||||
public int LineaMax { get; set; }
|
||||
public List<int>? LineasPermitidas { get; set; }
|
||||
public bool ActivarRangoItinerarios { get; set; }
|
||||
public int ItinerarioMin { get; set; }
|
||||
public int ItinerarioMax { get; set; }
|
||||
public string? FiltroSentidoItinerario { get; set; }
|
||||
public bool ActivarRangoTransbordos { get; set; }
|
||||
public int MinTransbordosPermitidos { get; set; }
|
||||
public int MaxTransbordosPermitidos { get; set; }
|
||||
public bool UsarHoraSimulada { get; set; }
|
||||
public string? FechaSimulada { get; set; }
|
||||
public string? HoraSimulada { get; set; }
|
||||
public double? FactorPenalizacionDistanciaPie { get; set; }
|
||||
public int? VersionFactorPenalizacionPie { get; set; }
|
||||
public double? ParametroPenalizacionDistanciaPieMetros { get; set; }
|
||||
public double? CoeficienteEsfuerzoAltura { get; set; }
|
||||
public int? VersionCoeficienteEsfuerzo { get; set; }
|
||||
public double? PesoTransbordoRankingMinutos { get; set; }
|
||||
public double? FactorEquilibradoAndarBus { get; set; }
|
||||
public int? VersionFactorEquilibrado { get; set; }
|
||||
public bool? MostrarElevacionesRuta { get; set; }
|
||||
public string? FuenteElevacionCalculo { get; set; }
|
||||
public int? VersionFuenteElevacion { get; set; }
|
||||
public int? VersionPendientes { get; set; }
|
||||
public int? VersionColoresPendientes { get; set; }
|
||||
public double? UmbralPendienteSubidaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaMediaRuta { get; set; }
|
||||
public double? UmbralPendienteSubidaFuerteRuta { get; set; }
|
||||
public string? ColorPendienteBajadaRuta { get; set; }
|
||||
public string? ColorPendienteLlanoRuta { get; set; }
|
||||
public string? ColorPendienteSubidaSuaveRuta { get; set; }
|
||||
public string? ColorPendienteSubidaMediaRuta { get; set; }
|
||||
public string? ColorPendienteSubidaFuerteRuta { get; set; }
|
||||
public double? UmbralPendienteBajadaRuta { get; set; }
|
||||
public double? UmbralAlturaAlertaPendienteRutaMetros { get; set; }
|
||||
public double? UmbralPisosPendienteRuta { get; set; }
|
||||
public double VelocidadPieKmH { get; set; }
|
||||
public double VelocidadBusKmH { get; set; }
|
||||
public int ElevMaxPuntosPorTramo { get; set; }
|
||||
public int RadioCandidatasMetros { get; set; }
|
||||
public int? MaxCandidatasPorLado { get; set; }
|
||||
public int? MinutosTransbordo { get; set; }
|
||||
public int MargenTransbordoSegundos { get; set; }
|
||||
public string? WalkProvider { get; set; }
|
||||
public int NivelBrilloMapa { get; set; }
|
||||
public bool UsarColorRealLineaEnItinerarios { get; set; }
|
||||
public bool UsarOsrmParaRanking { get; set; }
|
||||
public string? CriterioPrioritarioRuta { get; set; }
|
||||
public string? PreferenciaEtiquetaRuta { get; set; }
|
||||
|
||||
public ConfiguracionHistorialRuta Clonar()
|
||||
{
|
||||
var copia = (ConfiguracionHistorialRuta)MemberwiseClone();
|
||||
copia.LineasPermitidas = LineasPermitidas?.ToList();
|
||||
return copia;
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ public sealed class RegistroHistorialRuta
|
||||
public double? FactorEquilibradoAndarBus { get; set; }
|
||||
public bool ActivarFiltroLineas { get; set; }
|
||||
public List<int> LineasPermitidas { get; set; } = new();
|
||||
public ConfiguracionHistorialRuta? Configuracion { get; set; }
|
||||
public DateTime FechaCreacionUtc { get; set; } = DateTime.UtcNow;
|
||||
public DateTime FechaActualizacionUtc { get; set; } = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,9 @@ public class Variante
|
||||
/// <summary>Código interno de la variante.</summary>
|
||||
public int Codigo { get; set; }
|
||||
|
||||
/// <summary>Destino indicado por DIR_DESTINO en las expediciones del itinerario.</summary>
|
||||
public string Destino { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Identificadores de trayectos que se recorren en esta variante, en orden.
|
||||
/// </summary>
|
||||
|
||||
@@ -89,6 +89,8 @@ public sealed class ServicioHistorialRutasCompartido : IHistorialRutasCompartido
|
||||
existente.FactorEquilibradoAndarBus = registro.FactorEquilibradoAndarBus;
|
||||
existente.ActivarFiltroLineas = registro.ActivarFiltroLineas;
|
||||
existente.LineasPermitidas = NormalizarLineas(registro.LineasPermitidas).ToList();
|
||||
if (registro.Configuracion is not null)
|
||||
existente.Configuracion = CopiarConfiguracion(registro.Configuracion);
|
||||
|
||||
if (registro.FechaCreacionUtc != default)
|
||||
existente.FechaCreacionUtc = registro.FechaCreacionUtc;
|
||||
@@ -300,10 +302,20 @@ public sealed class ServicioHistorialRutasCompartido : IHistorialRutasCompartido
|
||||
FactorEquilibradoAndarBus = item.FactorEquilibradoAndarBus,
|
||||
ActivarFiltroLineas = item.ActivarFiltroLineas,
|
||||
LineasPermitidas = NormalizarLineas(item.LineasPermitidas).ToList(),
|
||||
Configuracion = item.Configuracion is null
|
||||
? null
|
||||
: CopiarConfiguracion(item.Configuracion),
|
||||
FechaCreacionUtc = item.FechaCreacionUtc,
|
||||
FechaActualizacionUtc = item.FechaActualizacionUtc
|
||||
};
|
||||
|
||||
private static ConfiguracionHistorialRuta CopiarConfiguracion(ConfiguracionHistorialRuta configuracion)
|
||||
{
|
||||
var copia = configuracion.Clonar();
|
||||
copia.LineasPermitidas = NormalizarLineas(copia.LineasPermitidas).ToList();
|
||||
return copia;
|
||||
}
|
||||
|
||||
private static string CalcularClaveEscenario(RegistroHistorialRuta item)
|
||||
{
|
||||
var origenLat = Math.Round(item.OrigenLatitud, 6).ToString("0.000000", CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -95,7 +95,7 @@ public sealed class CreadorRedTransporteDbus
|
||||
var codigoVariante = ExtraerCodigoVariante(exp.IdPatronExp);
|
||||
var key = $"{exp.IdRuta}|{codigoItinerario}|{sentido}|{exp.IdPatronExp}";
|
||||
|
||||
if (!variantesTemp.ContainsKey(key))
|
||||
if (!variantesTemp.TryGetValue(key, out var varianteTemp))
|
||||
{
|
||||
variantesTemp[key] = new VarianteTemporal
|
||||
{
|
||||
@@ -108,6 +108,11 @@ public sealed class CreadorRedTransporteDbus
|
||||
StopIds = stopIds
|
||||
};
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(varianteTemp.Destino) &&
|
||||
!string.IsNullOrWhiteSpace(exp.DirDestino))
|
||||
{
|
||||
varianteTemp.Destino = exp.DirDestino;
|
||||
}
|
||||
}
|
||||
|
||||
var nextTrayectoId = 1;
|
||||
@@ -132,7 +137,11 @@ public sealed class CreadorRedTransporteDbus
|
||||
itinerario.Sentidos.Add(sentido);
|
||||
}
|
||||
|
||||
var variante = new Variante { Codigo = temp.CodigoVariante };
|
||||
var variante = new Variante
|
||||
{
|
||||
Codigo = temp.CodigoVariante,
|
||||
Destino = temp.Destino?.Trim() ?? ""
|
||||
};
|
||||
var stopIdsValidos = temp.StopIds.Where(paradaById.ContainsKey).ToList();
|
||||
var codigosParadas = stopIdsValidos
|
||||
.Select(id => paradaById[id].Codigo)
|
||||
|
||||
@@ -55,14 +55,16 @@
|
||||
|
||||
.inspector-previous-point {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
gap: 5px;
|
||||
margin: 7px 0 6px;
|
||||
padding: 7px 0 2px;
|
||||
padding: 8px 0 2px;
|
||||
border-top: 1px solid rgba(148, 163, 184, .25);
|
||||
}
|
||||
|
||||
.inspector-previous-point__distance {
|
||||
line-height: 1.3;
|
||||
.inspector-previous-point__title {
|
||||
color: #e2e8f0;
|
||||
font-size: .78rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.inspector-previous-point__details {
|
||||
@@ -74,10 +76,8 @@
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.inspector-previous-point__details > span:first-child {
|
||||
.inspector-previous-point__detail--full {
|
||||
flex-basis: 100%;
|
||||
color: #cbd5e1;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rt-inspector-place-icon {
|
||||
@@ -788,12 +788,6 @@ html, body {
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.popup-itinerario-header__destination {
|
||||
margin-left: .3rem;
|
||||
color: #bae6fd;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.popup-parada-body {
|
||||
font-size: .8rem;
|
||||
}
|
||||
@@ -1374,70 +1368,59 @@ html, body {
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.history-parameters-toggle {
|
||||
.history-config-mode {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: .65rem;
|
||||
min-height: 30px;
|
||||
padding-bottom: .6rem;
|
||||
gap: .35rem;
|
||||
padding-bottom: .65rem;
|
||||
border-bottom: 1px solid rgba(148,163,184,.2);
|
||||
color: #cbd5e1;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.history-parameters-toggle__label {
|
||||
min-width: 0;
|
||||
font-size: .78rem;
|
||||
.history-config-mode__label {
|
||||
color: #cbd5e1;
|
||||
font-size: .75rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.history-parameters-toggle input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
.history-config-mode__options {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 2px;
|
||||
padding: 2px;
|
||||
border: 1px solid rgba(148,163,184,.42);
|
||||
border-radius: 8px;
|
||||
background: rgba(2,6,23,.58);
|
||||
}
|
||||
|
||||
.history-parameters-toggle__track {
|
||||
position: relative;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
border: 1px solid rgba(148,163,184,.55);
|
||||
border-radius: 999px;
|
||||
background: rgba(2,6,23,.72);
|
||||
transition: background .15s ease, border-color .15s ease;
|
||||
.history-config-mode__option {
|
||||
min-width: 0;
|
||||
height: 28px;
|
||||
overflow: hidden;
|
||||
border: 0;
|
||||
border-radius: 6px;
|
||||
padding: 0 .35rem;
|
||||
background: transparent;
|
||||
color: #94a3b8;
|
||||
font-size: .7rem;
|
||||
font-weight: 700;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.history-parameters-toggle__thumb {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 999px;
|
||||
background: #94a3b8;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.35);
|
||||
transition: transform .15s ease, background .15s ease;
|
||||
}
|
||||
|
||||
.history-parameters-toggle--active {
|
||||
.history-config-mode__option:hover:not(:disabled) {
|
||||
background: rgba(51,65,85,.72);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.history-parameters-toggle--active .history-parameters-toggle__track {
|
||||
border-color: rgba(59,130,246,.85);
|
||||
background: rgba(37,99,235,.82);
|
||||
.history-config-mode__option--active {
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
.history-parameters-toggle--active .history-parameters-toggle__thumb {
|
||||
transform: translateX(16px);
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.history-parameters-toggle:has(input:disabled) {
|
||||
.history-config-mode__option:disabled {
|
||||
cursor: default;
|
||||
opacity: .6;
|
||||
opacity: .58;
|
||||
}
|
||||
|
||||
.history-section {
|
||||
|
||||
@@ -7,16 +7,22 @@
|
||||
};
|
||||
|
||||
window.initAltInspector = function (dotNetHelper) {
|
||||
const setInspectorActive = function (active) {
|
||||
window.rt = window.rt || {};
|
||||
window.rt._inspectorActive = !!active;
|
||||
dotNetHelper.invokeMethodAsync("SetInspectorActivo", !!active);
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Z" || e.key === "z") dotNetHelper.invokeMethodAsync("SetInspectorActivo", true);
|
||||
if (e.key === "Z" || e.key === "z") setInspectorActive(true);
|
||||
}, true);
|
||||
|
||||
document.addEventListener("keyup", function (e) {
|
||||
if (e.key === "Z" || e.key === "z") dotNetHelper.invokeMethodAsync("SetInspectorActivo", false);
|
||||
if (e.key === "Z" || e.key === "z") setInspectorActive(false);
|
||||
}, true);
|
||||
|
||||
window.addEventListener("blur", function () {
|
||||
dotNetHelper.invokeMethodAsync("SetInspectorActivo", false);
|
||||
setInspectorActive(false);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -84,6 +90,40 @@ window.initAltInspector = function (dotNetHelper) {
|
||||
|
||||
window.rt = window.rt || {};
|
||||
|
||||
window.rt.handleInspectorLayerClick = function (event) {
|
||||
if (!window.rt._inspectorActive) return false;
|
||||
|
||||
const originalEvent = event && event.originalEvent;
|
||||
if (originalEvent) {
|
||||
if (originalEvent.preventDefault) originalEvent.preventDefault();
|
||||
if (originalEvent.stopPropagation) originalEvent.stopPropagation();
|
||||
if (originalEvent.stopImmediatePropagation) originalEvent.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
const alreadyHandled = !!(
|
||||
(event && event.__rtInspectorHandled) ||
|
||||
(originalEvent && originalEvent.__rtInspectorHandled));
|
||||
|
||||
if (event) event.__rtInspectorHandled = true;
|
||||
if (originalEvent) originalEvent.__rtInspectorHandled = true;
|
||||
|
||||
if (!alreadyHandled && window.rt._dotNetHelper) {
|
||||
const latLng = event && event.latlng
|
||||
? event.latlng
|
||||
: event && event.target && typeof event.target.getLatLng === "function"
|
||||
? event.target.getLatLng()
|
||||
: null;
|
||||
const lat = Number(latLng && latLng.lat);
|
||||
const lon = Number(latLng && latLng.lng);
|
||||
|
||||
if (Number.isFinite(lat) && Number.isFinite(lon)) {
|
||||
window.rt._dotNetHelper.invokeMethodAsync("OnInspectorOverlayClick", lat, lon);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
window.rt.ensureRouteLayer = function () {
|
||||
const map = window.__rtLeafletMap;
|
||||
if (!map || !window.L) {
|
||||
@@ -290,6 +330,8 @@ window.rt.drawRoute = function (id, coords, options) {
|
||||
const attachRouteClick = function (line) {
|
||||
line.on("click", function (e) {
|
||||
try {
|
||||
if (window.rt.handleInspectorLayerClick(e)) return;
|
||||
|
||||
if (e && e.originalEvent) {
|
||||
if (e.originalEvent.preventDefault) e.originalEvent.preventDefault();
|
||||
if (e.originalEvent.stopPropagation) e.originalEvent.stopPropagation();
|
||||
@@ -422,6 +464,8 @@ window.rt.drawRoute = function (id, coords, options) {
|
||||
segmentLine.on("mouseover", updateTooltipAtCursor);
|
||||
segmentLine.on("mousemove", updateTooltipAtCursor);
|
||||
segmentLine.on("click", function (e) {
|
||||
if (window.rt.handleInspectorLayerClick(e)) return;
|
||||
|
||||
window.rt.selectElevationSegment(
|
||||
id,
|
||||
segmentLine,
|
||||
@@ -732,11 +776,14 @@ window.rt.drawElevPoints = function (id, points, options) {
|
||||
opacity: 0.92,
|
||||
className: "rt-elev-tooltip"
|
||||
});
|
||||
}
|
||||
|
||||
m.on("click", function (e) {
|
||||
if (window.rt.handleInspectorLayerClick(e)) return;
|
||||
if (!showSlopeTooltips || !p || typeof p.slope !== "number" || !Number.isFinite(p.slope)) return;
|
||||
if (!window.rt.isMobileLayout || !window.rt.isMobileLayout()) return;
|
||||
try { m.openTooltip(e && e.latlng); } catch { }
|
||||
});
|
||||
}
|
||||
|
||||
m.addTo(group);
|
||||
}
|
||||
@@ -978,6 +1025,8 @@ window.rt.drawPreviewLine = function (id, coords, options) {
|
||||
// ✅ Hacer la línea clicable y avisar a Blazor
|
||||
line.on("click", function (e) {
|
||||
try {
|
||||
if (window.rt.handleInspectorLayerClick(e)) return;
|
||||
|
||||
if (e && e.originalEvent) {
|
||||
if (e.originalEvent.preventDefault) e.originalEvent.preventDefault();
|
||||
if (e.originalEvent.stopPropagation) e.originalEvent.stopPropagation();
|
||||
@@ -1166,6 +1215,8 @@ window.rt.createHighlightedStopMarker = function (stop, pane, options) {
|
||||
if (stop.code && window.rt._dotNetHelper) {
|
||||
marker.on("click", function (event) {
|
||||
try {
|
||||
if (window.rt.handleInspectorLayerClick(event)) return;
|
||||
|
||||
if (event && event.originalEvent) {
|
||||
if (event.originalEvent.preventDefault) event.originalEvent.preventDefault();
|
||||
if (event.originalEvent.stopPropagation) event.originalEvent.stopPropagation();
|
||||
@@ -1355,7 +1406,10 @@ window.rt.setEndpointMarker = function (kind, lat, lon, options) {
|
||||
if (e.originalEvent.stopImmediatePropagation) e.originalEvent.stopImmediatePropagation();
|
||||
};
|
||||
|
||||
marker.on("click", stopEvent);
|
||||
marker.on("click", function (event) {
|
||||
if (window.rt.handleInspectorLayerClick(event)) return;
|
||||
stopEvent(event);
|
||||
});
|
||||
marker.on("mousedown", stopEvent);
|
||||
|
||||
marker.on("dragend", function (e) {
|
||||
@@ -1438,6 +1492,9 @@ window.rt.setInspectorMarkers = function (lat, lon, places) {
|
||||
opacity: 0.95,
|
||||
className: "rt-inspector-tooltip"
|
||||
});
|
||||
puntoZ.on("click", function (event) {
|
||||
window.rt.handleInspectorLayerClick(event);
|
||||
});
|
||||
puntoZ.addTo(window.rt._inspectorLayer);
|
||||
|
||||
const lugares = Array.isArray(places) ? places.slice(0, 3) : [];
|
||||
@@ -1510,6 +1567,9 @@ window.rt.setInspectorMarkers = function (lat, lon, places) {
|
||||
opacity: 0.95,
|
||||
className: "rt-inspector-tooltip"
|
||||
});
|
||||
marker.on("click", function (event) {
|
||||
window.rt.handleInspectorLayerClick(event);
|
||||
});
|
||||
marker.addTo(window.rt._inspectorLayer);
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user