Update sim past/new events

This commit is contained in:
Samuele Locatelli
2026-01-15 09:25:55 +01:00
parent 41d6fb655b
commit 3a0f0d363f
12 changed files with 221 additions and 164 deletions
+18 -38
View File
@@ -17,6 +17,8 @@ namespace EgwCoreLib.Lux.Core.Generic
#if false
public int IdxDipendente { get; set; } = 0;
public string CognomeNome { get; set; } = "";
public bool Conf { get; set; } = false;
public bool IsCompany { get; set; } = false;
#endif
public string Abbrev { get; set; } = "";
public string Titolo { get; set; } = "";
@@ -25,9 +27,9 @@ namespace EgwCoreLib.Lux.Core.Generic
public DateTime DtStart { get; set; } = DateTime.Today.AddHours(9);
public DateTime DtEnd { get; set; } = DateTime.Today.AddHours(17);
public string Note { get; set; } = "";
public bool Conf { get; set; } = false;
public bool IsDraggable { get; set; } = false;
public bool IsCompany { get; set; } = false;
public bool IsExpired { get; set; } = false;
public bool IsPlanned { get; set; } = true;
public EventDto Clone()
{
@@ -38,6 +40,8 @@ namespace EgwCoreLib.Lux.Core.Generic
#if false
IdxDipendente = this.IdxDipendente,
CognomeNome = this.CognomeNome,
Conf = this.Conf,
IsCompany = this.IsCompany,
#endif
Abbrev = this.Abbrev,
Titolo = this.Titolo,
@@ -46,9 +50,9 @@ namespace EgwCoreLib.Lux.Core.Generic
DtStart = this.DtStart,
DtEnd = this.DtEnd,
Note = this.Note,
Conf = this.Conf,
IsDraggable = this.IsDraggable,
IsCompany = this.IsCompany
IsPlanned = this.IsPlanned,
IsExpired = this.IsExpired
};
}
@@ -76,72 +80,48 @@ namespace EgwCoreLib.Lux.Core.Generic
public string Color
{
get => calcColor(CodTipo, Conf, IsCompany);
get => calcColor(CodTipo, IsPlanned, IsExpired);
}
public string? ForeColor
{
get => calcText(CodTipo, Conf, IsCompany);
get => calcText(CodTipo, IsPlanned, IsExpired);
}
private string calcColor(string codTipo, bool conf, bool isComp)
private string calcColor(string codTipo, bool isPlanned, bool isExpired)
{
string answ = "#EDEDED";
switch (codTipo)
{
case "Saomad":
answ = isComp ? "#EEDD11" : conf ? "#11CD44" : "#AAFFCD";
answ = isExpired ? "#CDCDCD" : isPlanned ? "#11CD44" : "#D9FFE6";
break;
case "Essetre":
answ = "#DD0033";
answ = isExpired ? "#989898" : isPlanned ? "#AD1919" : "#CD6767";
break;
//case "104":
// answ = conf ? "#DE00AB" : "#FFAACD";
// break;
//case "MAL":
// answ = conf ? "#000" : "#696969";
// break;
//case "PERM":
// answ = conf ? "#9966DE" : "#CDAAFF";
// break;
default:
answ = isComp ? "#EEDD11" : conf ? "#11CD44" : "#AAFFCD";
answ = isExpired ? "#EEDD11" : isPlanned ? "#11CD44" : "#AAFFCD";
break;
}
return answ;
}
private string calcText(string codTipo, bool conf, bool isComp)
private string calcText(string codTipo, bool isPlanned, bool isExpired)
{
string answ = "#EDEDED";
switch (codTipo)
{
case "Saomad":
answ = isComp ? "#000000" : conf ? "#FFFFFF" : "#000000";
answ = isExpired ? "#000000" : isPlanned ? "#000000" : "#696969";
break;
case "Essetre":
answ = "#EEDD11";
answ = isExpired ? "#000000" : isPlanned ? "#EEDD11" : "#A39F2A";
break;
//case "104":
// answ = conf ? "#DEDEDE" : "#000000";
// break;
//case "MAL":
// answ = conf ? "#DEDEDE" : "#ABABAB";
// break;
//case "PERM":
// answ = conf ? "#DEDEDE" : "#000000";
// break;
default:
answ = isComp ? "#000000" : conf ? "#FFFFFF" : "#000000";
answ = isExpired ? "#000000" : isPlanned ? "#FFFFFF" : "#000000";
break;
}
return answ;
@@ -0,0 +1,129 @@
using EgwCoreLib.Lux.Core.Generic;
using EgwMultiEngineManager.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EgwCoreLib.Lux.Data.Controllers
{
public class DataSimulatorController
{
#region Public Constructors
/// <summary>
/// Controller per generazioen dati simulati
/// </summary>
public DataSimulatorController()
{
rnd = new Random();
}
#endregion Public Constructors
#region Internal Methods
/// <summary>
/// Restituisce un dizionario di dati simulati x rappresentazione in planner
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <returns></returns>
internal Dictionary<string, List<EventDto>>? PlannerGetEvents(DateTime dtStart, DateTime dtEnd)
{
var dictAnsw = new Dictionary<string, List<EventDto>>();
int idx = 1;
var simSaomad = DoSimPeriod("Saomad", idx, dtStart, dtEnd, 8, 19);
dictAnsw.Add("Saomad", simSaomad);
idx += simSaomad.Count();
var simEssetre = DoSimPeriod("Essetre", idx, dtStart, dtEnd, 8, 19);
dictAnsw.Add("Essetre", simEssetre);
return dictAnsw;
}
#endregion Internal Methods
#region Private Fields
private Random rnd = new Random();
#endregion Private Fields
#region Private Methods
/// <summary>
/// Genera un set di elementi simulati secondo i criteri ricevuti
/// </summary>
/// <param name="codMacc"></param>
/// <param name="minDate"></param>
/// <param name="maxDate"></param>
/// <param name="hStart"></param>
/// <param name="hEnd"></param>
/// <param name="minDur"></param>
/// <param name="maxDur"></param>
/// <param name="maxSim"></param>
/// <returns></returns>
private List<EventDto> DoSimPeriod(string codMacc, int currIdx, DateTime minDate, DateTime maxDate, int hStart = 8, int hEnd = 18, int minDur = 120, int maxDur = 360, int maxSim = 300, int minWait = 5, int maxWait = 25)
{
List<EventDto> currListEv = new();
// init date cursore
DateTime oggi = DateTime.Today;
DateTime maxPlan = oggi.AddDays(20);
DateTime dtStart = minDate.AddHours(hStart);
DateTime dtEnd = dtStart;
// ciclo principale entro limiti...
while (dtStart < maxDate && maxSim > 0)
{
// definisce limite giornaliero
DateTime fineGiornata = dtStart.Date.AddHours(hEnd);
// Verifica dtStart sia entro limite giornaliero altrimenti va alla mattina dopo..
if (dtStart >= fineGiornata.AddMinutes(-30))
{
dtStart = dtStart.Date.AddDays(1).AddHours(hStart);
fineGiornata = dtStart.Date.AddHours(hEnd);
}
// Trova il prossimo giorno lavorativo (lunedì-venerdì) dopo dtStart
while (dtStart.DayOfWeek == DayOfWeek.Saturday || dtStart.DayOfWeek == DayOfWeek.Sunday)
{
dtStart = dtStart.AddDays(1);
fineGiornata = dtStart.Date.AddHours(hEnd);
}
// Se siamo oltre la data di limEnd, interrompi
if (dtStart > maxDate)
break;
// Calcola la fine dell'evento
dtEnd = dtStart.AddMinutes(rnd.Next(minDur, maxDur));
// Verifica se l'evento supera il limite orario
if (dtEnd > fineGiornata)
{
// Se supera il limite, taglia l'evento entro +/-30 minuti da hEnd
dtEnd = fineGiornata.AddMinutes(rnd.Next(-30, 30));
}
EventDto newEv = new EventDto()
{
CodTipo = codMacc,
Abbrev = $"POR.{minDate.Year}.{currIdx:x8}",
Titolo = $"POR.{minDate.Year}.{currIdx:x8}",
Descrizione = $"Produzione {codMacc}",
DtStart = dtStart,
DtEnd = dtEnd,
IsExpired = dtEnd < oggi.AddHours(-8),
IsPlanned = dtEnd < maxPlan
};
currListEv.Add(newEv);
dtStart = dtEnd.AddMinutes(rnd.Next(minWait, maxWait));
currIdx++;
maxSim--;
}
return currListEv;
}
#endregion Private Methods
}
}
@@ -1,4 +1,5 @@
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Core.Generic;
using EgwCoreLib.Lux.Core.RestPayload;
using EgwCoreLib.Lux.Data.Controllers;
using EgwCoreLib.Lux.Data.DbModel.Config;
using EgwCoreLib.Lux.Data.DbModel.Cost;
@@ -40,10 +41,13 @@ namespace EgwCoreLib.Lux.Data.Services
}
else
{
StringBuilder sb = new StringBuilder();
//dbController = new Controllers.LuxController(_config);
dbController = new LuxController();
StringBuilder sb = new StringBuilder();
sb.AppendLine($"DataLayerServices | LuxController OK");
sb.AppendLine($"LuxController OK");
dataSimController = new DataSimulatorController();
sb.AppendLine($"DataSimController OK");
sb.AppendLine($"LuxController OK");
Log.Info(sb.ToString());
}
}
@@ -1712,6 +1716,39 @@ namespace EgwCoreLib.Lux.Data.Services
return fatto;
}
/// <summary>
/// Restituisce un dizionario di <CodFase,EventDto> da usare nel planner
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <returns></returns>
public async Task<Dictionary<string, List<EventDto>>?> PlannerGetEvents(DateTime dtStart, DateTime dtEnd)
{
string source = "DB";
Stopwatch sw = new Stopwatch();
sw.Start();
Dictionary<string, List<EventDto>>? result = null;
// cerco in redis...
string currKey = $"{redisBaseKey}:PlannerData:{dtStart:yyyyMMdd}:{dtEnd:yyyyMMdd}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
//if (!string.IsNullOrEmpty($"{rawData}"))
if (rawData.HasValue && rawData.Length() > 2)
{
result = JsonConvert.DeserializeObject<Dictionary<string, List<EventDto>>>($"{rawData}");
source = "REDIS";
}
else
{
result = dataSimController.PlannerGetEvents(dtStart, dtEnd);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, LongCache);
}
sw.Stop();
Log.Debug($"PlannerGetEvents | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Effettua upsert complessivo Ordine
/// </summary>
@@ -2479,6 +2516,7 @@ namespace EgwCoreLib.Lux.Data.Services
#region Private Properties
private static LuxController dbController { get; set; } = null!;
private static DataSimulatorController dataSimController { get; set; } = null!;
#endregion Private Properties
+1 -1
View File
@@ -4,7 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.9.2601.1419</Version>
<Version>0.9.2601.1509</Version>
</PropertyGroup>
<ItemGroup>
@@ -109,11 +109,11 @@ namespace Lux.UI.Components.Compo.Planner
{
// in primis copio tutto
EvDtoFilt = EvDtoList;
#if false
if (ShowNeedConf)
{
EvDtoFilt = EvDtoFilt.Where(x => !x.Conf).ToList();
}
#if false
// controllo ogni toggle...
if (!showChiu)
{
@@ -59,10 +59,10 @@
<div class="px-0"><b>@model.Note</b></div>
</div>
</li>
@if (!model.Conf)
@if (!model.IsPlanned)
{
<li class="list-group-item text-center bg-danger text-warning">
<b>NON CONFERMATO</b>
<b>NON PIANIFICATO</b>
</li>
}
</ul>
+4 -4
View File
@@ -93,7 +93,7 @@
<div class="nav-item px-3">
@* <div class="nav-item px-3">
<NavLink class="nav-link" href="scratch">
<span class="bi bi-cloud-moon px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Scratch</span>
</NavLink>
@@ -103,9 +103,9 @@
<NavLink class="nav-link" href="auth">
<span class="bi bi-lock-fill px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Auth Required</span>
</NavLink>
</div>
</div> *@
<AuthorizeView>
@* <AuthorizeView>
<Authorized>
<div class="nav-item px-3">
<NavLink class="nav-link" href="Account/Manage">
@@ -134,7 +134,7 @@
</NavLink>
</div>
</NotAuthorized>
</AuthorizeView>
</AuthorizeView> *@
<div class="nav-item px-3">
<NavLink class="nav-link bg-dark bg-opacity-50 bg-gradient" href="ResetCache">
<span class="fa-solid fa-arrows-rotate px-2 fs-4" aria-hidden="true"></span> <span class="@hideText">Flush Cache</span>
+21 -111
View File
@@ -1,125 +1,50 @@
using EgwCoreLib.Lux.Core.Generic;
using EgwCoreLib.Lux.Data.Services;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
namespace Lux.UI.Components.Pages
{
public partial class ProdPlanner
{
#region Protected Methods
#region Protected Properties
#endregion Protected Methods
[Inject]
protected DataLayerServices DLService { get; set; } = null!;
#endregion Protected Properties
#region Private Fields
private List<EventDto> ListEventi { get; set; } = new();
/// <summary>
/// Periodo selezionato attuale
/// </summary>
private EgwCoreLib.Utils.DtUtils.Periodo PeriodoSel = new EgwCoreLib.Utils.DtUtils.Periodo(EgwCoreLib.Utils.DtUtils.PeriodSet.ThisYear);
private Random rnd = new Random();
#endregion Private Fields
#region Private Properties
private List<EventDto> ListEventi { get; set; } = new();
#endregion Private Properties
#region Private Methods
/// <summary>
/// Sim modalità iniziale
/// </summary>
/// <returns></returns>
private async Task DoSimData()
{
// simulo eventi...
DateTime limStart = new DateTime(DateTime.Today.Year, 1, 1);
DateTime limEnd = new DateTime(DateTime.Today.Year, 12, 31);
await Task.Delay(50);
int idx = 1;
var simSaomad = DoSimPeriod("Saomad", idx, limStart, limEnd, 8, 19);
ListEventi.AddRange(simSaomad);
idx += ListEventi.Count();
var simEssetre = DoSimPeriod("Essetre", idx, limStart, limEnd, 8, 19);
ListEventi.AddRange(simEssetre);
}
/// <summary>
/// Genera un set di elementi simulati secondo i criteri ricevuti
/// </summary>
/// <param name="codMacc"></param>
/// <param name="minDate"></param>
/// <param name="maxDate"></param>
/// <param name="hStart"></param>
/// <param name="hEnd"></param>
/// <param name="minDur"></param>
/// <param name="maxDur"></param>
/// <param name="maxSim"></param>
/// <returns></returns>
private List<EventDto> DoSimPeriod(string codMacc, int currIdx, DateTime minDate, DateTime maxDate, int hStart = 8, int hEnd = 18, int minDur = 60, int maxDur = 360, int maxSim = 500)
{
List<EventDto> currListEv = new();
// init date cursore
DateTime dtStart = minDate.AddHours(hStart);
DateTime dtEnd = dtStart;
// ciclo principale entro limiti...
while (dtStart < maxDate && maxSim > 0)
{
// definisce limite giornaliero
DateTime fineGiornata = dtStart.Date.AddHours(hEnd);
// Verifica dtStart sia entro limite giornaliero altrimenti va alla mattina dopo..
if (dtStart >= fineGiornata.AddMinutes(-30))
{
dtStart = dtStart.Date.AddDays(1).AddHours(hStart);
fineGiornata = dtStart.Date.AddHours(hEnd);
}
// Trova il prossimo giorno lavorativo (lunedì-venerdì) dopo dtStart
while (dtStart.DayOfWeek == DayOfWeek.Saturday || dtStart.DayOfWeek == DayOfWeek.Sunday)
{
dtStart = dtStart.AddDays(1);
fineGiornata = dtStart.Date.AddHours(hEnd);
}
// Se siamo oltre la data di limEnd, interrompi
if (dtStart > maxDate)
break;
// Calcola la fine dell'evento
dtEnd = dtStart.AddMinutes(rnd.Next(minDur, maxDur));
// Verifica se l'evento supera il limite orario
if (dtEnd > fineGiornata)
{
// Se supera il limite, taglia l'evento entro +/-30 minuti da hEnd
dtEnd = fineGiornata.AddMinutes(rnd.Next(-30, 30));
}
EventDto newEv = new EventDto()
{
CodTipo = codMacc,
Abbrev = $"POR.{minDate.Year}.{currIdx:x8}",
Titolo = $"POR.{minDate.Year}.{currIdx:x8}",
Descrizione = $"Produzione {codMacc}",
DtStart = dtStart,
DtEnd = dtEnd
};
currListEv.Add(newEv);
dtStart = dtEnd.AddMinutes(rnd.Next(5, 25));
currIdx++;
maxSim--;
}
return currListEv;
}
/// <summary>
/// Legge i dati dei record completi
/// </summary>
private async Task ReloadData()
{
if (ListEventi.Count == 0)
var rawData = await DLService.PlannerGetEvents(PeriodoSel.Inizio, PeriodoSel.Fine);
if (rawData != null && rawData.Count > 0)
{
ListEventi = new List<EventDto>();
//ListEventi.Clear();
await DoSimData();
ListEventi.Clear();
// x ora copio i vari blocchi...
foreach (var item in rawData)
{
ListEventi.AddRange(item.Value);
}
}
}
@@ -132,21 +57,6 @@ namespace Lux.UI.Components.Pages
{
PeriodoSel = newPeriod;
await ReloadData();
UpdateTable();
}
/// <summary>
/// Filtro e paginazione
/// </summary>
private void UpdateTable()
{
#if false
// fix paginazione
ListRecords = ListFilt
.Skip(numRecord * (currPage - 1))
.Take(numRecord)
.ToList();
#endif
}
#endregion Private Methods
+1 -1
View File
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-Lux.UI-a758c101-a2f4-4e38-977d-1c4887dbbd50</UserSecretsId>
<Version>0.9.2601.1419</Version>
<Version>0.9.2601.1509</Version>
</PropertyGroup>
<ItemGroup>
+1 -1
View File
@@ -1,6 +1,6 @@
<body>
<i>LUX - Web Windows MES</i>
<h4>Versione: 0.9.2601.1419</h4>
<h4>Versione: 0.9.2601.1509</h4>
<br /> Note di rilascio:
<ul>
<li>
+1 -1
View File
@@ -1 +1 @@
0.9.2601.1419
0.9.2601.1509
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<item>
<version>0.9.2601.1419</version>
<version>0.9.2601.1509</version>
<url>http://nexus.steamware.net/repository/SWS/GPW/stable/GPW.UI.zip</url>
<changelog>http://nexus.steamware.net/repository/SWS/GPW/stable/ChangeLog.html</changelog>
<mandatory>false</mandatory>