update interafaccia Callstats

This commit is contained in:
Samuele Locatelli
2026-04-18 10:19:37 +02:00
parent b6a1879543
commit e3c1c6baef
6 changed files with 79 additions and 84 deletions
+16 -2
View File
@@ -62,14 +62,28 @@
}
else
{
<b>@currDetail</b>
if (tsDataDetail.Count == 0)
{
<div class="alert alert-info">&larr; No data found</div>
}
else
{
<MultiLine Id="@currTsId" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" Stepped="false" yScale="logarithmic"></MultiLine>
<div class="card shadow">
<div class="card-header d-flex justify-content-between">
<div class="px-0">
<b>@currDetail</b>
</div>
<div class="px-0">
<div class="input-group">
<span class="input-group-text"># giorni</span>
<input type="number" class="form-control form-control-sm" @bind="numDays" @bind:after="OnDaysChangedAsync">
</div>
</div>
</div>
<div class="card-body">
<MultiLine Id="@currTsId" AspRatio="2.5" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColorsMLine" backColor="@bgColorsMLine" lTens="0" Titles="@lineTitles" Stepped="false" yScale="logarithmic"></MultiLine>
</div>
</div>
}
}
</div>
+59 -78
View File
@@ -9,6 +9,28 @@ namespace MP.IOC.Components.Pages
{
public partial class CallStats
{
#region Protected Properties
private int numDays
{
get => _numDays;
set
{
if (_numDays != value)
{
_numDays = value;
//_ = ShowDetail(currDetail);
}
}
}
private async Task OnDaysChangedAsync()
{
// Questo metodo viene invocato automaticamente dopo che numDays è stato aggiornato
await ShowDetail(currDetail);
// Non serve chiamare StateHasChanged(), Blazor lo fa al termine del Task
}
#endregion Protected Properties
#region Protected Methods
protected override async Task OnInitializedAsync()
@@ -20,6 +42,7 @@ namespace MP.IOC.Components.Pages
#region Private Fields
private int _numDays = 5;
private List<StatDataDTO> currData = new();
private string currDetail = "";
@@ -64,17 +87,12 @@ namespace MP.IOC.Components.Pages
private List<double> DatiPareto
{
get => currData.Where(x => x.Value > 10).OrderByDescending(x => x.Value).Take(ParetoTake).Select(x => x.Value).ToList();
get => currData.OrderByDescending(x => x.Value).Take(ParetoTake).Select(x => x.Value).ToList();
}
private List<string> LabelPareto
{
get => currData.Where(x => x.Value > 10).OrderByDescending(x => x.Value).Take(ParetoTake).Select(x => x.Label).ToList();
}
private int ParetoTake
{
get => currData.Count() <= 30 ? currData.Count() : 30;
get => currData.OrderByDescending(x => x.Value).Take(ParetoTake).Select(x => x.Label).ToList();
}
private List<string> LabelPlot
@@ -96,6 +114,11 @@ namespace MP.IOC.Components.Pages
get => GetDistinctColors(tsDataDetail.Count, "1");
}
private int ParetoTake
{
get => currData.Count() <= 30 ? currData.Count() : 30;
}
[Inject]
private IStatsDetailService SDetService { get; set; } = null!;
@@ -131,36 +154,37 @@ namespace MP.IOC.Components.Pages
}
}
private async Task ReloadData()
private List<string> GetDistinctColors(int numRecords, string alpha)
{
ParetoDay = await SDetService.GetParetoStatsDayAsync();
}
List<string> colors = new List<string>();
if (numRecords <= 0) return colors;
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
/// <param name="numRecords"></param>
/// <param name="alpha"></param>
/// <returns></returns>
private List<string> semaphColors(int numRecords, string alpha)
{
List<string> answ = new List<string>();
// verde...
for (int i = 0; i < numRecords / 3; i++)
// Partiamo dal Blu (240°) invece che dal Rosso (0°)
double startHue = 240.0;
for (int i = 0; i < numRecords; i++)
{
answ.Add($"rgba(54, 235, 82, {alpha})");
}
// arancione
for (int i = 0; i < numRecords / 3; i++)
{
answ.Add($"rgba(255, 206, 86, {alpha})");
}
while (answ.Count < numRecords)
{
answ.Add($"rgba(255, 99, 132, {alpha}");
// Distribuiamo la tonalità aggiungendo l'offset iniziale
// L'operatore % 360 assicura di rimanere nel cerchio se superiamo il rosso
double hue = (startHue + ((double)i * 360 / numRecords)) % 360;
// Strategia di distinzione (attiva sempre, ma più efficace sopra i 5 colori)
// Alterniamo i valori per i record pari/dispari
string saturation = "70%";
string lightness = "50%";
if (numRecords > 5)
{
// Se i colori sono molti, alterniamo luminosità e saturazione
// I record dispari saranno più chiari e saturi, i pari più scuri e tenui
lightness = (i % 2 == 0) ? "45%" : "65%";
saturation = (i % 2 == 0) ? "80%" : "60%";
}
colors.Add($"hsla({hue:0.##}, {saturation}, {lightness}, {alpha})");
}
return answ;
return colors;
}
private List<string> GetSemaforicColors(int numRecords, string alpha)
@@ -202,53 +226,10 @@ namespace MP.IOC.Components.Pages
return colors;
}
//private List<string> GetDistinctColors(int numRecords, string alpha)
//{
// List<string> colors = new List<string>();
// for (int i = 0; i < numRecords; i++)
// {
// // Distribuiamo la tonalità (Hue) uniformemente sui 360 gradi
// double hue = (double)i * 360 / numRecords;
// // Usiamo il formato CSS hsla() che è più semplice da generare direttamente
// // Saturazione 70% e Luminosità 50-60% di solito danno colori vivaci e distinti
// colors.Add($"hsla({hue:0.##}, 70%, 50%, {alpha})");
// }
// return colors;
//}
private List<string> GetDistinctColors(int numRecords, string alpha)
private async Task ReloadData()
{
List<string> colors = new List<string>();
if (numRecords <= 0) return colors;
// Partiamo dal Blu (240°) invece che dal Rosso (0°)
double startHue = 240.0;
for (int i = 0; i < numRecords; i++)
{
// Distribuiamo la tonalità aggiungendo l'offset iniziale
// L'operatore % 360 assicura di rimanere nel cerchio se superiamo il rosso
double hue = (startHue + ((double)i * 360 / numRecords)) % 360;
// Strategia di distinzione (attiva sempre, ma più efficace sopra i 5 colori)
// Alterniamo i valori per i record pari/dispari
string saturation = "70%";
string lightness = "50%";
if (numRecords > 5)
{
// Se i colori sono molti, alterniamo luminosità e saturazione
// I record dispari saranno più chiari e saturi, i pari più scuri e tenui
lightness = (i % 2 == 0) ? "45%" : "65%";
saturation = (i % 2 == 0) ? "80%" : "60%";
}
colors.Add($"hsla({hue:0.##}, {saturation}, {lightness}, {alpha})");
}
return colors;
ParetoDay = await SDetService.GetParetoStatsDayAsync();
}
/// <summary>
@@ -260,7 +241,7 @@ namespace MP.IOC.Components.Pages
currDetail = selDetail;
// recupero dettaglio 7gg...
DateTime adesso = DateTime.Now;
List<StatsDetailModel> rawData = await SDetService.GetFiltAsync(adesso.AddDays(-5), adesso, "", selDetail);
List<StatsDetailModel> rawData = await SDetService.GetFiltAsync(adesso.AddDays(-numDays), adesso, "", selDetail);
// conversione con grouping
tsData = rawData.Select(r => new chartJsData.chartJsTSerie() { x = r.Hour, y = (double)r.AvgDuration })
.OrderBy(o => o.x)
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>6.16.2604.1809</Version>
<Version>6.16.2604.1810</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo MP-IOC </i>
<h4>Versione: 6.16.2604.1809</h4>
<h4>Versione: 6.16.2604.1810</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
6.16.2604.1809
6.16.2604.1810
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>6.16.2604.1809</version>
<version>6.16.2604.1810</version>
<url>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/MP.IOC.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-IOC/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>