Prima bozza trend analysis

This commit is contained in:
Samuele Locatelli
2025-03-10 16:03:55 +01:00
parent dc9ee5bff1
commit 3db816c41d
17 changed files with 393 additions and 111 deletions
+22
View File
@@ -277,6 +277,28 @@ namespace MP.Data.Controllers
return dbResult;
}
/// <summary>
/// Restituisce dataset FluxLog filtrato
/// </summary>
/// <param name="IdxMacchina">Macchina singola, se "" = tutte</param>
/// <param name="DtStart">Data inizio selezione odl (inizio/fine)</param>
/// <param name="DtEnd">Data fine selezione odl (inizio/fine)</param>
/// <returns></returns>
public List<FLModel> FluxLogRawData(string IdxMacchina, DateTime DtStart, DateTime DtEnd)
{
List<FLModel> dbResult = new List<FLModel>();
using (var dbCtx = new MoonPro_STATSContext(_configuration))
{
dbResult = dbCtx
.DbSetFL
.Where(x => (IdxMacchina=="*" || x.IdxMacchina == IdxMacchina) && (x.dtEvento >= DtStart && x.dtEvento <= DtEnd))
.ToList();
}
return dbResult;
}
/// <summary>
/// Elenco tabella ODL da filtro
/// </summary>
+30
View File
@@ -0,0 +1,30 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
#nullable disable
// <Auto-Generated>
// This is here so CodeMaid doesn't reorganize this document
// </Auto-Generated>
namespace MP.Data.DbModels
{
[Table("FL")]
public partial class FLModel
{
#region Public Properties
[MaxLength(50)]
public string IdxMacchina { get; set; }
public DateTime dtEvento { get; set; }
[MaxLength(50)]
public string CodFlux { get; set; }
[MaxLength(250)]
public string Valore { get; set; }
#endregion Public Properties
}
}
+7
View File
@@ -42,6 +42,7 @@ namespace MP.Data
public virtual DbSet<ConfigModel> DbSetConfig { get; set; }
public virtual DbSet<ResControlli> DbSetControlli { get; set; }
public virtual DbSet<DdbTurni> DbSetDdbTurni { get; set; }
public virtual DbSet<FLModel> DbSetFL { get; set; }
public virtual DbSet<Macchine> DbSetMacchine { get; set; }
public virtual DbSet<StatsODL> DbSetODL { get; set; }
public virtual DbSet<OdlEnergyModel> DbSetOdlEnergy { get; set; }
@@ -94,6 +95,12 @@ namespace MP.Data
.HasComment("Valore di default/riferimento per la variabile");
});
modelBuilder.Entity<FLModel>(entity =>
{
entity.HasKey(e => new { e.IdxMacchina, e.dtEvento, e.CodFlux });
});
modelBuilder.Entity<VocabolarioModel>(entity =>
{
entity.HasKey(e => new { e.Lingua, e.Lemma });
+3 -15
View File
@@ -33,14 +33,6 @@ namespace MP.Stats.Components
#endregion Public Properties
#region Protected Fields
protected const string EsitoKO = "Esito: Non Passato";
protected const string EsitoOK = "Esito: OK";
#endregion Protected Fields
#region Protected Properties
protected SelectData _currFilter { get; set; } = new SelectData();
@@ -87,8 +79,6 @@ namespace MP.Stats.Components
#region Protected Methods
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
/// </summary>
@@ -129,6 +119,7 @@ namespace MP.Stats.Components
#region Private Fields
private List<string> lineTitles = new List<string>() { "Consumo/UM" };
private List<string> listMachine = new List<string>();
private string pieTitle = "Macchina";
#endregion Private Fields
@@ -164,8 +155,6 @@ namespace MP.Stats.Components
private List<chartJsData.chartJsTSerie> TSData { get; set; } = new List<chartJsData.chartJsTSerie>();
private List<List<chartJsData.chartJsTSerie>> TSDataMulti { get; set; } = new List<List<chartJsData.chartJsTSerie>>();
private List<string> listMachine = new List<string>();
#endregion Private Properties
#region Private Methods
@@ -178,7 +167,7 @@ namespace MP.Stats.Components
if (DynMode)
{
ParetoData = RawData
.GroupBy(p => new { p.IdxMacchina})
.GroupBy(p => new { p.IdxMacchina })
//.GroupBy(p => new { p.IdxMacchina, p.CodArticolo })
.Select(y => new ChartKV() { label = y.First().IdxMacchina, value = y.Count() })
//.Select(y => new ChartKV() { label = $"{y.First().IdxMacchina} {y.First().CodArticolo}", value = y.Count() })
@@ -209,7 +198,6 @@ namespace MP.Stats.Components
.ToList();
TSDataMulti.Add(TSDataCurr);
}
}
else
{
@@ -218,7 +206,7 @@ namespace MP.Stats.Components
.GroupBy(p => new { p.IdxMacchina })
//.GroupBy(p => new { p.IdxMacchina, p.CodArticolo })
.Select(y => new ChartKV() { label = y.First().IdxMacchina, value = y.Count() })
//.Select(y => new ChartKV() { label = $"{y.First().IdxMacchina} {y.First().CodArticolo}", value = y.Count() })
//.Select(y => new ChartKV() { label = $"{y.First().IdxMacchina} {y.First().CodArticolo}", value = y.Count() })
.OrderByDescending(x => x.value)
.ToList();
+9 -9
View File
@@ -11,7 +11,7 @@
{
<div class="col-2">
<div class="border" style="max-height: 14em; overflow:hidden; overflow-y: auto;">
<i>Selezione tipo (day/week/month/year) + selezione ITEM da mostrare</i>
<i>Selezione tipo (day/week/month/year) + selezione ITEM da mostrare, tra quelli POSSIBILI dato periodo...</i>
<ul class="list-group list-group-sm small">
@foreach (var item in @ParetoData)
{
@@ -29,14 +29,14 @@
<PieChart Id="PieODL" AspRatio="1" LegendPos="bottom" Data="@DatiPareto" Labels="@LabelPareto" lineColor="@lineColors" backColor="@bgColors" Title="@pieTitle"></PieChart>
</div>
<div class="col-10">
@if (DynMode)
{
<MultiLine Id="PlotODL" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColors" backColor="@bgColors" lTens="0" Titles="@lineTitles" Stepped="false"></MultiLine>
}
else
{
<Line Id="PlotODL" AspRatio="4" DataTS="@DatiPlot" Labels="@LabelPlot" lineColor="@lineColor" backColor="@lineColor" lTens="0" Title="@lineTitles.FirstOrDefault()" Stepped="true"></Line>
}
<b>Day</b>
<MultiLine Id="plotDay" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColors" backColor="@bgColors" lTens="0" Titles="@lineTitles" Stepped="false"></MultiLine>
<b>Week</b>
<MultiLine Id="plotWeek" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColors" backColor="@bgColors" lTens="0" Titles="@lineTitles" Stepped="false"></MultiLine>
<b>Month</b>
<MultiLine Id="plotMonth" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColors" backColor="@bgColors" lTens="0" Titles="@lineTitles" Stepped="false"></MultiLine>
@* <b>Year</b>
<MultiLine Id="plotYear" AspRatio="4" DataTSList="@TSDataMulti" Labels="@LabelPlot" lineColor="@lineColors" backColor="@bgColors" lTens="0" Titles="@lineTitles" Stepped="false"></MultiLine> *@
</div>
</div>
</div>
+48 -13
View File
@@ -1,7 +1,9 @@
using Microsoft.AspNetCore.Components;
using MP.Data;
using MP.Data.DbModels;
using MP.Data.Services;
using MP.Stats.Data;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -12,10 +14,7 @@ namespace MP.Stats.Components
#region Public Properties
[Parameter]
public bool DynMode { get; set; } = false;
[Parameter]
public List<MP.Data.DbModels.OdlEnergyModel> RawData
public List<FLModel> RawData
{
get => _rawData;
set
@@ -34,17 +33,11 @@ namespace MP.Stats.Components
#region Protected Fields
protected const string EsitoKO = "Esito: Non Passato";
protected const string EsitoOK = "Esito: OK";
#endregion Protected Fields
#region Protected Properties
protected SelectData _currFilter { get; set; } = new SelectData();
protected List<MP.Data.DbModels.OdlEnergyModel> _rawData { get; set; } = new List<MP.Data.DbModels.OdlEnergyModel>();
protected List<FLModel> _rawData { get; set; } = new List<FLModel>();
/// <summary>
/// Genera colori sfondo 33% rosso / arancione / giallo
@@ -74,7 +67,7 @@ namespace MP.Stats.Components
}
[Inject]
protected Data.MessageService MessageService { get; set; }
protected Data.MessageService MService { get; set; }
[Inject]
protected MpStatsService StatService { get; set; }
@@ -174,6 +167,42 @@ namespace MP.Stats.Components
if (RawData != null)
{
lineTitles = new List<string>();
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} {y.First().CodFlux}", value = y.Count() })
.OrderByDescending(x => x.value)
.ToList();
TSData = RawData
.Select(r => new chartJsData.chartJsTSerie() { x = r.dtEvento, y = cDouble(r.Valore) })
.OrderBy(o => o.x)
.ToList();
// reset lista
TSDataMulti = new List<List<chartJsData.chartJsTSerie>>();
// 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")} / {StatService.FluxGetUM("TotCount01")}");
var TSDataCurr = RawData
.Where(x => x.IdxMacchina == idxMacc)
.Select(r => new chartJsData.chartJsTSerie() { x = r.dtEvento, y = cDouble(r.Valore) })
.OrderBy(o => o.x)
.ToList();
TSDataMulti.Add(TSDataCurr);
}
#if false
if (DynMode)
{
ParetoData = RawData
@@ -226,10 +255,16 @@ namespace MP.Stats.Components
.Select(r => new chartJsData.chartJsTSerie() { x = r.First().DataInizio.Date, y = r.Average(l => (double)l.AvgWatt) })
.OrderBy(o => o.x)
.ToList();
}
}
#endif
}
}
private double cDouble(string origValue)
{
return double.Parse(origValue);
}
#endregion Private Methods
}
}
+39
View File
@@ -440,6 +440,45 @@ namespace MP.Stats.Data
return numRec;
}
/// <summary>
/// Recupero dati FluxLog secondo filtro + richiesta raggruppamento
/// </summary>
/// <param name="CurrFilter"></param>
/// <param name="searchVal"></param>
/// <returns></returns>
public async Task<List<FLModel>> FluxLogRawData(SelectData CurrFilter, string searchVal = "")
{
// setup parametri costanti
string source = "DB";
Stopwatch sw = new Stopwatch();
sw.Start();
List<FLModel> result = new List<FLModel>();
// cerco in redis...
DateTime adesso = DateTime.Now;
string currKey = getCacheKey($"{redisBaseKey}:FL_DATA", CurrFilter);
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<FLModel>>($"{rawData}");
source = "REDIS";
}
else
{
result = dbController.FluxLogRawData(CurrFilter.IdxMacchina, CurrFilter.DateStart, CurrFilter.DateEnd);
// serializzp e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, FastCache);
}
if (result == null)
{
result = new List<FLModel>();
}
sw.Stop();
Log.Debug($"FluxLogRawData | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Statistiche ODL
/// </summary>
+2 -2
View File
@@ -4,8 +4,8 @@
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>MP.Stats</RootNamespace>
<UserSecretsId>826e877c-ba70-4253-84cb-d0b1cafd4440</UserSecretsId>
<Version>6.16.2503.1012</Version>
<Version>6.16.2503.1012</Version>
<Version>6.16.2503.1016</Version>
<Version>6.16.2503.1016</Version>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);1591</NoWarn>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
+44 -44
View File
@@ -15,34 +15,9 @@ namespace MP.Stats.Pages
{
#region Public Methods
public string checkSelect(int IdxODL)
{
string answ = "";
if (currRecord != null)
{
try
{
answ = (currRecord.IdxOdl == IdxODL) ? "table-info" : "";
}
catch
{ }
}
return answ;
}
public void Dispose()
{
MessageService.EA_SearchUpdated -= OnSeachUpdated;
}
/// <summary>
/// recupero UM del flusso indicato
/// </summary>
/// <param name="CodFlux"></param>
/// <returns></returns>
public string GetUM(string CodFlux)
{
return StatService.FluxGetUM(CodFlux);
MServ.EA_SearchUpdated -= OnSeachUpdated;
}
public async void OnSeachUpdated()
@@ -54,16 +29,6 @@ namespace MP.Stats.Pages
});
}
/// <summary>
/// Traduzione lemma richeisto (lingua default="IT")
/// </summary>
/// <param name="Lemma"></param>
/// <returns></returns>
public string Traduci(string Lemma)
{
return TradService.Traduci(Lemma);
}
#endregion Public Methods
#region Protected Fields
@@ -78,7 +43,7 @@ namespace MP.Stats.Pages
protected IJSRuntime JSRuntime { get; set; }
[Inject]
protected Data.MessageService MessageService { get; set; }
protected Data.MessageService MServ { get; set; }
[Inject]
protected NavigationManager NavManager { get; set; }
@@ -106,6 +71,21 @@ namespace MP.Stats.Pages
#region Protected Methods
protected string checkSelect(int IdxODL)
{
string answ = "";
if (currRecord != null)
{
try
{
answ = (currRecord.IdxOdl == IdxODL) ? "table-info" : "";
}
catch
{ }
}
return answ;
}
protected async Task DoFilter(SelectData newFilter)
{
clearFile();
@@ -115,14 +95,24 @@ namespace MP.Stats.Pages
await ReloadData();
}
/// <summary>
/// recupero UM del flusso indicato
/// </summary>
/// <param name="CodFlux"></param>
/// <returns></returns>
protected string GetUM(string CodFlux)
{
return StatService.FluxGetUM(CodFlux);
}
protected override async Task OnInitializedAsync()
{
clearFile();
numRecord = 10;
MessageService.ShowSearch = false;
MessageService.PageName = "ENERGY";
MessageService.PageIcon = "oi oi-bar-chart";
MessageService.EA_SearchUpdated += OnSeachUpdated;
MServ.ShowSearch = false;
MServ.PageName = "ENERGY";
MServ.PageIcon = "oi oi-bar-chart";
MServ.EA_SearchUpdated += OnSeachUpdated;
await LoadConfData();
await ReloadData();
}
@@ -175,6 +165,16 @@ namespace MP.Stats.Pages
}
}
/// <summary>
/// Traduzione lemma richeisto (lingua default="IT")
/// </summary>
/// <param name="Lemma"></param>
/// <returns></returns>
protected string Traduci(string Lemma)
{
return TradService.Traduci(Lemma);
}
protected async Task UpdateData()
{
currRecord = null;
@@ -202,11 +202,11 @@ namespace MP.Stats.Pages
{
get
{
return MessageService.ODL_Filter;
return MServ.ODL_Filter;
}
set
{
MessageService.ODL_Filter = value;
MServ.ODL_Filter = value;
}
}
@@ -271,7 +271,7 @@ namespace MP.Stats.Pages
private async Task ReloadData()
{
SearchRecords = await StatService.StatOdlEnergyGetAll(currFilter, MessageService.SearchVal);
SearchRecords = await StatService.StatOdlEnergyGetAll(currFilter, MServ.SearchVal);
DisplayData();
}
-17
View File
@@ -1,17 +0,0 @@
@page "/TrendAnalisys"
@page "/trend-analisys"
@using MP.Stats.Components
<div class="card">
<div class="card-header table-primary p-1">
@* <SelectionFilter SelFilter="currFilter" filterChanged="DoFilter" filterReset="ResetFilter" chartVisible="ShowCharts" chartsToggle="ToggleChart" ChartEnabled="true"></SelectionFilter> *@
<h4>Titolo + filtro (TBD)</h4>
<small>filtro periodo e macchine</small>
</div>
<div class="card-body py-0 px-1">
<ChartTrends></ChartTrends>
</div>
</div>
-7
View File
@@ -1,7 +0,0 @@
namespace MP.Stats.Pages
{
public partial class TrendAnalisys
{
}
}
+18
View File
@@ -0,0 +1,18 @@
@page "/TrendAnalysis"
@page "/trend-analysis"
@using MP.Stats.Components
<div class="card">
<div class="card-header table-primary p-1">
<SelectionFilter SelFilter="currFilter" filterChanged="DoFilter" filterReset="ResetFilter" ChartEnabled="false"></SelectionFilter>
</div>
<div class="card-body py-0 px-1">
<ChartTrends RawData="SearchRecords"></ChartTrends>
</div>
<div class="card-footer text-end">
#rec: @totalCount
</div>
</div>
+167
View File
@@ -0,0 +1,167 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using MP.Data.DbModels;
using MP.Data.Services;
using MP.Stats.Data;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MP.Stats.Pages
{
public partial class TrendAnalysis
{
#region Public Methods
public void Dispose()
{
MServ.EA_SearchUpdated -= OnSeachUpdated;
}
public async void OnSeachUpdated()
{
await InvokeAsync(() =>
{
Task task = UpdateData();
StateHasChanged();
});
}
#endregion Public Methods
#region Protected Fields
protected string fileName = "TrendAnalysis.csv";
#endregion Protected Fields
#region Protected Properties
[Inject]
protected IJSRuntime JSRuntime { get; set; }
[Inject]
protected Data.MessageService MServ { get; set; }
[Inject]
protected NavigationManager NavManager { get; set; }
[Inject]
protected MpStatsService StatService { get; set; }
protected int totalCount
{
get
{
int answ = 0;
if (SearchRecords != null)
{
answ = SearchRecords.Count;
}
return answ;
}
}
[Inject]
protected TranslateSrv TradService { get; set; }
#endregion Protected Properties
#region Protected Methods
protected async Task DoFilter(SelectData newFilter)
{
SearchRecords = null;
currFilter = newFilter;
await ReloadData();
}
protected override async Task OnInitializedAsync()
{
MServ.ShowSearch = false;
MServ.PageName = "Trend Analisys";
MServ.PageIcon = "fa-solid fa-arrow-trend-up";
CalcFilt();
MServ.EA_SearchUpdated += OnSeachUpdated;
await LoadConfData();
await ReloadData();
}
protected async Task ResetFilter(SelectData newFilter)
{
SearchRecords = null;
CalcFilt();
await ReloadData();
}
/// <summary>
/// Traduzione lemma richeisto (lingua default="IT")
/// </summary>
/// <param name="Lemma"></param>
/// <returns></returns>
protected string Traduci(string Lemma)
{
return TradService.Traduci(Lemma);
}
protected async Task UpdateData()
{
await ReloadData();
}
#endregion Protected Methods
#region Private Fields
private List<ConfigModel> ConfigList;
private List<FLModel> SearchRecords;
#endregion Private Fields
#region Private Properties
private SelectData currFilter
{
get
{
return MServ.ODL_Filter;
}
set
{
MServ.ODL_Filter = value;
}
}
private bool isLoading { get; set; } = false;
#endregion Private Properties
#region Private Methods
/// <summary>
/// Calcola il filtro alla data necessaria x arrivare al confronto x mese...
/// </summary>
private void CalcFilt()
{
DateTime oggi = DateTime.Now.Date;
DateTime inizio = new DateTime(oggi.Year, oggi.Month, 1).AddMonths(-1);
int numPrev = (int)oggi.Subtract(inizio).TotalDays;
currFilter = SelectData.Init(5, numPrev);
}
private async Task LoadConfData()
{
ConfigList = await StatService.ConfigGetAll();
}
private async Task ReloadData()
{
SearchRecords = await StatService.FluxLogRawData(currFilter, MServ.SearchVal);
}
#endregion Private Methods
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>Modulo statistiche MAPO</i>
<h4>Versione: 6.16.2503.1012</h4>
<h4>Versione: 6.16.2503.1016</h4>
<br />
Note di rilascio:
<ul>
+1 -1
View File
@@ -1 +1 @@
6.16.2503.1012
6.16.2503.1016
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>6.16.2503.1012</version>
<version>6.16.2503.1016</version>
<url>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/MP.Stats.zip</url>
<changelog>https://nexus.steamware.net/repository/SWS/MP-STATS/stable/LAST/ChangeLog.html</changelog>
<mandatory>false</mandatory>
+1 -1
View File
@@ -42,7 +42,7 @@
</NavLink>
</li>
<li class="nav-item px-2">
<NavLink class="nav-link" href="trend-analisys">
<NavLink class="nav-link" href="trend-analysis">
<i class="fa-solid fa-arrow-trend-up pe-3"></i>
@if (showText)
{