Files
2025-07-08 18:37:35 +02:00

435 lines
15 KiB
C#

using Microsoft.AspNetCore.Components;
using MongoDB.Driver.Linq;
using MP.Data;
using MP.Data.DbModels;
using MP.Data.Services;
using MP.Stats.Data;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
namespace MP.Stats.Components
{
public partial class ChartTrends
{
#region Public Properties
[Parameter]
public List<string> CodFluxList { get; set; }
[Parameter]
public EventCallback<string> EC_CodFluxSel { get; set; }
[Parameter]
public EventCallback<string> EC_IdxMaccRem { get; set; }
[Parameter]
public bool ShowRem { get; set; } = false;
[Parameter]
public List<FLModel> RawData
{
get => _rawData;
set
{
// salvo valori
_rawData = value;
if (value != null)
{
// ricalcolo charting data
RecalcData();
}
}
}
#endregion Public Properties
private async Task RemoveMachine(string idxMacc)
{
await EC_IdxMaccRem.InvokeAsync(idxMacc);
}
#region Protected Enums
protected enum PeriodoSel
{
Day,
Week,
Month,
Year
}
#endregion Protected Enums
#region Protected Properties
protected List<FLModel> _rawData { get; set; } = new List<FLModel>();
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
/// <returns></returns>
protected List<string> bgColors
{
get => semaphColors(ParetoData.Count, "0.3");
}
protected List<string> bgColorsDet { get; set; } = new List<string>();
protected string CodFluxSel
{
get => codFluxSel;
set
{
if (codFluxSel != value)
{
codFluxSel = value;
EC_CodFluxSel.InvokeAsync(value).ConfigureAwait(false);
}
}
}
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
/// <returns></returns>
protected List<string> lineColor
{
get => solidColors("0.9");
}
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
/// <returns></returns>
protected List<string> lineColors
{
get => semaphColors(ParetoData.Count, "1");
}
protected List<string> lineColorsDet { get; set; } = new List<string>();
[Inject]
protected Data.MessageService MService { get; set; }
[Inject]
protected MpStatsService StatService { get; set; }
[Inject]
protected TranslateSrv TradService { get; set; }
#endregion Protected Properties
#region Protected Methods
/// <summary>
/// Genera colori sfondo alternat full / quasi grigi (x preious data)
/// </summary>
/// <param name="numRecords">numero record CURRENT</param>
/// <param name="alpha"></param>
/// <returns></returns>
protected List<string> cpColors(int numRecords, string alpha)
{
List<string> answ = new List<string>();
int r = 0;
int g = 0;
int b = 0;
// ciclo x numRecords-1
for (int j = 0; j < numRecords; j++)
{
r = 54 + (180 - 54) * j / numRecords;
g = 86 + (35 - 86) * j / numRecords;
b = 254 + (180 - 254) * j / numRecords;
answ.Add($"rgba({r}, {g}, {b}, {alpha}");
answ.Add($"rgba({(510 + r) / 3},{(510 + g) / 3},{(510 + b) / 3}, {alpha}");
}
// chiude
while (answ.Count < numRecords)
{
answ.Add($"rgba(180, 180, 35, {alpha})");
}
return answ;
}
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
/// <param name="numRecords"></param>
/// <param name="alpha"></param>
/// <returns></returns>
protected List<string> semaphColors(int numRecords, string alpha)
{
List<string> answ = new List<string>();
// ciclo x numRecords-1
for (int j = 0; j < numRecords; j++)
{
answ.Add($"rgba({54 + (180 - 54) * j / numRecords}, {86 + (35 - 86) * j / numRecords}, {254 + (180 - 254) * j / numRecords}, {alpha}");
}
// chiude
while (answ.Count < numRecords)
{
answ.Add($"rgba(180, 180, 35, {alpha})");
}
return answ;
}
/// <summary>
/// Colore azzurro + alpha
/// </summary>
/// <param name="alpha"></param>
/// <returns></returns>
protected List<string> solidColors(string alpha)
{
List<string> answ = new List<string>();
answ.Add($"rgba(54, 162, 235, {alpha})");
return answ;
}
#endregion Protected Methods
#region Private Fields
private List<string> lineTitles = new List<string>() { "Consumo/UM" };
private List<string> lineTitlesDet = new List<string>() { "Consumo/UM" };
private List<string> listMachine = new List<string>();
#if false
private string pieTitle = "Macchina";
#endif
/// <summary>
/// Modalità selezione
/// </summary>
private PeriodoSel pSel;
#endregion Private Fields
#region Private Properties
private string codFluxSel { get; set; }
private List<double> DatiPareto
{
get => ParetoData.Select(x => x.value).ToList();
}
private List<chartJsData.chartJsTSerie> DatiPlot
{
get => TSData;
}
private List<string> LabelPareto
{
get => ParetoData.Select(x => x.label).ToList();
}
private List<string> LabelPlot
{
get => TSData.Select(r => $"{r.x:yyyy-MM-dd}").ToList();
}
private List<string> LabelPlotDet { get; set; } = new List<string>();
private int numMachine
{
get => listMachine.Count;
}
private List<ChartKV> ParetoData { get; set; } = new List<ChartKV>();
private List<chartJsData.chartJsTSerie> TSData { get; set; } = new List<chartJsData.chartJsTSerie>();
private List<List<chartJsData.chartJsTSerie>> TSDataMulti { get; set; } = new List<List<chartJsData.chartJsTSerie>>();
/// <summary>
/// TimeSeries su scala DAY
/// </summary>
private List<List<chartJsData.chartJsTSerie>> TSDataMultiDetail { get; set; } = new List<List<chartJsData.chartJsTSerie>>();
#endregion Private Properties
#region Private Methods
private double cDouble(string origValue)
{
double dblVal = 0;
double.TryParse(origValue, NumberStyles.Any, CultureInfo.InvariantCulture, out dblVal);
return dblVal;
}
private string CssBtn(PeriodoSel reqMode)
{
string answ = "btn-outline-primary";
if (reqMode == pSel)
{
answ = "btn-primary text-light";
}
return answ;
}
private DateTime GetFirstDayOfWeek(DateTime date)
{
int offset = date.DayOfWeek - DayOfWeek.Sunday;
return date.AddDays(-offset);
}
/// <summary>
/// Ritorna dettaglio dato macchina e tipo (current o prev)
/// </summary>
/// <param name="idxMacc">Macchina richiesta</param>
/// <param name="codFlux">Flusso richiesto</param>
/// <param name="recapMode">Modo recap (se null --> intero periodo)</param>
/// <param name="isCurrent">Indica se iin caso di recap sia periodo corrente/precedente</param>
/// <returns></returns>
private List<chartJsData.chartJsTSerie> GetTSDetail(string idxMacc, string codFlux, PeriodoSel? recapMode, bool isCurrent = true)
{
List<chartJsData.chartJsTSerie> answ = new();
if (!recapMode.HasValue)
{
answ = RawData
.Where(x => x.IdxMacchina == idxMacc)
.Select(r => new chartJsData.chartJsTSerie() { x = r.dtEvento, y = cDouble(r.Valore) })
.OrderBy(o => o.x)
.ToList();
}
else
{
// fake fix: indietro 7 gg...
DateTime dataRif = DateTime.Today;//.AddDays(-7);
TimeSpan deltaOld = new TimeSpan(0);
DateTime dtStart = dataRif;
DateTime inizio = dataRif;
DateTime fine = inizio.AddDays(1);
double startVal = 0;
switch (recapMode)
{
case PeriodoSel.Day:
inizio = isCurrent ? dataRif : dataRif.AddDays(-1);
fine = inizio.AddDays(1);
deltaOld = TimeSpan.FromDays(1);
break;
case PeriodoSel.Week:
inizio = isCurrent ? GetFirstDayOfWeek(dataRif) : GetFirstDayOfWeek(dataRif).AddDays(-7);
fine = inizio.AddDays(7);
deltaOld = TimeSpan.FromDays(7);
break;
case PeriodoSel.Month:
inizio = isCurrent ? new DateTime(dataRif.Year, dataRif.Month, 1) : new DateTime(dataRif.Year, dataRif.Month, 1).AddMonths(-1);
fine = inizio.AddMonths(1);
deltaOld = inizio.AddMonths(1).Subtract(inizio);
break;
case PeriodoSel.Year:
inizio = isCurrent ? new DateTime(dataRif.Year, 1, 1) : new DateTime(dataRif.Year, 1, 1).AddYears(-1);
fine = inizio.AddYears(1);
deltaOld = inizio.AddYears(1).Subtract(inizio);
break;
case null:
default:
break;
}
// calcolo il minimo...
var listRaw = RawData
.Where(x => x.IdxMacchina == idxMacc && x.dtEvento >= inizio && x.dtEvento < fine)
.OrderBy(o => o.dtEvento)
.ToList();
var firstRec = listRaw
.FirstOrDefault();
if (firstRec != null)
{
startVal = cDouble(firstRec.Valore);
dtStart = firstRec.dtEvento.Date;
}
answ = listRaw
.Select(r => new chartJsData.chartJsTSerie() { x = isCurrent ? r.dtEvento : r.dtEvento.Add(deltaOld), y = cDouble(r.Valore) - startVal })
.OrderBy(o => o.x)
.ToList();
}
return answ;
}
private void RecalcData()
{
if (RawData != null)
{
// reset preliminare
TSDataMulti.Clear();
TSDataMultiDetail.Clear();
lineTitles.Clear();
lineTitlesDet.Clear();
LabelPlotDet.Clear();
bgColorsDet.Clear();
lineColorsDet.Clear();
// calcolo i dati Pareto
ParetoData = RawData
//.GroupBy(p => new { p.IdxMacchina })
.GroupBy(p => new { p.IdxMacchina, p.CodFlux })
//.Select(y => new ChartKV() { label = y.First().IdxMacchina, value = y.Count() })
.Select(y => new ChartKV() { label = $"{y.First().IdxMacchina} {TradService.Traduci($"MP-STATS_{y.First().CodFlux}")}", value = y.Count() })
.OrderByDescending(x => x.value)
.ToList();
// ciclo x ogni macchina
listMachine = RawData
.GroupBy(x => x.IdxMacchina)
.Select(y => y.First().IdxMacchina)
.ToList();
foreach (var idxMacc in listMachine)
{
lineTitles.Add($"{idxMacc} | {TradService.Traduci("MP-STATS_TotEn01")}");
lineTitlesDet.Add($"{idxMacc} | {TradService.Traduci("MP-STATS_TotEn01")} - CURR");
lineTitlesDet.Add($"{idxMacc} | {TradService.Traduci("MP-STATS_TotEn01")} - PREV");
// periodo completo
TSDataMulti.Add(GetTSDetail(idxMacc, "", null));
// dettaglio richiesto...
var currPlot = GetTSDetail(idxMacc, "", pSel, true);
TSDataMultiDetail.Add(currPlot);
TSDataMultiDetail.Add(GetTSDetail(idxMacc, "", pSel, false));
#if false
if (LabelPlotDet.Count == 0)
{
switch (pSel)
{
//case PeriodoSel.Day:
// LabelPlotDet = currPlot.Select(r => $"{r.x:HH}").ToList();
// break;
//case PeriodoSel.Week:
// LabelPlotDet = currPlot.Select(r => $"{r.x:dd}").ToList();
// break;
//case PeriodoSel.Month:
// LabelPlotDet = currPlot.Select(r => $"{r.x:dd}").ToList();
// break;
//case PeriodoSel.Year:
// LabelPlotDet = currPlot.Select(r => $"{r.x:MM-dd}").ToList();
// break;
//default:
// LabelPlotDet = currPlot.Select(r => $"{r.x:yyyy-MM-dd}").ToList();
// break;
}
}
#endif
}
bgColorsDet = cpColors(ParetoData.Count, "0.3");
lineColorsDet = cpColors(ParetoData.Count, "1");
}
}
private void SetModo(PeriodoSel newModo)
{
pSel = newModo;
// ricalcolo!
RecalcData();
}
#endregion Private Methods
}
}