Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52a52b3993 | |||
| 6f243eb188 | |||
| 28a7c403d9 | |||
| f4f2b7c857 | |||
| 3d6e818b8d | |||
| ec48ab08b0 | |||
| d5a2406704 | |||
| 2044515ce4 | |||
| 3000a43330 | |||
| 61fafe9236 | |||
| 3879bcc6f3 | |||
| b678109ec0 | |||
| 67a3f582bf | |||
| 0d08c57112 | |||
| a62d1688b1 | |||
| d3ef9ce45f | |||
| 46f3146d85 | |||
| 22c9e1186c | |||
| e60dc2e172 | |||
| 14bcf025e0 | |||
| 0713f3d52d | |||
| 10ce6709dc | |||
| b415cb6b53 | |||
| 1ccfd55a1c | |||
| bcea43806b | |||
| e1de4d2bde | |||
| 5f7ce2ee5c | |||
| 1b1855c8f4 | |||
| 0aafcc6770 | |||
| f947f98e39 | |||
| 3ba140305e | |||
| dcae718f75 | |||
| 921cbed53b | |||
| dc43f4fe18 | |||
| 76f7c0d05c | |||
| 4adda8deaf | |||
| 236858e4dd | |||
| 2367b25c3c | |||
| 840b27e452 | |||
| 09cb7fd30c | |||
| c53452bf98 | |||
| fd99bf78dd | |||
| 9c0aa41620 | |||
| 01647b74b4 | |||
| 573c967670 | |||
| 0c2b819fb3 | |||
| 1e0d2746c6 | |||
| 60ed02f452 | |||
| 0cbea6a055 | |||
| 0302aee0e8 | |||
| ba96677c80 | |||
| fe42629e0e | |||
| e2627ffb8d | |||
| 955ee08a45 | |||
| c0c3bd65e9 | |||
| c5a0d1595b | |||
| d53a89b95e | |||
| 212b6abfef | |||
| ed249951e2 | |||
| 9601eaffcd | |||
| d8db7a8075 | |||
| 7928ff14e2 | |||
| a13bea1813 | |||
| ebd5af2d77 | |||
| 4fd374a4c3 | |||
| a59bb18c0e | |||
| 3e2729f594 | |||
| 4f33831180 | |||
| 23f334d233 | |||
| c21532256d | |||
| 0d4fb29b5b | |||
| 10a1356a6e | |||
| bf27ae8e19 | |||
| 041eae2260 | |||
| c3f011ec75 | |||
| 9d05a9f068 | |||
| 5b459bbd7b | |||
| 05ef3a3a4f | |||
| f1b5c99463 | |||
| 2f7337348e | |||
| 7f88624935 | |||
| dacd3b9bcd | |||
| 596449f259 | |||
| e149445529 | |||
| 178d7a3ef0 | |||
| 53d505006a | |||
| 53e1abd2c0 | |||
| 321b7a3a6f | |||
| 2e54c8b164 | |||
| 8c978f68c2 | |||
| 781c570a3d | |||
| de2a8cb6a5 | |||
| 63e92f0c83 | |||
| 73a28e33b4 | |||
| f4d2265de2 | |||
| b40764c2bc | |||
| 0333154935 | |||
| fc19fb563e | |||
| fd6a0512ba | |||
| 7c4ae1f7dc | |||
| b9c2418532 | |||
| 50a6848f25 | |||
| 6e1b60cc71 | |||
| 23a3985251 | |||
| 274d58ab68 | |||
| 14637860e0 | |||
| fe0545084a | |||
| e37b5050e2 | |||
| fc3a6a70da | |||
| 9837f276d7 | |||
| 865aa0afab | |||
| ef2bd7c5d5 | |||
| 3c92333f0e | |||
| 190b7a10b7 | |||
| 7a89709a29 | |||
| 3777090416 | |||
| 16d13748c9 | |||
| 5a46df0f19 | |||
| d3ff540382 | |||
| 15fcbd57b9 | |||
| 07ac5aa9a5 | |||
| 488ca47e50 |
@@ -182,8 +182,6 @@ CORE.Api:deploy:
|
||||
- dotnet restore "$env:SOL_NAME.sln"
|
||||
script:
|
||||
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
|
||||
# # IIS 02
|
||||
# - dotnet publish -p:PublishProfile=IIS02.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
|
||||
# IIS PROD
|
||||
- dotnet publish -p:PublishProfile=IIS-PROD.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
|
||||
|
||||
@@ -202,8 +200,6 @@ CORE.WLOG:deploy:
|
||||
- dotnet restore "$env:SOL_NAME.sln"
|
||||
script:
|
||||
- dotnet build $env:APP_NAME/$env:APP_NAME.csproj
|
||||
# # IIS 02
|
||||
# - dotnet publish -p:PublishProfile=IIS02.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
|
||||
# IIS PROD
|
||||
- dotnet publish -p:PublishProfile=IIS-PROD.pubxml -p:RunCodeAnalysis=false -p:Configuration=Release -p:username=jenkins -p:Password=$IIS_PWD -p:AllowUntrustedCertificate=true -p:verbosity=quiet $env:APP_NAME/$env:APP_NAME.csproj
|
||||
|
||||
|
||||
@@ -10,16 +10,6 @@ namespace GPW.CORE.Api.Controllers
|
||||
[ApiController]
|
||||
public class ProjCheckController : ControllerBase
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
private IConfiguration _configuration;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -39,90 +29,6 @@ namespace GPW.CORE.Api.Controllers
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Protected Enums
|
||||
|
||||
protected enum logType
|
||||
{
|
||||
none,
|
||||
local,
|
||||
trace,
|
||||
info,
|
||||
warn
|
||||
}
|
||||
|
||||
#endregion Protected Enums
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Dataservice x accesso DB
|
||||
/// </summary>
|
||||
protected ApiDataService dataService { get; set; }
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua log del tipo richiesto aggiungendo riga anche allo stringbuilder indicato
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="tipoLog"></param>
|
||||
/// <param name="currSB"></param>
|
||||
protected void doLog(string message, logType tipoLog, ref StringBuilder currSB)
|
||||
{
|
||||
bool doLine = true;
|
||||
switch (tipoLog)
|
||||
{
|
||||
case logType.info:
|
||||
Log.Info(message);
|
||||
break;
|
||||
|
||||
case logType.trace:
|
||||
Log.Trace(message);
|
||||
break;
|
||||
|
||||
case logType.warn:
|
||||
Log.Warn(message);
|
||||
break;
|
||||
|
||||
case logType.local:
|
||||
break;
|
||||
|
||||
default:
|
||||
case logType.none:
|
||||
doLine = false;
|
||||
break;
|
||||
}
|
||||
if (doLine)
|
||||
{
|
||||
currSB.AppendLine(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
currSB.Append(message);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task sendEmail(string subject, string message)
|
||||
{
|
||||
string emailRaw = _configuration["MailDest:ProjCheck"] ?? "";
|
||||
List<string> emailDestList = emailRaw.Split(",").ToList();
|
||||
foreach (var dest in emailDestList)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _emailSender.SendEmailAsync(dest, subject, message);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante invio email:{Environment.NewLine}dest: {dest} | subject {subject}{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Public Methods
|
||||
|
||||
[HttpGet("ResAlloc")]
|
||||
@@ -136,7 +42,7 @@ namespace GPW.CORE.Api.Controllers
|
||||
int numFix = 0;
|
||||
int numProj = 0;
|
||||
int numFasi = 0;
|
||||
string enableChiudiRaw = _configuration["EnableChiudiFasi"]??"false";
|
||||
string enableChiudiRaw = _configuration["EnableChiudiFasi"] ?? "false";
|
||||
bool enableChiudi = false;
|
||||
if (!string.IsNullOrEmpty(enableChiudiRaw))
|
||||
{
|
||||
@@ -228,11 +134,106 @@ namespace GPW.CORE.Api.Controllers
|
||||
// invio email
|
||||
await sendEmail(msgTopic, msgBody.Replace($"{Environment.NewLine}", "<br/>"));
|
||||
|
||||
// ritorno solo LOG azioni
|
||||
// ritorno solo LOG azioni
|
||||
answ = numFix == 0 ? $"ALL {numProj} Proj OK" : $"Proj: {numProj} | Fasi: {numFasi} | Fixed/Closed: {numFix}";
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Enums
|
||||
|
||||
protected enum logType
|
||||
{
|
||||
none,
|
||||
local,
|
||||
trace,
|
||||
info,
|
||||
warn
|
||||
}
|
||||
|
||||
#endregion Protected Enums
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Dataservice x accesso DB
|
||||
/// </summary>
|
||||
protected ApiDataService dataService { get; set; }
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua log del tipo richiesto aggiungendo riga anche allo stringbuilder indicato
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="tipoLog"></param>
|
||||
/// <param name="currSB"></param>
|
||||
protected void doLog(string message, logType tipoLog, ref StringBuilder currSB)
|
||||
{
|
||||
bool doLine = true;
|
||||
switch (tipoLog)
|
||||
{
|
||||
case logType.info:
|
||||
Log.Info(message);
|
||||
break;
|
||||
|
||||
case logType.trace:
|
||||
Log.Trace(message);
|
||||
break;
|
||||
|
||||
case logType.warn:
|
||||
Log.Warn(message);
|
||||
break;
|
||||
|
||||
case logType.local:
|
||||
break;
|
||||
|
||||
default:
|
||||
case logType.none:
|
||||
doLine = false;
|
||||
break;
|
||||
}
|
||||
if (doLine)
|
||||
{
|
||||
currSB.AppendLine(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
currSB.Append(message);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task sendEmail(string subject, string message)
|
||||
{
|
||||
string emailRaw = _configuration["MailDest:ProjCheck"] ?? "";
|
||||
List<string> emailDestList = emailRaw.Split(",").ToList();
|
||||
foreach (var dest in emailDestList)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _emailSender.SendEmailAsync(dest, subject, message);
|
||||
Log.Info($"Email inviata | dest: {dest} | subject: {subject}");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Eccezione durante invio email:{Environment.NewLine}dest: {dest} | subject: {subject}{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static NLog.Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly IEmailSender _emailSender;
|
||||
|
||||
private IConfiguration _configuration;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ namespace GPW.CORE.Api.Data
|
||||
/// <param name="emailSender"></param>
|
||||
/// <param name="redisCacheClient"></param>
|
||||
public ApiDataService(IConfiguration configuration, ILogger<ApiDataService> logger, IEmailSender emailSender, IConnectionMultiplexer redisConn)
|
||||
//public ApiDataService(IConfiguration configuration, ILogger<ApiDataService> logger, IEmailSender emailSender, IRedisCacheClient redisCacheClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.27" />
|
||||
<PackageReference Include="StackExchange.Redis.Extensions.AspNetCore" Version="9.1.0" />
|
||||
<PackageReference Include="StackExchange.Redis.Extensions.Core" Version="9.1.0" />
|
||||
<PackageReference Include="StackExchange.Redis.Extensions.Newtonsoft" Version="9.1.0" />
|
||||
|
||||
@@ -29,19 +29,12 @@ builder.Services.AddSwaggerGen();
|
||||
// abilitazione x email management con MailKit
|
||||
//builder.Services.AddTransient<IEmailSender, MailKitEmailSender>();
|
||||
builder.Services.AddSingleton<IEmailSender, MailKitEmailSender>();
|
||||
// recupero email reversed
|
||||
string revPwd = configuration["ExternalProviders:MailKit:SMTP:Password"] ?? "";
|
||||
string pwd = "";
|
||||
foreach (char c in revPwd)
|
||||
{
|
||||
pwd = c + pwd;
|
||||
}
|
||||
builder.Services.Configure<MailKitEmailSenderOptions>(options =>
|
||||
{
|
||||
options.Host_Address = configuration["ExternalProviders:MailKit:SMTP:Address"] ?? "";
|
||||
options.Host_Port = Convert.ToInt32(configuration["ExternalProviders:MailKit:SMTP:Port"] ?? "");
|
||||
options.Host_Username = configuration["ExternalProviders:MailKit:SMTP:Account"] ?? "";
|
||||
options.Host_Password = pwd;
|
||||
options.Host_Password = configuration["ExternalProviders:MailKit:SMTP:Password"] ?? "";
|
||||
options.Sender_EMail = configuration["ExternalProviders:MailKit:SMTP:SenderEmail"] ?? "";
|
||||
options.Sender_Name = configuration["ExternalProviders:MailKit:SMTP:SenderName"] ?? "";
|
||||
});
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"GPW.DB": "Server=W2019-SQL-STEAM;Database=GPW;User ID=sa;Password=keyhammer16;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;",
|
||||
"Redis": "localhost:6379,DefaultDatabase=15,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000"
|
||||
"GPW.DB": "Server=W2019-SQL-STEAM;Database=GPW;User ID=UserGPW; Password=Us3rGpw!75x93$77;integrated security=False;MultipleActiveResultSets=True;App=LiMan.API;",
|
||||
"Redis": "localhost:26379,serviceName=prod,DefaultDatabase=15,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,password=BtN9Py1wtLfLRvmzWnOPJ7RytDM+CLiVsJ/16zduNTlV8IOPGNrtzJSXPUnImA5PqmUMhKaUqo9NdHIG"
|
||||
},
|
||||
"ExternalProviders": {
|
||||
"MailKit": {
|
||||
@@ -16,7 +16,7 @@
|
||||
"Address": "smtp-mail.outlook.com",
|
||||
"Port": "587",
|
||||
"Account": "steamwarebot@outlook.it",
|
||||
"Password": "!39elanoizaNaiVnIomais",
|
||||
"Password": "siamoInViaNazionale93!",
|
||||
"SenderEmail": "steamwarebot@outlook.it",
|
||||
"SenderName": "Steamware Email BOT"
|
||||
}
|
||||
@@ -29,17 +29,30 @@
|
||||
},
|
||||
"EnableChiudiFasi": "false",
|
||||
"Redis": {
|
||||
"Password": "",
|
||||
"Password": "BtN9Py1wtLfLRvmzWnOPJ7RytDM+CLiVsJ/16zduNTlV8IOPGNrtzJSXPUnImA5PqmUMhKaUqo9NdHIG",
|
||||
"AllowAdmin": false,
|
||||
"Ssl": false,
|
||||
"ConnectTimeout": 6000,
|
||||
"SyncTimeout": 6000,
|
||||
"AsyncTimeout": 6000,
|
||||
"ConnectRetry": 2,
|
||||
"ServiceName": "prod",
|
||||
"Hosts": [
|
||||
{
|
||||
"Host": "localhost",
|
||||
"Port": "6379"
|
||||
"Port": "26379"
|
||||
},
|
||||
{
|
||||
"Host": "redis01.ufficio",
|
||||
"Port": "26379"
|
||||
},
|
||||
{
|
||||
"Host": "redis03.ufficio",
|
||||
"Port": "26379"
|
||||
},
|
||||
{
|
||||
"Host": "redis03.ufficio",
|
||||
"Port": "26379"
|
||||
}
|
||||
],
|
||||
"Database": 15
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GPW.CORE.Data
|
||||
{
|
||||
public class Const
|
||||
{
|
||||
#region Public Fields
|
||||
|
||||
public const string rPipeChRich = $"Channel_Rich";
|
||||
public const string rPipeChTimb = $"Channel_Timb";
|
||||
|
||||
#endregion Public Fields
|
||||
}
|
||||
}
|
||||
@@ -366,6 +366,35 @@ namespace GPW.CORE.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tabella setup dati orari - elenco completo
|
||||
/// </summary>
|
||||
/// <param name="idxProj"></param>
|
||||
/// <returns></returns>
|
||||
public List<AnagOrariModel> AnagOrarioGetAll()
|
||||
{
|
||||
List<AnagOrariModel> dbResult = new List<AnagOrariModel>();
|
||||
using (GPWContext localDbCtx = new GPWContext(_configuration))
|
||||
{
|
||||
try
|
||||
{
|
||||
// recupero intero set....
|
||||
dbResult = localDbCtx
|
||||
.DbSetAnagOrari
|
||||
.ToList();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Log.Error($"Errore in AnagOrarioGetAll:{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
if (dbResult == null)
|
||||
{
|
||||
dbResult = new List<AnagOrariModel>();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
public List<AnagProgettiModel> AnagProjAll(bool onlyActive)
|
||||
{
|
||||
// init dati necessari
|
||||
@@ -501,6 +530,31 @@ namespace GPW.CORE.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco delle ultime attività inserite da un dipendente
|
||||
/// </summary>
|
||||
/// <param name="idxDipendente">Dipendente interessato</param>
|
||||
/// <param name="numRec">Num record da recuperare</param>
|
||||
/// <returns></returns>
|
||||
public List<RegAttivitaModel> UserLastRec(int idxDipendente, int numRec)
|
||||
{
|
||||
List<RegAttivitaModel> listRec = new List<RegAttivitaModel>();
|
||||
// cerco su DB recuperando set di dati....
|
||||
using (GPWContext localDbCtx = new GPWContext(_configuration))
|
||||
{
|
||||
listRec = localDbCtx
|
||||
.DbSetRegAttivita
|
||||
.Where(x => x.IdxDipendente == idxDipendente)
|
||||
.Include(a => a.FasiNav).ThenInclude(p => p.ProgettoNav).ThenInclude(c => c.ClienteNav)
|
||||
.OrderByDescending(x => x.IdxRa)
|
||||
.Take(numRec)
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
}
|
||||
return listRec;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco dei dettagli giornalieri attività di un dipendente, dato periodo riferimento
|
||||
/// </summary>
|
||||
@@ -615,6 +669,117 @@ namespace GPW.CORE.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco dei dettaglio giornaliero attività di tutti i dipendenti, dato giorno riferimento
|
||||
/// </summary>
|
||||
/// <param name="dtRif">Data di riferimento</param>
|
||||
/// <returns></returns>
|
||||
public List<DailyDataDTO> DailyDetailAllDip(DateTime dtRif)
|
||||
{
|
||||
//resetto valoredtRif a giornata (mezzanotte)
|
||||
dtRif = dtRif.Date;
|
||||
// init dati necessari
|
||||
List<DailyDataDTO> dbResult = new List<DailyDataDTO>();
|
||||
List<TimbratureExplModel> rawTimbExp = new List<TimbratureExplModel>();
|
||||
List<TimbratureModel> rawTimbr = new List<TimbratureModel>();
|
||||
List<RegAttivitaModel> rawRegAtt = new List<RegAttivitaModel>();
|
||||
List<RilievoTempModel> rawRilTemp = new List<RilievoTempModel>();
|
||||
List<CheckVc19Model> rawCheckC19 = new List<CheckVc19Model>();
|
||||
|
||||
// fermate/festività/ferie
|
||||
List<CalFesteFerieModel> rawFermateAz = new List<CalFesteFerieModel>();
|
||||
List<RegMalattieModel> rawMalattie = new List<RegMalattieModel>();
|
||||
List<RegRichiesteModel> rawRichDip = new List<RegRichiesteModel>();
|
||||
|
||||
// cerco su DB recuperando set di dati....
|
||||
using (GPWContext localDbCtx = new GPWContext(_configuration))
|
||||
{
|
||||
// recupero intero set dati timbrature e attività....
|
||||
rawTimbExp = localDbCtx
|
||||
.DbSetTimbratureExpl
|
||||
.Where(x => dtRif == x.DataLav)
|
||||
.ToList();
|
||||
|
||||
rawTimbr = localDbCtx
|
||||
.DbSetTimbrature
|
||||
.Where(x => dtRif == x.DataOra.Date)
|
||||
.ToList();
|
||||
|
||||
rawRegAtt = localDbCtx
|
||||
.DbSetRegAttivita
|
||||
.Where(x => dtRif == x.Inizio.Date)
|
||||
.Include(a => a.FasiNav).ThenInclude(p => p.ProgettoNav).ThenInclude(c => c.ClienteNav)
|
||||
.ToList();
|
||||
|
||||
rawRilTemp = localDbCtx
|
||||
.DbSetRilievoTemp
|
||||
.Where(x => dtRif <= x.DtRilievo.Date)
|
||||
.ToList();
|
||||
|
||||
rawCheckC19 = localDbCtx
|
||||
.DbSetCheckVc19
|
||||
.Where(x => dtRif <= x.DtCheck.Date)
|
||||
.ToList();
|
||||
|
||||
// recupero fermate e malattie/permessi del dipendente...
|
||||
rawFermateAz = localDbCtx
|
||||
.DbSetCalFesteFerie
|
||||
.Where(x => x.data == dtRif)
|
||||
.ToList();
|
||||
rawMalattie = localDbCtx
|
||||
.DbSetRegMalattie
|
||||
.Where(x => x.DtInizio.Date <= dtRif && x.DtInizio.AddDays(x.NumGG) >= dtRif)
|
||||
.ToList();
|
||||
rawRichDip = localDbCtx
|
||||
.DbSetRegRichieste
|
||||
.Where(x => x.DtStart.Date <= dtRif && x.DtEnd >= dtRif)
|
||||
.ToList();
|
||||
|
||||
// calcolo elenco DIP
|
||||
List<int> listDip = rawTimbExp.Select(x => x.IdxDipendente).Distinct().ToList();
|
||||
|
||||
// x ogni giorno scompongo il set di info...
|
||||
foreach (var idxDip in listDip)
|
||||
{
|
||||
DailyDataDTO currDayDto = new DailyDataDTO()
|
||||
{
|
||||
IdxDipendente = idxDip,
|
||||
DtRif = dtRif,
|
||||
ListRA = rawRegAtt
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.OrderBy(x => x.Inizio)
|
||||
.ToList(),
|
||||
ListTimbr = rawTimbr
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.OrderBy(x => x.DataOra)
|
||||
.ToList(),
|
||||
TimbrExpl = rawTimbExp
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.FirstOrDefault(),
|
||||
ListRilTemp = rawRilTemp
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.ToList(),
|
||||
ListCheckC19 = rawCheckC19
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.ToList(),
|
||||
ListFermateAzienda = rawFermateAz,
|
||||
ListMalattie = rawMalattie
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.ToList(),
|
||||
ListFerieDip = rawRichDip
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.ToList(),
|
||||
ListRichiesteDip = rawRichDip
|
||||
.Where(x => x.IdxDipendente == idxDip)
|
||||
.ToList()
|
||||
};
|
||||
|
||||
dbResult.Add(currDayDto);
|
||||
}
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
public bool DbForceMigrate()
|
||||
{
|
||||
bool answ = false;
|
||||
@@ -984,6 +1149,26 @@ namespace GPW.CORE.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Righe presenze giornaliere
|
||||
/// </summary>
|
||||
/// <param name="dtRif">DataOra riferimento per richiesta presenze</param>
|
||||
/// <returns></returns>
|
||||
public List<StatsDayPresModel> PresenzeDay(DateTime dtRif)
|
||||
{
|
||||
List<StatsDayPresModel> dbResult = new List<StatsDayPresModel>();
|
||||
using (GPWContext localDbCtx = new GPWContext(_configuration))
|
||||
{
|
||||
var idxProgetto = new SqlParameter("@dataRif", dtRif);
|
||||
|
||||
dbResult = localDbCtx
|
||||
.DbSetStatsDayPres
|
||||
.FromSqlRaw("EXEC stp_statsDayPres @dataRif", idxProgetto)
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
public bool RegAttDelete(RegAttivitaModel currItem)
|
||||
{
|
||||
bool answ = false;
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace GPW.CORE.Data.DbModels
|
||||
public DateTime? DataCessazione { get; set; }
|
||||
public bool? Attivo { get; set; }
|
||||
public string Sigla { get; set; } = "";
|
||||
public int idxResp { get; set; } = 0;
|
||||
|
||||
public virtual ICollection<RegAttivitaModel> RegAttivitaNav { get; set; }
|
||||
public virtual ICollection<RilievoTempModel> RilievoTempNav { get; set; }
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace GPW.CORE.Data.DbModels
|
||||
{
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
public partial class StatsDayPresModel
|
||||
{
|
||||
[Key]
|
||||
public int IdxDipendente { get; set; }
|
||||
public DateTime LastOp { get; set; }
|
||||
public int NEnt { get; set; } = 0;
|
||||
public int NUsc { get; set; } = 0;
|
||||
public int IsPresent { get; set; } = 0;
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Navigation property to Dipendente
|
||||
/// </summary>
|
||||
[ForeignKey("IdxDipendente")]
|
||||
public virtual DipendentiModel DipNav { get; set; } = null!;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="MailKit" Version="3.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.14">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.2.2" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.27" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.4.2307.3111" />
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="MailKit" Version="3.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.14" />
|
||||
@@ -19,6 +19,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.2.2" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.27" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace GPW.CORE.Data
|
||||
public virtual DbSet<RegistroEventiModel> DbSetRegEventi { get; set; } = null!;
|
||||
public virtual DbSet<DipendendiAndAnomalie> DbSetDipAndAnom { get; set; } = null!;
|
||||
public virtual DbSet<TeRaExplModel> DbSetTeRaExpl { get; set; } = null!;
|
||||
public virtual DbSet<StatsDayPresModel> DbSetStatsDayPres { get; set; } = null!;
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
|
||||
@@ -30,8 +30,9 @@ namespace GPW.CORE.Data
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public Task Execute(string to, string subject, string message)
|
||||
public async Task<bool> Execute(string to, string subject, string message)
|
||||
{
|
||||
bool fatto = false;
|
||||
// create message
|
||||
var email = new MimeMessage();
|
||||
email.Sender = MailboxAddress.Parse(Options.Sender_EMail);
|
||||
@@ -47,11 +48,12 @@ namespace GPW.CORE.Data
|
||||
{
|
||||
smtp.Connect(Options.Host_Address, Options.Host_Port, Options.Host_SecureSocketOptions);
|
||||
smtp.Authenticate(Options.Host_Username, Options.Host_Password);
|
||||
smtp.Send(email);
|
||||
await smtp.SendAsync(email);
|
||||
smtp.Disconnect(true);
|
||||
fatto = true;
|
||||
}
|
||||
|
||||
return Task.FromResult(true);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
public Task SendEmailAsync(string email, string subject, string message)
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GPW.CORE.Data
|
||||
{
|
||||
public class MessagePipe
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public MessagePipe(IConnectionMultiplexer redisConn, string channelName, bool enableLog = false)
|
||||
{
|
||||
_channel = channelName;
|
||||
redis = redisConn;
|
||||
redisDb = redis.GetDatabase();
|
||||
this.enableLog = enableLog;
|
||||
// aggiungo sottoscrittore
|
||||
setupSubscriber();
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Events
|
||||
|
||||
public event EventHandler EA_NewMessage = delegate { };
|
||||
|
||||
#endregion Public Events
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Invio messaggio sul canale + salvataggio in cache REDIS
|
||||
/// </summary>
|
||||
/// <param name="memKey">Chiave REDIS x salvare valore</param>
|
||||
/// <param name="message">Messaggio serializzato da inviare</param>
|
||||
public bool saveAndSendMessage(string memKey, string message)
|
||||
{
|
||||
bool answ = false;
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
|
||||
// invio notifica tramite il canale richiesto
|
||||
answ = sendMessage(message);
|
||||
if (redisDb != null)
|
||||
{
|
||||
redisDb.StringSetAsync(memKey, message);
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
if (numSent.ContainsKey(memKey))
|
||||
{
|
||||
numSent[memKey]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
numSent.Add(memKey, 1);
|
||||
}
|
||||
if (enableLog || numSent[memKey] > 30)
|
||||
{
|
||||
Log.Info($"saveAndSendMessage| mKey {memKey} x {numSent[memKey]} | {message.Length} size | {ts.TotalMilliseconds} ms");
|
||||
|
||||
numSent[memKey] = 0;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invio messaggio sul canale
|
||||
/// </summary>
|
||||
/// <param name="newMess"></param>
|
||||
/// <returns></returns>
|
||||
public bool sendMessage(string newMess)
|
||||
{
|
||||
bool answ = false;
|
||||
ISubscriber sub = redis.GetSubscriber();
|
||||
sub.Publish(_channel, newMess);
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private bool enableLog = false;
|
||||
private Dictionary<string, int> numSent = new Dictionary<string, int>();
|
||||
private IConnectionMultiplexer redis;
|
||||
private StackExchange.Redis.IDatabase redisDb;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
/// <summary>
|
||||
/// Canale associato al gestore pipeline messaggi
|
||||
/// </summary>
|
||||
private string _channel { get; set; } = "";
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void setupSubscriber()
|
||||
{
|
||||
ISubscriber sub = redis.GetSubscriber();
|
||||
//Subscribe to the channel named messages
|
||||
sub.Subscribe(_channel, (channel, message) =>
|
||||
{
|
||||
if (enableLog)
|
||||
{
|
||||
Log.Trace($"req setup ch {channel} | {message}");
|
||||
}
|
||||
// messaggio
|
||||
PubSubEventArgs mea = new PubSubEventArgs(message);
|
||||
// se qualcuno ascolta sollevo evento nuovo valore...
|
||||
if (EA_NewMessage != null)
|
||||
{
|
||||
EA_NewMessage(this, mea);
|
||||
}
|
||||
});
|
||||
if (enableLog)
|
||||
{
|
||||
Log.Info($"Subscribed {_channel}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
|
||||
public class PubSubEventArgs : EventArgs
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public PubSubEventArgs(string messaggio)
|
||||
{
|
||||
this.newMessage = messaggio;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
public string newMessage { get; set; } = "";
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" aria-label="@CompName" style="width: @CurrPerc;" aria-valuenow="@CurrVal" aria-valuemin="@ValMin" aria-valuemax="@ValMax">@CurrPerc</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public double ValMin { get; set; } = 0;
|
||||
[Parameter]
|
||||
public double ValMax { get; set; } = 100;
|
||||
[Parameter]
|
||||
public double ValCur { get; set; } = 0;
|
||||
[Parameter]
|
||||
public string CompName { get; set; } = "";
|
||||
|
||||
protected string CurrPerc
|
||||
{
|
||||
get => ValMax == 0 ? "0%" : $"{ValCur / ValMax:P0}";
|
||||
}
|
||||
protected int CurrVal
|
||||
{
|
||||
get => ValMax == 0 ? 0 : (int)(ValCur * 100 / ValMax);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<NoDefaultLaunchSettingsFile>true</NoDefaultLaunchSettingsFile>
|
||||
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
|
||||
<!--
|
||||
<GenerateRuntimeConfigDevFile>true</GenerateRuntimeConfigDevFile>
|
||||
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
|
||||
-->
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,63 @@
|
||||
@page "/clock-display"
|
||||
@using GPW.CORE.HYB.Client.Components
|
||||
@using GPW.CORE.HYB.Client.Services
|
||||
@implements IDisposable
|
||||
@rendermode InteractiveWebAssembly
|
||||
@inject PersistentComponentState ApplicationState
|
||||
@inject ClockService CServ
|
||||
|
||||
<h1>Hello, @handler!</h1>
|
||||
|
||||
<h3>Clock test</h3>
|
||||
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">Realtime: @($"{adesso:HH:mm:ss}")</li>
|
||||
<li class="list-group-item">Last Sync: @($"{lastSync:HH:mm:ss}")</li>
|
||||
<li class="list-group-item">Delta: @($"{deltaTs.TotalMilliseconds} ms")</li>
|
||||
<li class="list-group-item">Click: @($"{adesso:HH:mm:ss}")</li>
|
||||
</ul>
|
||||
|
||||
<p>@adesso</p>
|
||||
|
||||
@code {
|
||||
protected string handler = "";
|
||||
private DateTime adesso
|
||||
{
|
||||
get => DateTime.Now;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private DateTime lastSync { get; set; } = DateTime.Today;
|
||||
private DateTime clockDT { get; set; } = DateTime.Today;
|
||||
private TimeSpan deltaTs { get; set; } = new TimeSpan();
|
||||
protected override async void OnInitialized()
|
||||
{
|
||||
// persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount);
|
||||
// if (!ApplicationState.TryTakeFromJson<int>(nameof(currentCount), out var restoredCount))
|
||||
// {
|
||||
// currentCount = Random.Shared.Next(50);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// currentCount = restoredCount!;
|
||||
// }
|
||||
|
||||
|
||||
if (OperatingSystem.IsBrowser())
|
||||
{
|
||||
handler = "WASM";
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = "Server";
|
||||
}
|
||||
|
||||
lastSync = DateTime.Now;
|
||||
clockDT = await CServ.GetSrvClockAsync();
|
||||
deltaTs = clockDT.Subtract(DateTime.Now);
|
||||
}
|
||||
|
||||
private PersistingComponentStateSubscription persistingSubscription;
|
||||
void IDisposable.Dispose() => persistingSubscription.Dispose();
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
@page "/counter"
|
||||
@using GPW.CORE.HYB.Client.Components
|
||||
@implements IDisposable
|
||||
@rendermode InteractiveAuto
|
||||
@inject PersistentComponentState ApplicationState
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<h1>Hello, @handler!</h1>
|
||||
<ProgressBar ValMin="0" ValMax="100" ValCur="@currVal"></ProgressBar>
|
||||
<br />
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">Init: @($"{lastInit:HH:mm:ss}")</li>
|
||||
<li class="list-group-item">Render: @($"{lastRender:HH:mm:ss}")</li>
|
||||
<li class="list-group-item">ParamSet: @($"{lastParSet:HH:mm:ss}")</li>
|
||||
<li class="list-group-item">Click: @($"{adesso:HH:mm:ss}")</li>
|
||||
</ul>
|
||||
<br />
|
||||
@lastInit
|
||||
<hr />
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
<hr />
|
||||
|
||||
<p>@adesso</p>
|
||||
|
||||
@code {
|
||||
private int currentCount = 0;
|
||||
|
||||
private PersistingComponentStateSubscription persistingSubscription;
|
||||
|
||||
private double currVal = 0;
|
||||
|
||||
private async Task IncrementCount()
|
||||
{
|
||||
currentCount++;
|
||||
await AdvProg();
|
||||
}
|
||||
|
||||
private DateTime adesso
|
||||
{
|
||||
get => DateTime.Now;
|
||||
}
|
||||
private Task PersistCount()
|
||||
{
|
||||
ApplicationState.PersistAsJson(nameof(currentCount), currentCount);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() => persistingSubscription.Dispose();
|
||||
|
||||
protected string handler = "";
|
||||
protected DateTime lastInit = DateTime.Today;
|
||||
protected DateTime lastRender = DateTime.Today;
|
||||
protected DateTime lastParSet = DateTime.Today;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistCount);
|
||||
if (!ApplicationState.TryTakeFromJson<int>(nameof(currentCount), out var restoredCount))
|
||||
{
|
||||
currentCount = Random.Shared.Next(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCount = restoredCount!;
|
||||
}
|
||||
|
||||
|
||||
if (OperatingSystem.IsBrowser())
|
||||
{
|
||||
handler = "WASM";
|
||||
}
|
||||
else
|
||||
{
|
||||
handler = "Server";
|
||||
}
|
||||
lastInit = DateTime.Now;
|
||||
}
|
||||
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
lastRender = DateTime.Now;
|
||||
}
|
||||
|
||||
protected async Task AdvProg()
|
||||
{
|
||||
currVal = 0;
|
||||
StateHasChanged();
|
||||
await Task.Delay(100);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(100);
|
||||
currVal += 10;
|
||||
StateHasChanged();
|
||||
}
|
||||
currVal = 100;
|
||||
}
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
lastParSet = DateTime.Now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using GPW.CORE.HYB.Client.Services;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
||||
builder.Services.AddScoped<ClockService>();
|
||||
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace GPW.CORE.HYB.Client.Services
|
||||
{
|
||||
|
||||
public class ClockService(HttpClient http) //: IMovieService
|
||||
{
|
||||
public async Task<DateTime> GetSrvClockAsync()
|
||||
{
|
||||
DateTime answ = DateTime.Today;
|
||||
var rawData= await http.GetFromJsonAsync<string>("Clock") ?? "";
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
DateTime.TryParse(rawData, out answ);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using GPW.CORE.HYB.Client
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.10.35122.118
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPW.CORE.HYB", "GPW.CORE.HYB\GPW.CORE.HYB.csproj", "{7C77D787-A7B1-4A3B-8753-34BF4A56983A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPW.CORE.HYB.Client", "GPW.CORE.HYB.Client\GPW.CORE.HYB.Client.csproj", "{1FC390C1-D9E5-43CE-923C-78F76A4E7EF8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7C77D787-A7B1-4A3B-8753-34BF4A56983A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C77D787-A7B1-4A3B-8753-34BF4A56983A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C77D787-A7B1-4A3B-8753-34BF4A56983A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C77D787-A7B1-4A3B-8753-34BF4A56983A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1FC390C1-D9E5-43CE-923C-78F76A4E7EF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FC390C1-D9E5-43CE-923C-78F76A4E7EF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FC390C1-D9E5-43CE-923C-78F76A4E7EF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FC390C1-D9E5-43CE-923C-78F76A4E7EF8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DFCC3D3A-2A22-41CE-8361-2DAC02CDB9F6}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="app.css" />
|
||||
<link rel="stylesheet" href="GPW.CORE.HYB.styles.css" />
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<HeadOutlet />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<Routes />
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,23 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu />
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<div class="top-row px-4">
|
||||
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
|
||||
</div>
|
||||
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
An unhandled error has occurred.
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
@@ -0,0 +1,96 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.top-row ::deep a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row ::deep .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row.auth ::deep a:first-child {
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
#blazor-error-ui {
|
||||
background: lightyellow;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
|
||||
display: none;
|
||||
left: 0;
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#blazor-error-ui .dismiss {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
top: 0.5rem;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="top-row ps-3 navbar navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="">GPW.CORE.HYB</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
|
||||
|
||||
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
|
||||
<nav class="flex-column">
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
|
||||
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="counter">
|
||||
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="clock-display">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Clock Test
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="weather">
|
||||
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
.navbar-toggler {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
width: 3.5rem;
|
||||
height: 2.5rem;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 1rem;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.navbar-toggler:checked {
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.bi {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
margin-right: 0.75rem;
|
||||
top: -1px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.bi-house-door-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-plus-square-fill-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.bi-list-nested-nav-menu {
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link {
|
||||
color: #d7d7d7;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.37);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep .nav-link:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-toggler:checked ~ .nav-scrollable {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
@page "/Error"
|
||||
@using System.Diagnostics
|
||||
|
||||
<PageTitle>Error</PageTitle>
|
||||
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (ShowRequestId)
|
||||
{
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
|
||||
@code{
|
||||
[CascadingParameter]
|
||||
private HttpContext? HttpContext { get; set; }
|
||||
|
||||
private string? RequestId { get; set; }
|
||||
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
protected override void OnInitialized() =>
|
||||
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Home</PageTitle>
|
||||
|
||||
<h1>Hello, world!</h1>
|
||||
|
||||
Welcome to your new app.
|
||||
@@ -0,0 +1,78 @@
|
||||
@page "/weather"
|
||||
@using GPW.CORE.HYB.Client.Components
|
||||
@attribute [StreamRendering]
|
||||
|
||||
<PageTitle>Weather</PageTitle>
|
||||
|
||||
<h1>Weather</h1>
|
||||
|
||||
<p>This component demonstrates showing data.</p>
|
||||
|
||||
<ProgressBar ValMin="0" ValMax="100" ValCur="@currVal"></ProgressBar>
|
||||
|
||||
@if (forecasts == null)
|
||||
{
|
||||
<p><em>Loading...</em></p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Temp. (C)</th>
|
||||
<th>Temp. (F)</th>
|
||||
<th>Summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var forecast in forecasts)
|
||||
{
|
||||
<tr>
|
||||
<td>@forecast.Date.ToShortDateString()</td>
|
||||
<td>@forecast.TemperatureC</td>
|
||||
<td>@forecast.TemperatureF</td>
|
||||
<td>@forecast.Summary</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
private WeatherForecast[]? forecasts;
|
||||
|
||||
private double currVal = 0;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
currVal = 0;
|
||||
await Task.Delay(100);
|
||||
StateHasChanged();
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
// Simulate asynchronous loading to demonstrate streaming rendering
|
||||
await Task.Delay(100);
|
||||
currVal += 10;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
var startDate = DateOnly.FromDateTime(DateTime.Now);
|
||||
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
|
||||
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
||||
{
|
||||
Date = startDate.AddDays(index),
|
||||
TemperatureC = Random.Shared.Next(-20, 55),
|
||||
Summary = summaries[Random.Shared.Next(summaries.Length)]
|
||||
}).ToArray();
|
||||
currVal = 100;
|
||||
}
|
||||
|
||||
private class WeatherForecast
|
||||
{
|
||||
public DateOnly Date { get; set; }
|
||||
public int TemperatureC { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)" />
|
||||
<FocusOnNavigate RouteData="routeData" Selector="h1" />
|
||||
</Found>
|
||||
</Router>
|
||||
@@ -0,0 +1,11 @@
|
||||
@using System.Net.Http
|
||||
@using System.Net.Http.Json
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using GPW.CORE.HYB
|
||||
@using GPW.CORE.HYB.Client
|
||||
@using GPW.CORE.HYB.Components
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GPW.CORE.HYB.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class ClockController : ControllerBase
|
||||
{
|
||||
//public ClockController() { }
|
||||
|
||||
/// <summary>
|
||||
/// Restituisce l'orario corrente del server
|
||||
/// GET api/Clock
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public IActionResult Get()
|
||||
{
|
||||
return Ok(DateTime.Now);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GPW.CORE.HYB.Client\GPW.CORE.HYB.Client.csproj" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,43 @@
|
||||
using GPW.CORE.HYB.Client.Pages;
|
||||
using GPW.CORE.HYB.Client.Services;
|
||||
using GPW.CORE.HYB.Components;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
|
||||
//builder.Services.AddSingleton<ClockService>();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents()
|
||||
.AddInteractiveWebAssemblyComponents();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseWebAssemblyDebugging();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error", createScopeForErrors: true);
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseAntiforgery();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode()
|
||||
.AddInteractiveWebAssemblyRenderMode()
|
||||
.AddAdditionalAssemblies(typeof(GPW.CORE.HYB.Client._Imports).Assembly);
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:28435",
|
||||
"sslPort": 44365
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "http://localhost:5075",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "https://localhost:7127;http://localhost:5075",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace GPW.CORE.HYB.Services
|
||||
{
|
||||
|
||||
public class ClockService() //: IMovieService
|
||||
{
|
||||
public async Task<DateTime> GetSrvClockAsync()
|
||||
{
|
||||
DateTime answ = DateTime.Now;
|
||||
await Task.Delay(1);
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
html, body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
a, .btn-link {
|
||||
color: #006bb7;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
|
||||
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: 1.1rem;
|
||||
}
|
||||
|
||||
h1:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.valid.modified:not([type=checkbox]) {
|
||||
outline: 1px solid #26b050;
|
||||
}
|
||||
|
||||
.invalid {
|
||||
outline: 1px solid #e50000;
|
||||
}
|
||||
|
||||
.validation-message {
|
||||
color: #e50000;
|
||||
}
|
||||
|
||||
.blazor-error-boundary {
|
||||
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
||||
padding: 1rem 1rem 1rem 3.7rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.blazor-error-boundary::after {
|
||||
content: "An error has occurred."
|
||||
}
|
||||
|
||||
.darker-border-checkbox.form-check-input {
|
||||
border-color: #929292;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -1,64 +1,75 @@
|
||||
<div class="accordion mb-5" id="accordionExample">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseZero" aria-expanded="false" aria-controls="collapseZero">
|
||||
<h2 class="accordion-header" id="heading01">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapse01" aria-expanded="false" aria-controls="collapse01">
|
||||
<b>Gestione Admin</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseZero" class="accordion-collapse collapse show" aria-labelledby="headingZero" data-bs-parent="#accordionExample">
|
||||
<div id="collapse01" class="accordion-collapse collapse show" aria-labelledby="heading01" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body small">
|
||||
Di seguito le procedure per resettare e reinviare via email l'authKey al dipendente, approvare le timbrature, mostrare il QRCode di login
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (!isAuthKeyAdmin && !isApprAdmin)
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading02">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse02" aria-expanded="false" aria-controls="collapse02">
|
||||
<b>Fix pagine offline</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse02" class="accordion-collapse collapse" aria-labelledby="heading02" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body small">
|
||||
Nel caso il browser stia presentando pagine offline/archiviate come valide, traendo in inganno sulle effettive timbrature, si deve procedere con la pulizia della cache delle pagine offline.
|
||||
<br />
|
||||
Per farlo si deve seguire la procedura manuale di seguito riportata:
|
||||
<ul>
|
||||
<li>Aprire una nuova pagina dal browser chrome sul device</li>
|
||||
<li>inserire l'indirizzo seguente:<br /><b>chrome://offline-internals/</b></li>
|
||||
<li>eliminare almeno le pagine di<br /> <b>office.egalware.com</b></li>
|
||||
</ul>
|
||||
Purtroppo non è possibile automatizzare questa procedura ne aprire direttamente il link con un pulsante o una procedura poiché questo è vietato per motivi di sicurezza interna dai browser.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (isAuthKeyAdmin)
|
||||
{
|
||||
<div class="accordion-item">
|
||||
<LoadingData DisplayMode="LoadingData.SpinMode.Growl"></LoadingData>
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
||||
<b>QRCode direct display</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<UserQrCode></UserQrCode>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<b>ADMIN Reset AuthKey via e-mail</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body p-1">
|
||||
<InvioLinkEmail IdxDipAdmin="@IdxDipendente"></InvioLinkEmail>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
@if (isApprAdmin)
|
||||
{
|
||||
@if (isAuthKeyAdmin)
|
||||
{
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
<b>QRCode direct display</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body">
|
||||
<UserQrCode></UserQrCode>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
<b>Approvazione Timbrature</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
|
||||
<TimbAdmin IdxDipAdmin="@IdxDipendente"></TimbAdmin>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
|
||||
<b>ADMIN Reset AuthKey via e-mail</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body p-1">
|
||||
<InvioLinkEmail IdxDipAdmin="@IdxDipendente"></InvioLinkEmail>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (isApprAdmin)
|
||||
{
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<b>Approvazione Timbrature</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#accordionExample">
|
||||
<TimbAdmin IdxDipAdmin="@IdxDipendente"></TimbAdmin>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace GPW.CORE.Smart.Components
|
||||
IdxDipendente = idxDip,
|
||||
Ipv4 = $"{ipv4}"
|
||||
};
|
||||
done= await CDService.TimbratureUpdate(currRecord);
|
||||
done = await CDService.TimbratureUpdate(currRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,22 @@
|
||||
|
||||
@if (ListRecords == null)
|
||||
{
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Large"></LoadingData>
|
||||
<div class="row m-2 placeholder-glow">
|
||||
<span class="placeholder col-4 my-1"></span>
|
||||
<span class="placeholder col-7 my-1"></span>
|
||||
<span class="placeholder col-8 my-1"></span>
|
||||
<span class="placeholder col-3 my-1"></span>
|
||||
</div>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Large" DisplayMode="LoadingData.SpinMode.Growl"></LoadingData>
|
||||
<div class="row m-2 placeholder-glow">
|
||||
<span class="placeholder col-4 my-1"></span>
|
||||
<span class="placeholder col-7 my-1"></span>
|
||||
<span class="placeholder col-8 my-1"></span>
|
||||
<span class="placeholder col-3 my-1"></span>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
<div style="background-color: #34495E; border-radius: 12px; width:100%" class="pb-1 mb-5">
|
||||
<CalendarMonth DtRif="@dtCurr" MainCss="table table-dark table-borderless" DateSelected="DisplayDate" MonthChanged="ReloadMonth" DateCheck="@DateCheck" DateCheckBlock="@DateCFF" SingleWeek="@showDetail" SelDayCss="selDate rounded-top p-2" HeadStyle="color: #E67E22"></CalendarMonth>
|
||||
@if (showDetail)
|
||||
|
||||
@@ -18,19 +18,6 @@ namespace GPW.CORE.Smart.Components
|
||||
[Parameter]
|
||||
public int IdxDipendente { get; set; } = -1;
|
||||
|
||||
[Parameter]
|
||||
public List<DailyDataDTO>? ListRecords
|
||||
{
|
||||
get => listRecords;
|
||||
set
|
||||
{
|
||||
if (listRecords != value)
|
||||
{
|
||||
listRecords = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public List<CalFesteFerieModel>? ListFermateAzienda
|
||||
{
|
||||
@@ -44,6 +31,19 @@ namespace GPW.CORE.Smart.Components
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public List<DailyDataDTO>? ListRecords
|
||||
{
|
||||
get => listRecords;
|
||||
set
|
||||
{
|
||||
if (listRecords != value)
|
||||
{
|
||||
listRecords = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public List<RegRichiesteModel>? ListRecordsRichieste
|
||||
{
|
||||
@@ -62,8 +62,6 @@ namespace GPW.CORE.Smart.Components
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
private Dictionary<DateTime, string> DateCFF = new Dictionary<DateTime, string>();
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
@@ -80,7 +78,6 @@ namespace GPW.CORE.Smart.Components
|
||||
#region Protected Fields
|
||||
|
||||
protected DailyDataDTO? datiGiorno = null;
|
||||
|
||||
protected string emptyTime = "--/--";
|
||||
|
||||
#endregion Protected Fields
|
||||
@@ -105,6 +102,7 @@ namespace GPW.CORE.Smart.Components
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private Dictionary<DateTime, string> DateCFF = new Dictionary<DateTime, string>();
|
||||
private Dictionary<DateTime, string> DateCheck = new Dictionary<DateTime, string>();
|
||||
|
||||
private Dictionary<DateTime, string> DateFerFestCheck = new Dictionary<DateTime, string>();
|
||||
@@ -126,9 +124,8 @@ namespace GPW.CORE.Smart.Components
|
||||
|
||||
private DateTime dtCurr { get; set; } = DateTime.Today;
|
||||
|
||||
private List<DailyDataDTO>? listRecords { get; set; } = null;
|
||||
private List<CalFesteFerieModel>? listCFF { get; set; } = null;
|
||||
|
||||
private List<DailyDataDTO>? listRecords { get; set; } = null;
|
||||
private List<RegRichiesteModel>? listRecordsRichieste { get; set; } = null;
|
||||
|
||||
[Inject]
|
||||
@@ -211,7 +208,6 @@ namespace GPW.CORE.Smart.Components
|
||||
string cssSpec = "";
|
||||
foreach (var item in ListFermateAzienda)
|
||||
{
|
||||
|
||||
cssSpec = item.codGiust == "FEST" ? cssFest : cssChius;
|
||||
if (!DateCFF.ContainsKey(item.data))
|
||||
{
|
||||
@@ -244,7 +240,6 @@ namespace GPW.CORE.Smart.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ListRecords != null)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="container d-flex justify-content-between">
|
||||
<div class="title @homeCss" @onclick="ReturnHome">
|
||||
<div class="title @homeCss" @onclick="ForceReset">
|
||||
<i class="fa-solid fa-home"></i>
|
||||
<sub>@homeMessage</sub>
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace GPW.CORE.Smart.Components
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
MService.EA_DipUpdated -= MService_EA_DipUpdated;
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
@@ -122,7 +123,7 @@ namespace GPW.CORE.Smart.Components
|
||||
protected async Task DoVerifyActiv()
|
||||
{
|
||||
MService.PayloadOk = false;
|
||||
await Task.Delay(250);
|
||||
await Task.Delay(1);
|
||||
await VerifyActiv();
|
||||
}
|
||||
|
||||
@@ -149,6 +150,14 @@ namespace GPW.CORE.Smart.Components
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
MService.EA_DipUpdated += MService_EA_DipUpdated;
|
||||
// lettura dati base
|
||||
await ReloadData();
|
||||
// verifica attivazione
|
||||
await VerifyActiv();
|
||||
}
|
||||
private async void MService_EA_DipUpdated()
|
||||
{
|
||||
// lettura dati base
|
||||
await ReloadData();
|
||||
@@ -163,9 +172,12 @@ namespace GPW.CORE.Smart.Components
|
||||
LocalNet = confNet != null ? confNet.valore : "10";
|
||||
}
|
||||
|
||||
protected void ReturnHome()
|
||||
protected async Task ReturnHome()
|
||||
{
|
||||
navManager.NavigateTo("Home", true);
|
||||
// svuoto cache
|
||||
await CDService.FlushRedisCache();
|
||||
// ritorno in home
|
||||
navManager.NavigateTo("Home", true);
|
||||
}
|
||||
|
||||
protected async Task VerifyActiv()
|
||||
|
||||
@@ -51,7 +51,10 @@ namespace GPW.CORE.Smart.Components
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await reloadData();
|
||||
if (IdxDipCurr > 0)
|
||||
{
|
||||
await reloadData();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
@if (IsRicTimb)
|
||||
{
|
||||
<div class="cardContainerMancTimb">
|
||||
<div class="data">
|
||||
<span>@($"{oraRichiesta:dddd dd MMMM}")</span>
|
||||
<div class="cardContainerMancTimb py-2 px-3">
|
||||
<div class="data d-flex justify-content-between">
|
||||
<div class="px-0">
|
||||
<span>@($"{oraRichiesta:dddd}")</span>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
<span>@($"{oraRichiesta:dd MMMM}")</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oraRichiesta">
|
||||
<input @bind="oraRichiesta" type="time" step="300" />
|
||||
@@ -13,10 +18,14 @@ else
|
||||
{
|
||||
@if (!isCompactMode)
|
||||
{
|
||||
|
||||
<div class="cardContainer @cardCss">
|
||||
<div class="data">
|
||||
<span>@($"{dtCurr:dddd dd MMMM}")</span>
|
||||
<div class="cardContainer @cardCss py-2 px-3">
|
||||
<div class="data d-flex justify-content-between">
|
||||
<div class="px-0">
|
||||
<span>@($"{dtCurr:dddd}")</span>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
<span>@($"{dtCurr:dd MMMM}")</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ora">
|
||||
<div class="d-flex justify-content-center">
|
||||
@@ -33,11 +42,16 @@ else
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="cardContainerCompact @cardCss">
|
||||
<div class="cardContainerCompact @cardCss py-1 px-3">
|
||||
<div class="dataComp">
|
||||
<span>@($"{dtCurr:dddd}")</span>
|
||||
<span>@($"{dtCurr:dd MMMM}")</span>
|
||||
|
||||
<div class="data d-flex justify-content-between">
|
||||
<div class="px-0">
|
||||
<span>@($"{dtCurr:dddd}")</span>
|
||||
</div>
|
||||
<div class="px-0">
|
||||
<span>@($"{dtCurr:dd MMMM}")</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ora">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
}
|
||||
.cardContainerCompact .dataComp {
|
||||
font-weight: bold;
|
||||
padding-top: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
/*padding-top: 1.5rem;*/
|
||||
/*padding-left: 1.5rem;*/
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem;
|
||||
@@ -49,8 +49,8 @@
|
||||
}
|
||||
.data {
|
||||
font-weight: bold;
|
||||
padding-top: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
/*padding-top: 1.5rem;*/
|
||||
/*padding-left: 1.5rem;*/
|
||||
position: relative;
|
||||
font-size: 1.25rem;
|
||||
text-transform: uppercase;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
.cardContainerCompact .dataComp {
|
||||
font-weight: bold;
|
||||
padding-top: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
/*padding-top: 1.5rem;*/
|
||||
/*padding-left: 1.5rem;*/
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
font-size: 1rem;
|
||||
@@ -47,8 +47,8 @@
|
||||
|
||||
.data {
|
||||
font-weight: bold;
|
||||
padding-top: 1.5rem;
|
||||
padding-left: 1.5rem;
|
||||
/*padding-top: 1.5rem;*/
|
||||
/*padding-left: 1.5rem;*/
|
||||
position: relative;
|
||||
font-size: 1.25rem;
|
||||
text-transform: uppercase;
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
.cardContainerAll{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;}.cardContainer{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;min-height:8.5rem;padding-bottom:1rem;}.cardContainerCompact{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;min-height:4rem;}.cardContainerCompact .dataComp{font-weight:bold;padding-top:1.5rem;padding-left:1.5rem;position:relative;text-transform:uppercase;font-size:1rem;}.cardContainerCompact .ora{width:100%;font-weight:bold;position:relative;font-size:3.5rem;text-align:center;font-size:2.8rem;}.cardContainerMancTimb{padding-bottom:1rem;min-height:8.5rem;border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;background-color:#2980b9;}.titolo{font-size:1rem;}.data{font-weight:bold;padding-top:1.5rem;padding-left:1.5rem;position:relative;font-size:1.25rem;text-transform:uppercase;display:flex;justify-content:space-between;}.ora{width:100%;font-weight:bold;position:relative;font-size:3.5rem;text-align:center;}.oraRichiesta{width:100%;font-weight:bold;position:relative;font-size:2rem;text-align:center;padding-top:1.5rem;}.oraRichiesta input{border-radius:.5rem;border:0;padding:.25rem;}.defaultCard{background-color:rgba(0,128,255,.8);}.cardEntrata{background-color:#9b59b6;}.cardUscita{background-color:#4caf50;}.txtSec{font-weight:normal;font-size:2rem;}.pulse-warning{box-shadow:0 0 20px 5px rgba(0,128,255,.8);animation:pulse-warning 2.5s infinite;}@-webkit-keyframes pulse-warning{0%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}70%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,0);}100%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}}@keyframes pulse-warning{0%{-moz-box-shadow:0 0 20px 5px rgba(0,128,255,.8);box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}70%{-moz-box-shadow:0 0 20px 5px rgba(0,128,255,0);box-shadow:0 0 20px 5px rgba(0,128,255,0);}100%{-moz-box-shadow:0 0 20px 5px rgba(255,170,0,.8);box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}}
|
||||
.cardContainerAll{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;}.cardContainer{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;min-height:8.5rem;padding-bottom:1rem;}.cardContainerCompact{border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;min-height:4rem;}.cardContainerCompact .dataComp{font-weight:bold;position:relative;text-transform:uppercase;font-size:1rem;}.cardContainerCompact .ora{width:100%;font-weight:bold;position:relative;font-size:3.5rem;text-align:center;font-size:2.8rem;}.cardContainerMancTimb{padding-bottom:1rem;min-height:8.5rem;border-radius:12px;width:100%;box-shadow:0 3px 4px rgba(0,0,0,.7);color:#fff;background-color:#2980b9;}.titolo{font-size:1rem;}.data{font-weight:bold;position:relative;font-size:1.25rem;text-transform:uppercase;display:flex;justify-content:space-between;}.ora{width:100%;font-weight:bold;position:relative;font-size:3.5rem;text-align:center;}.oraRichiesta{width:100%;font-weight:bold;position:relative;font-size:2rem;text-align:center;padding-top:1.5rem;}.oraRichiesta input{border-radius:.5rem;border:0;padding:.25rem;}.defaultCard{background-color:rgba(0,128,255,.8);}.cardEntrata{background-color:#9b59b6;}.cardUscita{background-color:#4caf50;}.txtSec{font-weight:normal;font-size:2rem;}.pulse-warning{box-shadow:0 0 20px 5px rgba(0,128,255,.8);animation:pulse-warning 2.5s infinite;}@-webkit-keyframes pulse-warning{0%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}70%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,0);}100%{-webkit-box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}}@keyframes pulse-warning{0%{-moz-box-shadow:0 0 20px 5px rgba(0,128,255,.8);box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}70%{-moz-box-shadow:0 0 20px 5px rgba(0,128,255,0);box-shadow:0 0 20px 5px rgba(0,128,255,0);}100%{-moz-box-shadow:0 0 20px 5px rgba(255,170,0,.8);box-shadow:0 0 20px 5px rgba(0,128,255,.8);color:#fff;}}
|
||||
@@ -1,8 +1,10 @@
|
||||
using EgwCoreLib.Razor.Data;
|
||||
using EgwCoreLib.Utils;
|
||||
using GPW.CORE.Data;
|
||||
using GPW.CORE.Data.DbModels;
|
||||
using GPW.CORE.Data.DTO;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.VisualBasic;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
@@ -51,6 +53,11 @@ namespace GPW.CORE.Smart.Data
|
||||
{
|
||||
dbController = new CORE.Data.Controllers.GPWController(configuration);
|
||||
}
|
||||
|
||||
// init datapipe...
|
||||
mPipeTimb = new MessagePipe(redisConn, Const.rPipeChTimb);
|
||||
mPipeRich = new MessagePipe(redisConn, Const.rPipeChRich);
|
||||
|
||||
_logger.LogInformation("Avviata classe CoreSmartDataService");
|
||||
}
|
||||
|
||||
@@ -60,6 +67,16 @@ namespace GPW.CORE.Smart.Data
|
||||
|
||||
public string CodApp { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Pipe messaggi richieste
|
||||
/// </summary>
|
||||
public MessagePipe mPipeRich { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe messaggi timbrature
|
||||
/// </summary>
|
||||
public MessagePipe mPipeTimb { get; set; } = null!;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
@@ -354,6 +371,47 @@ namespace GPW.CORE.Smart.Data
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati orario globali da setup
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<AnagOrariModel>> AnagOrarioAll()
|
||||
{
|
||||
string source = "DB";
|
||||
List<AnagOrariModel> dbResult = new List<AnagOrariModel>();
|
||||
string currKey = $"{rKeyAnOrDip}:ALL";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<AnagOrariModel>>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dbResult = new List<AnagOrariModel>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = dbController.AnagOrarioGetAll();
|
||||
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, UltraLongCache);
|
||||
}
|
||||
if (dbResult == null)
|
||||
{
|
||||
dbResult = new List<AnagOrariModel>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"AnagOrarioAll | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dati orario del dipendente indicato
|
||||
/// </summary>
|
||||
@@ -882,8 +940,19 @@ namespace GPW.CORE.Smart.Data
|
||||
answ = dbController.RegMalattieDelete(currItem);
|
||||
if (answ)
|
||||
{
|
||||
// recupero info dipendente
|
||||
var listDip = await DipendentiGetAll();
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoMal"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkMal"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1014,6 +1083,14 @@ namespace GPW.CORE.Smart.Data
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoMal"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkMal"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1053,8 +1130,19 @@ namespace GPW.CORE.Smart.Data
|
||||
answ = dbController.RegRichiesteDelete(currItem);
|
||||
if (answ)
|
||||
{
|
||||
// recupero info dipendente
|
||||
var listDip = await DipendentiGetAll();
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoRich"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkRich"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1144,6 +1232,14 @@ namespace GPW.CORE.Smart.Data
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoRich"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkRich"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1301,7 +1397,7 @@ namespace GPW.CORE.Smart.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserimento richeista mancata timbratura
|
||||
/// Inserimento richiesta mancata timbratura
|
||||
/// </summary>
|
||||
/// <param name="currItem"></param>
|
||||
/// <returns></returns>
|
||||
@@ -1315,6 +1411,8 @@ namespace GPW.CORE.Smart.Data
|
||||
currItem.Approv = false;
|
||||
// upsert!
|
||||
answ = dbController.TimbratureUpdate(currItem);
|
||||
// invio in pipe timbratura
|
||||
mPipeRich.sendMessage(JsonConvert.SerializeObject(currItem));
|
||||
Log.Info($"Registrata richiesta Mancata Timbratura | idxDip {currItem.IdxDipendente} | data-ora: {currItem.DataOra} | isEntrata: {currItem.Entrata}");
|
||||
// invalido la cache...
|
||||
await FlushRedisCache();
|
||||
@@ -1347,6 +1445,8 @@ namespace GPW.CORE.Smart.Data
|
||||
try
|
||||
{
|
||||
answ = dbController.TimbratureUpdate(currItem);
|
||||
// invio in pipe timbratura
|
||||
mPipeTimb.sendMessage(JsonConvert.SerializeObject(currItem));
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
}
|
||||
@@ -1417,6 +1517,27 @@ namespace GPW.CORE.Smart.Data
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calcola email del responsabile dato idx
|
||||
/// </summary>
|
||||
/// <param name="idxResp"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<string> emailResp(int idxResp)
|
||||
{
|
||||
string answ = "";
|
||||
var listDip = await DipendentiGetAll();
|
||||
// recupero email resp...
|
||||
if (idxResp > 0)
|
||||
{
|
||||
var recResp = listDip.FirstOrDefault(x => x.IdxDipendente == idxResp);
|
||||
if (recResp != null)
|
||||
{
|
||||
answ = $"{recResp.Email}";
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invio email tramite libreria
|
||||
/// </summary>
|
||||
|
||||
@@ -162,23 +162,6 @@ namespace GPW.CORE.Smart.Data
|
||||
}
|
||||
}
|
||||
|
||||
public string SearchVal
|
||||
{
|
||||
get => _searchVal;
|
||||
set
|
||||
{
|
||||
if (_searchVal != value)
|
||||
{
|
||||
_searchVal = value;
|
||||
|
||||
if (EA_DipUpdated != null)
|
||||
{
|
||||
EA_DipUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int selWeekNum { get; set; } = 0;
|
||||
public int selYear { get; set; } = DateTime.Today.Year;
|
||||
|
||||
@@ -356,8 +339,6 @@ namespace GPW.CORE.Smart.Data
|
||||
|
||||
private DipendentiModel? _rigaDip;
|
||||
|
||||
private string _searchVal = "";
|
||||
|
||||
private Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private bool showSearch;
|
||||
@@ -382,13 +363,6 @@ namespace GPW.CORE.Smart.Data
|
||||
}
|
||||
}
|
||||
|
||||
private void ReportSearch()
|
||||
{
|
||||
if (EA_DipUpdated != null)
|
||||
{
|
||||
EA_DipUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>3.0.2312.0708</Version>
|
||||
<Version>3.0.2408.1910</Version>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PackageProjectUrl>www.egalware.com</PackageProjectUrl>
|
||||
<Description>GPW Smart UI</Description>
|
||||
@@ -28,10 +28,10 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
|
||||
<PackageReference Include="Blazored.SessionStorage" Version="2.3.0" />
|
||||
<PackageReference Include="EgwCoreLib.Razor" Version="1.4.2307.3111" />
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.4.2307.3111" />
|
||||
<PackageReference Include="EgwCoreLib.Razor" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="RestSharp" Version="108.0.3" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.27" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -48,7 +48,10 @@ namespace GPW.CORE.Smart.Pages
|
||||
{
|
||||
idxDipendente = MService.IdxDipendente;
|
||||
await Task.Delay(1);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
if (idxDipendente > 0)
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace GPW.CORE.Smart.Pages
|
||||
// resetto valori in localStorage...
|
||||
string devSec = "";
|
||||
string devIp = "";
|
||||
authKey = "";
|
||||
await MService.setDevSecretAsync(devSec);
|
||||
await MService.setDevIpv4Async(devIp);
|
||||
// recupero da URL
|
||||
@@ -111,6 +112,13 @@ namespace GPW.CORE.Smart.Pages
|
||||
authKey = _authKey;
|
||||
}
|
||||
}
|
||||
else if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("UserAuthKey", out var _userAuthKey))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_userAuthKey))
|
||||
{
|
||||
authKey = _userAuthKey;
|
||||
}
|
||||
}
|
||||
DateTime adesso = DateTime.Now;
|
||||
string dtData = $"{DateTime.UtcNow:yyyy-MM-dd_ZHH:mm:ss}";
|
||||
string devAgent = await JSRuntime.InvokeAsync<string>("getUserAgent");
|
||||
|
||||
@@ -27,4 +27,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading02">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse02" aria-expanded="false" aria-controls="collapse02">
|
||||
<b>Fix pagine offline</b>
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse02" class="accordion-collapse collapse" aria-labelledby="heading02" data-bs-parent="#accordionExample">
|
||||
<div class="accordion-body small">
|
||||
Nel caso il browser stia presentando pagine offline/archiviate come valide, traendo in inganno sulle effettive timbrature, si deve procedere con la pulizia della cache delle pagine offline.
|
||||
<br />
|
||||
Per farlo si deve seguire la procedura manuale di seguito riportata:
|
||||
<ul>
|
||||
<li>Aprire una nuova pagina dal browser chrome sul device</li>
|
||||
<li>inserire l'indirizzo seguente:<br /><b>chrome://offline-internals/</b></li>
|
||||
<li>eliminare almeno le pagine di<br /> <b>office.egalware.com</b></li>
|
||||
</ul>
|
||||
Purtroppo non è possibile automatizzare questa procedura ne aprire direttamente il link con un pulsante o una procedura poiché questo è vietato per motivi di sicurezza interna dai browser.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -36,13 +36,39 @@
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
@* <div id="offline-overlay" class="animate-overlay">
|
||||
<span>OFFLINE</span>
|
||||
</div> *@
|
||||
|
||||
<script type="text/javascript" src="lib/css/bootstrap/js/bootstrap.min.js"></script>
|
||||
@*Gestione autoriconnessione: https://github.com/dotnet/aspnetcore/issues/38305 (vedere anche https://docs.microsoft.com/it-it/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-6.0#modify-the-reconnection-handler-blazor-server)*@
|
||||
|
||||
<script src="_framework/blazor.server.js" autostart="false"></script>
|
||||
<script>
|
||||
Blazor.start({
|
||||
reconnectionOptions: {
|
||||
maxRetries: 300,
|
||||
retryIntervalMilliseconds: 2000
|
||||
maxRetries: 3600,
|
||||
retryIntervalMilliseconds: 1000
|
||||
},
|
||||
}).then(() => {
|
||||
Blazor.defaultReconnectionHandler._reconnectCallback = function (d) {
|
||||
console.log("Client reconnected, waiting 5 sec and reload!");
|
||||
setTimeout(function () {
|
||||
document.location.reload();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@*Gestione autoriconnessione: https://github.com/dotnet/aspnetcore/issues/38305 (vedere anche https://docs.microsoft.com/it-it/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-6.0#modify-the-reconnection-handler-blazor-server)*@
|
||||
@* <script>
|
||||
Blazor.start({
|
||||
reconnectionOptions: {
|
||||
maxRetries: 1500,
|
||||
retryIntervalMilliseconds: 4000
|
||||
},
|
||||
reconnectionHandler: {
|
||||
onConnectionDown: (options, error) => console.error(error),
|
||||
onConnectionUp: () => console.log("Connection up!,restarting!")
|
||||
}
|
||||
}).then(() => {
|
||||
Object.defineProperty(Blazor.defaultReconnectionHandler, '_reconnectionDisplay', {
|
||||
@@ -58,7 +84,27 @@
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script> *@
|
||||
@* <script>
|
||||
Blazor.start({
|
||||
reconnectionOptions: {
|
||||
maxRetries: 3000,
|
||||
retryIntervalMilliseconds: 2000
|
||||
},
|
||||
reconnectionHandler: {
|
||||
onConnectionDown: (options, error) => console.error(error),
|
||||
onConnectionUp: () => console.log("Client reconnected!")
|
||||
}
|
||||
}).then(() => {
|
||||
Blazor.defaultReconnectionHandler._reconnectCallback = function (d) {
|
||||
document.location.reload();
|
||||
}
|
||||
});
|
||||
</script> *@
|
||||
|
||||
|
||||
@* Versione alternativa da testare... https://github.com/dotnet/aspnetcore/issues/10325 *@
|
||||
|
||||
<script type="text/javascript" src="lib/font-awesome/js/all.min.js"></script>
|
||||
<script type="text/javascript" src="lib/Chart.js/chart.js"></script>
|
||||
<script type="text/javascript" src="lib/luxon/luxon.js"></script>
|
||||
@@ -67,10 +113,8 @@
|
||||
<script type="text/javascript" src="lib/WindowSize.js"></script>
|
||||
<script type="text/javascript" src="lib/UserAgent.js"></script>
|
||||
<script type="text/javascript" src="lib/ModalPopper.js"></script>
|
||||
@*<script type="text/javascript" src="lib/ToastTrigger.js"></script>*@
|
||||
@* <script type="text/javascript" src="lib/offlineOverlay.js"></script> *@
|
||||
<script type="text/javascript" src="lib/qrcode.js"></script>
|
||||
<script type="text/javascript" src="lib/qrHelper.js"></script>
|
||||
<script type="text/javascript" src="lib/MenuHandler.js"></script>
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -22,19 +22,13 @@ var redisMultiplexer = ConnectionMultiplexer.Connect(connStringRedis);
|
||||
|
||||
// abilitazione x email management con MailKit
|
||||
builder.Services.AddTransient<IEmailSender, MailKitEmailSender>();
|
||||
// recupero email reversed
|
||||
string revPwd = configuration["ExternalProviders:MailKit:SMTP:Password"] ?? "";
|
||||
string pwd = "";
|
||||
foreach (char c in revPwd)
|
||||
{
|
||||
pwd = c + pwd;
|
||||
}
|
||||
|
||||
builder.Services.Configure<MailKitEmailSenderOptions>(options =>
|
||||
{
|
||||
options.Host_Address = configuration["ExternalProviders:MailKit:SMTP:Address"];
|
||||
options.Host_Port = Convert.ToInt32(configuration["ExternalProviders:MailKit:SMTP:Port"]);
|
||||
options.Host_Username = configuration["ExternalProviders:MailKit:SMTP:Account"];
|
||||
options.Host_Password = pwd;// configuration["ExternalProviders:MailKit:SMTP:Password"];
|
||||
options.Host_Password = configuration["ExternalProviders:MailKit:SMTP:Password"];
|
||||
options.Sender_EMail = configuration["ExternalProviders:MailKit:SMTP:SenderEmail"];
|
||||
options.Sender_Name = configuration["ExternalProviders:MailKit:SMTP:SenderName"];
|
||||
});
|
||||
@@ -54,6 +48,9 @@ builder.Services.AddBlazoredSessionStorage();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// aggiunt base URL x routing corretto
|
||||
app.UsePathBase(builder.Configuration["OptConf:BaseUrl"]);
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (!app.Environment.IsDevelopment())
|
||||
{
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<div class="alert alert-secondary mt-4">
|
||||
<span class="oi oi-pencil me-2" aria-hidden="true"></span>
|
||||
<strong>@Title</strong>
|
||||
|
||||
<span class="text-nowrap">
|
||||
Please take our
|
||||
<a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2149017">brief survey</a>
|
||||
</span>
|
||||
and tell us what you think.
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Demonstrates how a parent component can supply parameters
|
||||
[Parameter]
|
||||
public string? Title { get; set; }
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
"AllowedHosts": "*",
|
||||
"CodApp": "GPW",
|
||||
"ConnectionStrings": {
|
||||
"Redis": "localhost:6379,DefaultDatabase=15,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false",
|
||||
"GPW.DB": "Server=W2019-SQL-STEAM;Database=GPW; User ID=sa;Password=keyhammer16; integrated security=False; MultipleActiveResultSets=True; App=GPW.CORE.WRKLOG;"
|
||||
"Redis": "localhost:26379,serviceName=prod,DefaultDatabase=15,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,password=BtN9Py1wtLfLRvmzWnOPJ7RytDM+CLiVsJ/16zduNTlV8IOPGNrtzJSXPUnImA5PqmUMhKaUqo9NdHIG",
|
||||
"GPW.DB": "Server=W2019-SQL-STEAM;Database=GPW; User ID=UserGPW; Password=Us3rGpw!75x93$77; integrated security=False; MultipleActiveResultSets=True; App=GPW.CORE.WRKLOG;"
|
||||
},
|
||||
"Application": {
|
||||
"ContactText": "Our contacts and support sites",
|
||||
@@ -22,12 +22,15 @@
|
||||
"Address": "smtp-mail.outlook.com",
|
||||
"Port": "587",
|
||||
"Account": "steamwarebot@outlook.it",
|
||||
"Password": "!39elanoizaNaiVnIomais",
|
||||
"Password": "siamoInViaNazionale93!",
|
||||
"SenderEmail": "steamwarebot@outlook.it",
|
||||
"SenderName": "Steamware Email BOT"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OptConf": {
|
||||
"BaseUrl": "/GPW/CORE.Smart"
|
||||
},
|
||||
"MailDest": {
|
||||
"Admin": "samuele@steamware.net",
|
||||
"InfoMal": "samuele.locatelli@egalware.com",
|
||||
|
||||
@@ -27,6 +27,39 @@ a,
|
||||
.btn-link {
|
||||
color: #0071c1;
|
||||
}
|
||||
@keyframes offline {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
99% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.animate-overlay {
|
||||
animation-name: offline;
|
||||
animation-duration: 3s;
|
||||
}
|
||||
#offline-overlay {
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
#offline-overlay span {
|
||||
font-size: 300%;
|
||||
font-family: sans-serif;
|
||||
letter-spacing: 5px;
|
||||
color: #888;
|
||||
}
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
|
||||
@@ -19,6 +19,46 @@ a, .btn-link {
|
||||
color: #0071c1;
|
||||
}
|
||||
|
||||
@keyframes offline {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
99% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animate-overlay {
|
||||
animation-name: offline;
|
||||
animation-duration: 3s;
|
||||
}
|
||||
|
||||
#offline-overlay {
|
||||
background-color: rgba(255,255,255,.9);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#offline-overlay span {
|
||||
font-size: 300%;
|
||||
font-family: sans-serif;
|
||||
letter-spacing: 5px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');@import url('fonts.min.css');h1,h2,h3,h4,h5,h6,b,display-1,display-2,display-3,display-4{font-family:'Lato',sans-serif;}html,body{font-family:'Roboto',sans-serif;}h1:focus{outline:0;}a,.btn-link{color:#0071c1;}.btn-primary{color:#fff;background-color:#1b6ec2;border-color:#1861ac;}.content{padding-top:1.1rem;}.valid.modified:not([type=checkbox]){outline:1px solid #26b050;}.invalid{outline:1px solid #f00;}.validation-message{color:#f00;}#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}.blazor-error-boundary{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem,#b32121;padding:1rem 1rem 1rem 3.7rem;color:#fff;}.blazor-error-boundary::after{content:"An error has occurred.";}
|
||||
@import url('open-iconic/font/css/open-iconic-bootstrap.min.css');@import url('fonts.min.css');h1,h2,h3,h4,h5,h6,b,display-1,display-2,display-3,display-4{font-family:'Lato',sans-serif;}html,body{font-family:'Roboto',sans-serif;}h1:focus{outline:0;}a,.btn-link{color:#0071c1;}@keyframes offline{0%{opacity:0;}99%{opacity:0;}100%{opacity:1;}}.animate-overlay{animation-name:offline;animation-duration:3s;}#offline-overlay{background-color:rgba(255,255,255,.9);position:absolute;top:0;left:0;right:0;bottom:0;display:flex;justify-content:center;align-items:center;pointer-events:none;}#offline-overlay span{font-size:300%;font-family:sans-serif;letter-spacing:5px;color:#888;}.btn-primary{color:#fff;background-color:#1b6ec2;border-color:#1861ac;}.content{padding-top:1.1rem;}.valid.modified:not([type=checkbox]){outline:1px solid #26b050;}.invalid{outline:1px solid #f00;}.validation-message{color:#f00;}#blazor-error-ui{background:#ffffe0;bottom:0;box-shadow:0 -1px 2px rgba(0,0,0,.2);display:none;left:0;padding:.6rem 1.25rem .7rem 1.25rem;position:fixed;width:100%;z-index:1000;}#blazor-error-ui .dismiss{cursor:pointer;position:absolute;right:.75rem;top:.5rem;}.blazor-error-boundary{background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem,#b32121;padding:1rem 1rem 1rem 3.7rem;color:#fff;}.blazor-error-boundary::after{content:"An error has occurred.";}
|
||||
@@ -1,9 +0,0 @@
|
||||
var toastTrigger = document.getElementById('ToastBtn')
|
||||
var currToastObj = document.getElementById('LiveToast')
|
||||
|
||||
if (toastTrigger) {
|
||||
toastTrigger.addEventListener('click', () => {
|
||||
const toast = new bootstrap.Toast(currToastObj)
|
||||
toast.show()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
const overlay = document.getElementById('offline-overlay');
|
||||
|
||||
const stopJS = document.getElementById('stopJS');
|
||||
|
||||
const heartbeat = () => {
|
||||
overlay.classList.remove("animate-overlay");
|
||||
void overlay.offsetWidth;
|
||||
overlay.classList.add("animate-overlay");
|
||||
}
|
||||
|
||||
const heartbeatInterval = setInterval(heartbeat, 1000);
|
||||
|
||||
stopJS.addEventListener("click", function () {
|
||||
clearInterval(heartbeatInterval);
|
||||
});
|
||||
@@ -1,16 +1,66 @@
|
||||
namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
public partial class CmpFooter
|
||||
public partial class CmpFooter : IDisposable
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (aTimer != null)
|
||||
{
|
||||
aTimer.Elapsed -= ElapsedTimer;
|
||||
aTimer.Stop();
|
||||
aTimer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected DateTime adesso = DateTime.Now;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected void ElapsedTimer(object? source, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
var pUpd = Task.Run(async () =>
|
||||
{
|
||||
adesso = DateTime.Now;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
pUpd.Wait();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var rawVers = typeof(Program).Assembly.GetName().Version;
|
||||
version = rawVers != null ? rawVers : new Version("0.0.0.0");
|
||||
StartTimer();
|
||||
}
|
||||
|
||||
protected void StartTimer()
|
||||
{
|
||||
if (aTimer != null)
|
||||
{
|
||||
aTimer.Stop();
|
||||
aTimer.Dispose();
|
||||
}
|
||||
int tOutPeriod = 1000;
|
||||
aTimer = new System.Timers.Timer(tOutPeriod);
|
||||
aTimer.Elapsed += ElapsedTimer;
|
||||
aTimer.Enabled = true;
|
||||
aTimer.Start();
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private Version? version = typeof(Program).Assembly.GetName().Version;
|
||||
private System.Timers.Timer aTimer = null!;
|
||||
private Version? version = null!;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
<div class="@cssTemp px-0">
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
@@ -101,7 +101,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,15 +4,31 @@
|
||||
<div class="p-1" style="width: 3.4rem;">
|
||||
@if (IsTitle)
|
||||
{
|
||||
<b>DAY</b>
|
||||
@if (MultiUser)
|
||||
{
|
||||
<div class="text-uppercase"><b>@DtRif.ToString("ddd")</b></div>
|
||||
<div class="small">@DtRif.ToString("dd.MM")</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<b>DAY</b>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DayDTO != null)
|
||||
{
|
||||
<div class="@dayCardCss text-center text-uppercase">
|
||||
<div class="text-uppercase"><b>@DayDTO.DtRif.ToString("ddd")</b></div>
|
||||
<div class="small">@DayDTO.DtRif.ToString("dd.MM")</div>
|
||||
@if (MultiUser)
|
||||
{
|
||||
<div class="small text-truncate" title="@Cognome"><b>@Cognome</b></div>
|
||||
<div class="small text-truncate" title="@Nome">@Nome</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="text-uppercase"><b>@DayDTO.DtRif.ToString("ddd")</b></div>
|
||||
<div class="small">@DayDTO.DtRif.ToString("dd.MM")</div>
|
||||
}
|
||||
@if (hasFest && DayDTO.ListFermateAzienda != null && DayDTO.ListFermateAzienda.Count > 0)
|
||||
{
|
||||
@foreach (var fermata in DayDTO.ListFermateAzienda)
|
||||
@@ -33,7 +49,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="small mt-2">
|
||||
<div class="my-2">
|
||||
|
||||
</div>
|
||||
}
|
||||
@@ -55,49 +71,54 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
@*<!-- MPF -->*@
|
||||
<div class="d-flex justify-content-between text-center small">
|
||||
@if (hasFest && DayDTO.ListFermateAzienda != null)
|
||||
{
|
||||
@foreach (var fermata in DayDTO.ListFermateAzienda)
|
||||
@if (hasFest || hasFerie || hasPerm)
|
||||
{
|
||||
<div class="d-flex justify-content-between text-center small">
|
||||
@*<!-- MPF -->*@
|
||||
@if (hasFest && DayDTO != null && DayDTO.ListFermateAzienda != null)
|
||||
{
|
||||
if (fermata.codGiust == "FEST")
|
||||
@foreach (var fermata in DayDTO.ListFermateAzienda)
|
||||
{
|
||||
<div class="mx-2 bg-danger rounded text-warning w-100">
|
||||
<div class="text-uppercase"><b>@fermata.codGiust</b> | @fermata.descrizione</div>
|
||||
</div>
|
||||
if (fermata.codGiust == "FEST")
|
||||
{
|
||||
<div class="mx-2 bg-danger rounded text-warning w-100">
|
||||
<div class="text-uppercase"><b>@fermata.codGiust</b> | @fermata.descrizione</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="mx-2 bg-warning rounded text-danger w-100">
|
||||
<div class="text-uppercase"><b>@fermata.codGiust</b> | @fermata.descrizione</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
}
|
||||
@if (hasFerie && DayDTO != null && DayDTO.ListFerieDip != null)
|
||||
{
|
||||
@foreach (var richiesta in DayDTO.ListFerieDip)
|
||||
{
|
||||
<div class="mx-2 bg-warning rounded text-danger w-100">
|
||||
<div class="text-uppercase"><b>@fermata.codGiust</b> | @fermata.descrizione</div>
|
||||
<div class="mx-2 bg-info rounded text-light w-100">
|
||||
<div>
|
||||
<b>FERIE</b> | <small class="small">@richiesta.Note</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
@if (hasFerie && DayDTO.ListFerieDip != null)
|
||||
{
|
||||
@foreach (var richiesta in DayDTO.ListFerieDip)
|
||||
else if (hasPerm && DayDTO != null && DayDTO.ListRichiesteDip != null)
|
||||
{
|
||||
<div class="mx-2 bg-info rounded text-light w-100">
|
||||
<div>
|
||||
<b>FERIE</b> | <small class="small">@richiesta.Note</small>
|
||||
|
||||
@foreach (var richiesta in DayDTO.ListRichiesteDip)
|
||||
{
|
||||
<div class="mx-2 bg-warning rounded text-dark w-100">
|
||||
<div>
|
||||
<b>@richiesta.CodGiust</b> | <small class="small">@richiesta.Note, @($"{@richiesta.DtStart:HH.mm} - {@richiesta.DtEnd:HH.mm}")</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
@if (hasPerm && DayDTO.ListRichiesteDip != null)
|
||||
{
|
||||
@foreach (var richiesta in DayDTO.ListRichiesteDip)
|
||||
{
|
||||
<div class="mx-2 bg-warning rounded text-dark w-100">
|
||||
<div>
|
||||
<b>@richiesta.CodGiust</b> | <small class="small">@richiesta.Note, @($"{@richiesta.DtStart:HH.mm} - {@richiesta.DtEnd:HH.mm}")</small>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@*<!-- Timbrature -->*@
|
||||
<div class="d-flex justify-content-between text-center">
|
||||
@if (DayDTO != null && DayDTO.ListTimbr != null && DayDTO.ListTimbr.Count > 0)
|
||||
@@ -125,13 +146,20 @@
|
||||
}
|
||||
if (doShow)
|
||||
{
|
||||
<PeriodoLav Periodo="periodo" CurrPeriodo="item" ItemSelected="PeriodoSelected"></PeriodoLav>
|
||||
string fSize = MultiUser ? "0.6rem" : "0.7em";
|
||||
<PeriodoLav Periodo="periodo" CurrPeriodo="item" ItemSelected="PeriodoSelected" FontSize="@fSize"></PeriodoLav>
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="py-0 mb-1 flex-fill" style="font-size: 1em;">
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@*<!-- RegAtt -->*@
|
||||
<div class="d-flex justify-content-between text-center">
|
||||
<div class="d-flex justify-content-between text-center" style="@cStyle">
|
||||
@if (@noData)
|
||||
{
|
||||
<AddRA NewItemCreated="ReportSelected" InizioPer="@FirstTimb" IdxDip="@IdxDipSel" EnableAction="@EnableActionMenu"></AddRA>
|
||||
@@ -141,6 +169,7 @@
|
||||
{
|
||||
@foreach (var item in ListRegAtt().OrderBy(x => x.Inizio))
|
||||
{
|
||||
|
||||
bool doShow = true;
|
||||
// se fuori periodo --> nascondo
|
||||
if (item.Fine < item.Inizio.Date.AddHours(StartHour) || item.Inizio > item.Fine.Date.AddHours(EndHour))
|
||||
@@ -162,7 +191,8 @@
|
||||
}
|
||||
if (doShow)
|
||||
{
|
||||
<RegAtt CurrData="item" Periodo="periodo" MidHour="midHour" ListFasi="@ListFasi" IdxDipSel="@IdxDipSel" ItemCloned="ReportCloned" ItemSelected="ReportSelected" ItemUpdated="ReportUpdated" EnableActionMenu="@EnableActionMenu"></RegAtt>
|
||||
string fSize = MultiUser ? "0.6rem" : "0.75em";
|
||||
<RegAtt CurrData="item" Periodo="periodo" MidHour="midHour" ListFasi="@ListFasi" IdxDipSel="@IdxDipSel" ItemCloned="ReportCloned" ItemSelected="ReportSelected" ItemUpdated="ReportUpdated" EnableActionMenu="@EnableActionMenu" FontSize="@fSize"></RegAtt>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,7 +209,10 @@
|
||||
{
|
||||
<div class="btn btn-sm w-100 btn-dark px-1 py-0" @onclick="SelTimbrature"><b>@TotLav</b> <i class="far fa-calendar-alt"></i></div>
|
||||
<div class="btn btn-sm w-100 @cssBadgeLav px-1 py-0 mt-1" @onclick="SelDayAgenda"><b>@TotComm</b> <i class="far fa-hourglass"></i></div>
|
||||
<div class="btn btn-sm w-100 btn-light border border-dark px-1 py-0 mt-1" @onclick="SelTemperature"><i class="fas fa-thermometer-half @cssThermo"></i> <i class="fas fa-certificate @cssCheck"></i></div>
|
||||
@if (!MultiUser)
|
||||
{
|
||||
<div class="btn btn-sm w-100 btn-light border border-dark px-1 py-0 mt-1" @onclick="SelTemperature"><i class="fas fa-thermometer-half @cssThermo"></i> <i class="fas fa-certificate @cssCheck"></i></div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,68 +8,12 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
public string cssBadgeLav
|
||||
{
|
||||
get
|
||||
{
|
||||
string bCtr = "btn";
|
||||
string answ = $"{bCtr}-light";
|
||||
var deltaComm = oreComm - oreLav;
|
||||
if (Math.Abs(deltaComm) < 0.5)
|
||||
{
|
||||
answ = $"{bCtr}-primary bg-opacity-75";
|
||||
}
|
||||
else if (Math.Abs(deltaComm) < 1)
|
||||
{
|
||||
answ = $"{bCtr}-warning";
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = $"{bCtr}-danger";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
public string cssCheck
|
||||
{
|
||||
get => OkVC19 ? "text-success" : "text-secondary";
|
||||
}
|
||||
|
||||
public string cssThermo
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "";
|
||||
// verifico in base a ok temp o meno...
|
||||
if (OkTemp)
|
||||
{
|
||||
// colore in base al valore...
|
||||
var currTemp = tempRil;
|
||||
if (currTemp >= (decimal)37.5)
|
||||
{
|
||||
answ = "text-danger";
|
||||
}
|
||||
else if (currTemp >= 37)
|
||||
{
|
||||
answ = "text-warning";
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = "text-success";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = "text-secondary";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public DailyDataDTO? DayDTO { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DateTime DtRif { get; set; } = DateTime.MinValue.Date;
|
||||
|
||||
[Parameter]
|
||||
public bool EnableActionMenu { get; set; } = true;
|
||||
|
||||
@@ -91,11 +35,11 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
[Parameter]
|
||||
public List<AnagFasiModel> ListFasi { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool MultiUser { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<DailyDataDTO> PeriodSelected { get; set; }
|
||||
#if false
|
||||
//public EventCallback<List<TimbratureModel>?> PeriodSelected { get; set; }
|
||||
#endif
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<DailyDataDTO> ReqDayAgenda { get; set; }
|
||||
@@ -117,6 +61,32 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected string cStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
int numBlock = ListRegAtt().Count;
|
||||
string fSize = "1.1rem";
|
||||
if (numBlock > 9)
|
||||
{
|
||||
fSize = "0.85rem";
|
||||
}
|
||||
else if (numBlock > 7)
|
||||
{
|
||||
fSize = "0.9rem";
|
||||
}
|
||||
else if (numBlock > 5)
|
||||
{
|
||||
fSize = "1.0rem";
|
||||
}
|
||||
return $"font-size: {fSize};";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
@@ -127,9 +97,6 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
if (DayDTO != null)
|
||||
{
|
||||
await PeriodSelected.InvokeAsync(DayDTO);
|
||||
#if false
|
||||
//await PeriodSelected.InvokeAsync(DayDTO.ListTimbr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,9 +145,6 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
if (DayDTO != null)
|
||||
{
|
||||
await PeriodSelected.InvokeAsync(DayDTO);
|
||||
#if false
|
||||
//await PeriodSelected.InvokeAsync(DayDTO.ListTimbr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +152,78 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private string Cognome
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "NA";
|
||||
if (DayDTO != null)
|
||||
{
|
||||
answ = DayDTO.TimbrExpl.CognomeNome.Split(" ")[0] ?? " NA";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private string cssBadgeLav
|
||||
{
|
||||
get
|
||||
{
|
||||
string bCtr = "btn";
|
||||
string answ = $"{bCtr}-light";
|
||||
var deltaComm = oreComm - oreLav;
|
||||
if (Math.Abs(deltaComm) < 0.5)
|
||||
{
|
||||
answ = $"{bCtr}-primary bg-opacity-75";
|
||||
}
|
||||
else if (Math.Abs(deltaComm) < 1)
|
||||
{
|
||||
answ = $"{bCtr}-warning";
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = $"{bCtr}-danger";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private string cssCheck
|
||||
{
|
||||
get => OkVC19 ? "text-success" : "text-secondary";
|
||||
}
|
||||
|
||||
private string cssThermo
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "";
|
||||
// verifico in base a ok temp o meno...
|
||||
if (OkTemp)
|
||||
{
|
||||
// colore in base al valore...
|
||||
var currTemp = tempRil;
|
||||
if (currTemp >= (decimal)37.5)
|
||||
{
|
||||
answ = "text-danger";
|
||||
}
|
||||
else if (currTemp >= 37)
|
||||
{
|
||||
answ = "text-warning";
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = "text-success";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = "text-secondary";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private string dayCardCss
|
||||
{
|
||||
get => hasTimb ? "border border-dark text-dark rounded shadow" : "text-secondary rounded";
|
||||
@@ -223,6 +259,19 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
get => DayDTO == null || DayDTO.ListRA == null || DayDTO.ListRA.Count == 0;
|
||||
}
|
||||
|
||||
private string Nome
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "NA";
|
||||
if (DayDTO != null)
|
||||
{
|
||||
answ = DayDTO.TimbrExpl.CognomeNome.Replace($"{Cognome} ", "");
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool OkTemp
|
||||
{
|
||||
get
|
||||
@@ -315,8 +364,6 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
answ = DayDTO.OreMinComm;
|
||||
}
|
||||
return answ;
|
||||
//TimeSpan tSpan = TimeSpan.FromHours(oreComm);
|
||||
//return $"{tSpan.Hours}:{tSpan.Minutes:00}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,8 +377,6 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
answ = DayDTO.OreMinLav;
|
||||
}
|
||||
return answ;
|
||||
//TimeSpan tSpan = Utils.TSpanRounded(TimeSpan.FromHours(oreLav), 5, true);
|
||||
//return $"{tSpan.Hours}:{tSpan.Minutes:00}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +481,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
result.Add(emptyPeriod);
|
||||
}
|
||||
|
||||
|
||||
// ...processo cercando uscita relativa oppure NOW
|
||||
if (timbOUT.Count > idxTimb)
|
||||
{
|
||||
@@ -448,12 +494,19 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
fineLav = DateTime.Today.AddHours(adesso.Hour).AddMinutes(minRound);
|
||||
isClosed = false;
|
||||
}
|
||||
// solo x la prima prendo entrata_1... x rettifica ingresso
|
||||
DateTime inizioLav = item.DataOra;
|
||||
if (idxTimb == 0 && DayDTO.TimbrExpl.Entrata1 != null)
|
||||
{
|
||||
inizioLav = DayDTO.TimbrExpl.Entrata1 ?? item.DataOra;
|
||||
}
|
||||
PeriodoDTO workPeriod = new PeriodoDTO()
|
||||
{
|
||||
Inizio = item.DataOra,
|
||||
|
||||
Inizio = inizioLav,
|
||||
Fine = fineLav,
|
||||
Tipo = CORE.Data.TipoPeriodo.Lavoro,
|
||||
OreTot = (decimal)fineLav.Subtract(item.DataOra).TotalHours,
|
||||
OreTot = (decimal)fineLav.Subtract(inizioLav).TotalHours,
|
||||
IsClosed = isClosed
|
||||
};
|
||||
result.Add(workPeriod);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<button @onclick="() => Clone()" class="px-1 text-center border border-secondary border-top-0 border-bottom-0 border-left-0 btn btn-primary btn-sm py-1" style="font-size: @FontSizeBig; width:3.4em;" title="Copy">
|
||||
<i class="fas fa-paste"></i>
|
||||
</button>
|
||||
<div class="px-2 py-0 text-start textTrim flex-fill" style="font-size: @FontSizeSmall;">
|
||||
<div class="px-2 py-0 text-start textTrim flex-fill @blockClass" style="font-size: @FontSizeSmall;">
|
||||
<div class="text-dark textTrim @cssTrim" title="@CurrData.FasiNav?.ProgettoNav?.ClienteNav?.RagSociale - @CurrData.FasiNav?.ProgettoNav?.NomeProj"><b>@(trimLine($"{CurrData.FasiNav?.ProgettoNav?.ClienteNav?.RagSociale}", MaxChar))</b> - @(trimLine($"{CurrData.FasiNav?.ProgettoNav?.NomeProj}", MaxChar))</div>
|
||||
<div class="text-secondary textTrim @cssTrim" title="@CurrData.FasiNav?.DescrizioneFase">@(trimLine($"{CurrData.FasiNav?.DescrizioneFase}", 100))</div>
|
||||
<div class="text-trim @cssTrim" title="@CurrData.Descrizione">@(trimLine($"{CurrData.Descrizione}", MaxChar))</div>
|
||||
|
||||
@@ -4,13 +4,19 @@ using Microsoft.JSInterop;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
public partial class DettAtt
|
||||
public partial class DettAtt : IDisposable
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
[Parameter]
|
||||
public RegAttivitaModel CurrData { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public string FontSizeBig { get; set; } = "1.4rem";
|
||||
|
||||
[Parameter]
|
||||
public string FontSizeSmall { get; set; } = "1.1rem";
|
||||
|
||||
[Parameter]
|
||||
public int IdxDipSel { get; set; } = 0;
|
||||
|
||||
@@ -32,13 +38,17 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
[Parameter]
|
||||
public bool ShowDate { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public string FontSizeBig { get; set; } = "1.4rem";
|
||||
[Parameter]
|
||||
public string FontSizeSmall { get; set; } = "1.1rem";
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppMServ.EA_SearchUpdated -= AppMServ_EA_SearchUpdated;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected bool isSelected = false;
|
||||
@@ -47,6 +57,24 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected string blockClass
|
||||
{
|
||||
get
|
||||
{
|
||||
string btnClass = "";
|
||||
bool highlight = false;
|
||||
// recupero search
|
||||
string SearchVal = AppMServ.SearchVal;
|
||||
// calcolo valore highlight
|
||||
if (!string.IsNullOrEmpty(SearchVal))
|
||||
{
|
||||
highlight = (CurrData.Descrizione.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
btnClass = highlight ? "bg-success bg-opacity-25" : "bg-light";
|
||||
return btnClass;
|
||||
}
|
||||
}
|
||||
|
||||
protected string cssSelected
|
||||
{
|
||||
get => isSelected ? "table-info" : "";
|
||||
@@ -118,6 +146,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AppMServ.EA_SearchUpdated += AppMServ_EA_SearchUpdated;
|
||||
isSelected = false;
|
||||
}
|
||||
|
||||
@@ -173,5 +202,14 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void AppMServ_EA_SearchUpdated()
|
||||
{
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -59,91 +59,4 @@ else
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
private int _maxSugg = 10;
|
||||
private int _ggPrec = 60;
|
||||
private int idxFaseSel = 0;
|
||||
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<int> ItemSelected { get; set; }
|
||||
[Parameter]
|
||||
public int idxFase
|
||||
{
|
||||
get
|
||||
{
|
||||
return idxFaseSel;
|
||||
}
|
||||
set
|
||||
{
|
||||
idxFaseSel = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int maxSugg
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxSugg;
|
||||
}
|
||||
set
|
||||
{
|
||||
_maxSugg = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
private int ggPrec
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ggPrec;
|
||||
}
|
||||
set
|
||||
{
|
||||
_ggPrec = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
protected List<ParetoRegAttModel>? ListRecords { get; set; } = null;
|
||||
|
||||
protected string cssRiga(int idxFase)
|
||||
{
|
||||
string answ = "";
|
||||
if (idxFase == idxFaseSel)
|
||||
{
|
||||
answ = "bg-info text-light";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await ReloadData();
|
||||
AppMServ.EA_SearchUpdated += OnSearchUpdated;
|
||||
}
|
||||
|
||||
protected void OnSearchUpdated()
|
||||
{
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
|
||||
protected async Task ReloadData()
|
||||
{
|
||||
idxFaseSel = 0;
|
||||
if (AppMServ.IdxDipendente > 0)
|
||||
{
|
||||
ListRecords = await GDataServ.ParetoRegAtt(AppMServ.IdxDipendente, ggPrec, maxSugg);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task SelectRecord(int idxFase)
|
||||
{
|
||||
idxFaseSel = idxFase;
|
||||
await ItemSelected.InvokeAsync(idxFase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
using GPW.CORE.Data.DbModels;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
public partial class ParetoRA : IDisposable
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
[Parameter]
|
||||
public int idxFase
|
||||
{
|
||||
get
|
||||
{
|
||||
return idxFaseSel;
|
||||
}
|
||||
set
|
||||
{
|
||||
idxFaseSel = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<int> ItemSelected { get; set; }
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppMServ.EA_SearchUpdated -= OnSearchUpdated;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected List<ParetoRegAttModel>? ListRecords { get; set; } = null;
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected string cssRiga(int idxFase)
|
||||
{
|
||||
string answ = "";
|
||||
if (idxFase == idxFaseSel)
|
||||
{
|
||||
answ = "bg-info text-light";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await ReloadData();
|
||||
AppMServ.EA_SearchUpdated += OnSearchUpdated;
|
||||
}
|
||||
|
||||
protected void OnSearchUpdated()
|
||||
{
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
|
||||
protected async Task ReloadData()
|
||||
{
|
||||
idxFaseSel = 0;
|
||||
if (AppMServ.IdxDipendente > 0)
|
||||
{
|
||||
ListRecords = await GDataServ.ParetoRegAtt(AppMServ.IdxDipendente, ggPrec, maxSugg);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task SelectRecord(int idxFase)
|
||||
{
|
||||
idxFaseSel = idxFase;
|
||||
await ItemSelected.InvokeAsync(idxFase);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private int _ggPrec = 60;
|
||||
private int _maxSugg = 10;
|
||||
private int idxFaseSel = 0;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private int ggPrec
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ggPrec;
|
||||
}
|
||||
set
|
||||
{
|
||||
_ggPrec = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
private int maxSugg
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxSugg;
|
||||
}
|
||||
set
|
||||
{
|
||||
_maxSugg = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
@inject MessageService AppMServ
|
||||
@inject IJSRuntime JSRuntime
|
||||
|
||||
<div class="py-0 mb-1 flex-fill @blockCss" style="width: @widthPerc; font-size: 0.7em;">
|
||||
<div class="py-0 mb-1 flex-fill @blockCss" style="width: @widthPerc; font-size: @FontSize;">
|
||||
@if (CurrPeriodo.Tipo != CORE.Data.TipoPeriodo.ND)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
[Parameter]
|
||||
public EventCallback<PeriodoDTO> ItemSelected { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public string FontSize { get; set; } = "0.7em";
|
||||
|
||||
private string widthPerc
|
||||
{
|
||||
get
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
@if (CalcOreFasi == null)
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
@if (@CurrData.IdxFase > 0)
|
||||
{
|
||||
<div class="dropdown shadow-lg">
|
||||
<button @onclick="() => Edit()" class="@buttonCss px-1 text-center border border-0 rounded-0 rounded-start btn btn-primary bg-opacity-75 btn-sm py-1 font-monospace2" style="font-size: 0.75rem;" disabled="@(IsClipboard)">
|
||||
<button @onclick="() => Edit()" class="@buttonCss px-1 text-center border border-0 rounded-0 rounded-start @btnClass bg-opacity-75 btn-sm py-1 font-monospace2" style="font-size: @FontSize;" disabled="@(IsClipboard)">
|
||||
@if (@CurrData.OreTot > 1)
|
||||
{
|
||||
<div>@CurrData.Inizio.ToString("HH:mm")</div>
|
||||
@@ -72,7 +72,7 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="px-1 py-0 text-start textTrim flex-fill shadow-lg">
|
||||
<div class="px-1 py-0 text-start textTrim flex-fill shadow @blockClass">
|
||||
<div class="text-dark" title="@CurrData.FasiNav?.ProgettoNav?.ClienteNav?.RagSociale - @CurrData.FasiNav?.ProgettoNav?.NomeProj"><b>@(trimLine($"{CurrData.FasiNav?.ProgettoNav?.ClienteNav?.RagSociale}", 60))</b> @(trimLine($"{CurrData.FasiNav?.ProgettoNav?.NomeProj}", 60))</div>
|
||||
<div class="text-secondary" title="@CurrData.FasiNav?.DescrizioneFase">@(trimLine($"{CurrData.FasiNav?.DescrizioneFase}", 150))</div>
|
||||
<div class="small" title="@CurrData.Descrizione">@(trimLine($"{CurrData.Descrizione}", 200))</div>
|
||||
@@ -80,7 +80,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="px-1 small textTrim py-2">
|
||||
<div class="px-1 small textTrim py-0">
|
||||
<AddRA IdxDip="@IdxDipSel" NewItemCreated="ReportSelect" InizioPer="@CurrData.Inizio" EnableAction="@EnableActionMenu"></AddRA>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -4,89 +4,103 @@ using Microsoft.JSInterop;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
public partial class RegAtt
|
||||
public partial class RegAtt : IDisposable
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
[Parameter]
|
||||
public RegAttivitaModel CurrData { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool EnableActionMenu { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public string FontSize { get; set; } = "0.75em";
|
||||
|
||||
[Parameter]
|
||||
public int IdxDipSel { get; set; } = 0;
|
||||
|
||||
[Parameter]
|
||||
public bool IsClipboard { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemCloned { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemSelected { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemUpdated { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public List<AnagFasiModel> ListFasi { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public int MidHour { get; set; } = 12;
|
||||
|
||||
[Parameter]
|
||||
public double Periodo { get; set; } = 1;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
AppMServ.EA_SearchUpdated -= AppMServ_EA_SearchUpdated;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected bool isSelected = false;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private string blockCss
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = CurrData.IdxFase == 0 ? "" : " bg-body rounded shadow";
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool dropActionTop
|
||||
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = false;
|
||||
switch (CurrData.Inizio.DayOfWeek)
|
||||
{
|
||||
case DayOfWeek.Sunday:
|
||||
case DayOfWeek.Saturday:
|
||||
case DayOfWeek.Friday:
|
||||
answ = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
private bool dropActionLeft
|
||||
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = CurrData.Inizio.Hour >= MidHour ? true : false;
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private string widthPerc
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "1%";
|
||||
if (CurrData != null)
|
||||
{
|
||||
double num = CurrData.OreTot != null ? (double)CurrData.OreTot : 0;
|
||||
answ = $"{num / Periodo:P2}".Replace(",", ".");
|
||||
}
|
||||
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool VetoInsert
|
||||
{
|
||||
get => GDataServ.VetoInsert;
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected string blockClass
|
||||
{
|
||||
get
|
||||
{
|
||||
string btnClass = "";
|
||||
bool highlight = false;
|
||||
// recupero search
|
||||
string SearchVal = AppMServ.SearchVal;
|
||||
// calcolo valore highlight
|
||||
if (!string.IsNullOrEmpty(SearchVal))
|
||||
{
|
||||
highlight = (CurrData.Descrizione.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
btnClass = highlight ? "bg-success bg-opacity-25" : "bg-light";
|
||||
return btnClass;
|
||||
}
|
||||
}
|
||||
|
||||
protected string btnClass
|
||||
{
|
||||
get
|
||||
{
|
||||
string btnClass = "";
|
||||
bool highlight = false;
|
||||
// recupero search
|
||||
string SearchVal = AppMServ.SearchVal;
|
||||
// calcolo valore highlight
|
||||
if (!string.IsNullOrEmpty(SearchVal))
|
||||
{
|
||||
highlight = (CurrData.Descrizione.Contains(SearchVal, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
btnClass = highlight ? "btn btn-success" : "btn btn-primary";
|
||||
return btnClass;
|
||||
}
|
||||
}
|
||||
|
||||
protected string buttonCss
|
||||
{
|
||||
get => !IsClipboard ? "dropbtn" : "";
|
||||
}
|
||||
|
||||
protected string cssSelected
|
||||
{
|
||||
get => isSelected ? "table-info" : "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// definizione CSS posizionale secondo condizioni top/left
|
||||
/// </summary>
|
||||
@@ -107,67 +121,12 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Public Properties
|
||||
|
||||
[Parameter]
|
||||
public RegAttivitaModel CurrData { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public bool EnableActionMenu { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public int IdxDipSel { get; set; } = 0;
|
||||
|
||||
[Parameter]
|
||||
public bool IsClipboard { get; set; } = false;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemCloned { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemSelected { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<RegAttivitaModel> ItemUpdated { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public List<AnagFasiModel> ListFasi { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public double Periodo { get; set; } = 1;
|
||||
|
||||
[Parameter]
|
||||
public int MidHour { get; set; } = 12;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Verifico coerenza date (inizio < fine)
|
||||
/// </summary>
|
||||
/// <param name="modInizio">indica se la data modificata sia l'inizio</param>
|
||||
private void checkCoerenzaDate(bool modInizio)
|
||||
protected string cssSelected
|
||||
{
|
||||
// verifica presenza errori
|
||||
bool inError = CurrData.Inizio >= CurrData.Fine;
|
||||
if (inError)
|
||||
{
|
||||
// se ho mod inizio --> tengo ferma fine, inizio 1/2 h prima
|
||||
if (modInizio)
|
||||
{
|
||||
CurrData.Inizio = CurrData.Fine.AddMinutes(-30);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrData.Fine = CurrData.Inizio.AddMinutes(30);
|
||||
}
|
||||
}
|
||||
get => isSelected ? "table-info" : "";
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
@@ -222,16 +181,13 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
/// </summary>
|
||||
protected async void Edit()
|
||||
{
|
||||
// SOLO SE non � una copia clipboard...
|
||||
//if (!IsClipboard)
|
||||
//{
|
||||
isSelected = true;
|
||||
await ItemSelected.InvokeAsync(CurrData);
|
||||
//}
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
AppMServ.EA_SearchUpdated += AppMServ_EA_SearchUpdated;
|
||||
isSelected = false;
|
||||
}
|
||||
|
||||
@@ -246,8 +202,8 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
/// <summary>
|
||||
/// Trim linea di testo secondo regole
|
||||
/// </summary>
|
||||
/// <param name = "stringOrig">Stringa origiale</param>
|
||||
/// <param name = "multFact">Fattore di moltiplicazione (std: 130)</param>
|
||||
/// <param name="stringOrig">Stringa origiale</param>
|
||||
/// <param name="multFact">Fattore di moltiplicazione (std: 130)</param>
|
||||
/// <returns></returns>
|
||||
protected string trimLine(object stringOrig, int multFact = 130)
|
||||
{
|
||||
@@ -269,5 +225,98 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private string blockCss
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = CurrData.IdxFase == 0 ? "" : " bg-body rounded shadow";
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool dropActionLeft
|
||||
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = CurrData.Inizio.Hour >= MidHour ? true : false;
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool dropActionTop
|
||||
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = false;
|
||||
switch (CurrData.Inizio.DayOfWeek)
|
||||
{
|
||||
case DayOfWeek.Sunday:
|
||||
case DayOfWeek.Saturday:
|
||||
case DayOfWeek.Friday:
|
||||
answ = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
private bool VetoInsert
|
||||
{
|
||||
get => GDataServ.VetoInsert;
|
||||
}
|
||||
|
||||
private string widthPerc
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "1%";
|
||||
if (CurrData != null)
|
||||
{
|
||||
double num = CurrData.OreTot != null ? (double)CurrData.OreTot : 0;
|
||||
answ = $"{num / Periodo:P2}".Replace(",", ".");
|
||||
}
|
||||
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void AppMServ_EA_SearchUpdated()
|
||||
{
|
||||
InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
/// <summary> Verifico coerenza date (inizio < fine) </summary> <param
|
||||
/// name="modInizio">indica se la data modificata sia l'inizio</param>
|
||||
private void checkCoerenzaDate(bool modInizio)
|
||||
{
|
||||
// verifica presenza errori
|
||||
bool inError = CurrData.Inizio >= CurrData.Fine;
|
||||
if (inError)
|
||||
{
|
||||
// se ho mod inizio --> tengo ferma fine, inizio 1/2 h prima
|
||||
if (modInizio)
|
||||
{
|
||||
CurrData.Inizio = CurrData.Fine.AddMinutes(-30);
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrData.Fine = CurrData.Inizio.AddMinutes(30);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -3,52 +3,15 @@ using GPW.CORE.WRKLOG.Data;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Components
|
||||
{
|
||||
public partial class RegAttEditor
|
||||
{
|
||||
#region Protected Fields
|
||||
|
||||
protected string _gruppoSel = "";
|
||||
protected int _idxProj = 0;
|
||||
protected bool vetoUpd = false;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
[Inject]
|
||||
private MessageService AppMServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime JSRuntime { get; set; } = null!;
|
||||
|
||||
private bool VetoInsert
|
||||
{
|
||||
get => GDataServ.VetoInsert;
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected List<AnagFasiModel> fasiList { get; set; } = new List<AnagFasiModel>();
|
||||
|
||||
[Inject]
|
||||
protected GpwDataService GDataServ { get; set; } = null!;
|
||||
|
||||
protected List<AnagGruppiModel> gruppiList { get; set; } = new List<AnagGruppiModel>();
|
||||
protected List<AnagProgettiModel> projList { get; set; } = new List<AnagProgettiModel>();
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Public Properties
|
||||
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
[Parameter]
|
||||
public RegAttivitaModel? currRecord
|
||||
{
|
||||
@@ -74,9 +37,8 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// effettuo selezione manuale...
|
||||
var currFase = await GDataServ.AnagFasiByKey(value.IdxFase);
|
||||
// effettuo selezione manuale...
|
||||
var currFase = await GDataServ.AnagFasiByKey(value.IdxFase);
|
||||
if (currFase != null)
|
||||
{
|
||||
if (currFase.ProgettoNav != null)
|
||||
@@ -117,26 +79,6 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
}
|
||||
|
||||
protected int idxFase
|
||||
{
|
||||
get
|
||||
{
|
||||
int answ = 0;
|
||||
if (currRecord != null)
|
||||
{
|
||||
answ = currRecord.IdxFase;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (currRecord != null)
|
||||
{
|
||||
currRecord.IdxFase = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int idxProj
|
||||
{
|
||||
get
|
||||
@@ -162,47 +104,46 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Methods
|
||||
#region Protected Fields
|
||||
|
||||
private void arrotondaMinuti()
|
||||
{
|
||||
if (currRecord != null)
|
||||
{
|
||||
// arrotondo ai 5 min...
|
||||
currRecord.Inizio = CORE.Data.Utils.DateRounded(currRecord.Inizio.AddMinutes(2), 5, true);
|
||||
// arrotondo ai 5 min...
|
||||
currRecord.Fine = CORE.Data.Utils.DateRounded(currRecord.Fine.AddMinutes(2), 5, true);
|
||||
checkCoerenzaDate(true);
|
||||
}
|
||||
}
|
||||
protected string _gruppoSel = "";
|
||||
protected int _idxProj = 0;
|
||||
protected bool vetoUpd = false;
|
||||
|
||||
/// <summary>
|
||||
/// Verifico coerenza date (inizio < fine)
|
||||
/// </summary>
|
||||
/// <param name="modInizio">indica se la data modificata sia l'inizio</param>
|
||||
private void checkCoerenzaDate(bool modInizio)
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected List<AnagFasiModel> fasiList { get; set; } = new List<AnagFasiModel>();
|
||||
|
||||
[Inject]
|
||||
protected GpwDataService GDataServ { get; set; } = null!;
|
||||
|
||||
protected List<AnagGruppiModel> gruppiList { get; set; } = new List<AnagGruppiModel>();
|
||||
|
||||
protected int idxFase
|
||||
{
|
||||
bool inError = false;
|
||||
// verifica presenza errori
|
||||
if (currRecord != null)
|
||||
get
|
||||
{
|
||||
inError = currRecord.Inizio >= currRecord.Fine;
|
||||
if (inError)
|
||||
int answ = 0;
|
||||
if (currRecord != null)
|
||||
{
|
||||
// se ho mod inizio --> tengo ferma fine, inizio 1/2 h prima
|
||||
if (modInizio)
|
||||
{
|
||||
currRecord.Inizio = currRecord.Fine.AddMinutes(-30);
|
||||
}
|
||||
else
|
||||
{
|
||||
currRecord.Fine = currRecord.Inizio.AddMinutes(30);
|
||||
}
|
||||
answ = currRecord.IdxFase;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (currRecord != null)
|
||||
{
|
||||
currRecord.IdxFase = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
protected List<AnagProgettiModel> projList { get; set; } = new List<AnagProgettiModel>();
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
@@ -251,9 +192,18 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
/// </summary>
|
||||
protected async void DoUpdate()
|
||||
{
|
||||
arrotondaMinuti();
|
||||
bool checkOk = false;
|
||||
checkOk = await arrotondaMinuti();
|
||||
if (checkOk)
|
||||
{
|
||||
checkOk = await checkDayDiff();
|
||||
if (checkOk)
|
||||
{
|
||||
checkOk = await checkDurata();
|
||||
}
|
||||
}
|
||||
// aggiorno
|
||||
if (currRecord != null)
|
||||
if (currRecord != null && checkOk)
|
||||
{
|
||||
// controllo IdxDipendente
|
||||
if (currRecord.IdxDipendente == 0)
|
||||
@@ -314,6 +264,11 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
await ItemUpdated.InvokeAsync(true);
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await initConf();
|
||||
}
|
||||
|
||||
protected async Task ReloadData(bool resetProj, bool resetFase)
|
||||
{
|
||||
gruppiList = await GDataServ.AnagGruppiUser(AppMServ.IdxDipendente);
|
||||
@@ -363,5 +318,167 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private int lapseMinLimit = 1440;
|
||||
|
||||
private int lapseMinWarn = 480;
|
||||
|
||||
private int maxDayDiff = 60;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
[Inject]
|
||||
private MessageService AppMServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
private IJSRuntime JSRuntime { get; set; } = null!;
|
||||
|
||||
private bool VetoInsert
|
||||
{
|
||||
get => GDataServ.VetoInsert;
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private async Task<bool> arrotondaMinuti()
|
||||
{
|
||||
bool answ = false;
|
||||
if (currRecord != null)
|
||||
{
|
||||
// arrotondo ai 5 min...
|
||||
currRecord.Inizio = CORE.Data.Utils.DateRounded(currRecord.Inizio.AddMinutes(2), 5, true);
|
||||
// arrotondo ai 5 min...
|
||||
currRecord.Fine = CORE.Data.Utils.DateRounded(currRecord.Fine.AddMinutes(2), 5, true);
|
||||
answ = await checkCoerenzaDate(true);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary> Verifico coerenza date (inizio < fine) </summary> <param
|
||||
/// name="modInizio">indica se la data modificata sia l'inizio</param>
|
||||
private async Task<bool> checkCoerenzaDate(bool modInizio)
|
||||
{
|
||||
bool inError = false;
|
||||
// verifica presenza errori
|
||||
if (currRecord != null)
|
||||
{
|
||||
inError = currRecord.Inizio >= currRecord.Fine;
|
||||
if (inError)
|
||||
{
|
||||
// chiedo se voglia proseguire...
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"L'inizio dell'attività inserita ({currRecord.Inizio:yyyy-MM-dd HH:mm}) è successivo alla fine dell'attività ({currRecord.Fine:yyyy-MM-dd HH:mm}). Vuoi proseguire correggendo l'inizio attività?"))
|
||||
return false;
|
||||
// se ho mod inizio --> tengo ferma fine, inizio 1/2 h prima
|
||||
if (modInizio)
|
||||
{
|
||||
currRecord.Inizio = currRecord.Fine.AddMinutes(-30);
|
||||
}
|
||||
else
|
||||
{
|
||||
currRecord.Fine = currRecord.Inizio.AddMinutes(30);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica coerenza data inserita/data corrente, altrimenti segnala messaggio e ferma...
|
||||
/// </summary>
|
||||
private async Task<bool> checkDayDiff()
|
||||
{
|
||||
// verifica presenza errori
|
||||
if (currRecord != null)
|
||||
{
|
||||
DateTime oggi = DateTime.Today;
|
||||
// controllo coerenza inizio
|
||||
if (Math.Abs(currRecord.Inizio.Subtract(oggi).TotalDays) > maxDayDiff)
|
||||
{
|
||||
// chiedo se voglia proseguire...
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"L'inizio dell'attività inserita ({currRecord.Inizio:yyyy-MM-dd HH:mm}) supera la soglia di coerenza con la data odierna: Sicuro di voler procedere con la modifica?"))
|
||||
return false;
|
||||
}
|
||||
if (Math.Abs(currRecord.Fine.Subtract(oggi).TotalDays) > maxDayDiff)
|
||||
{
|
||||
// chiedo se voglia proseguire...
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"La fine dell'attività inserita ({currRecord.Fine:yyyy-MM-dd HH:mm}) supera la soglia di coerenza con la data odierna: Sicuro di voler procedere con la modifica?"))
|
||||
return false;
|
||||
}
|
||||
// verifico non siano date future oltre limite di 1 gg..
|
||||
if (currRecord.Inizio.Date > oggi)
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("alert", $"Errore! La data-ora di inizio attività è su una data successiva a quella odierna. Impossibile salvare il record.");
|
||||
return false;
|
||||
}
|
||||
if (currRecord.Fine.Date > oggi.AddDays(1))
|
||||
{
|
||||
await JSRuntime.InvokeVoidAsync("alert", $"Errore! La data-ora di fine attività è oltre il limite consentito. Impossibile salvare il record.");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica coerenza durata evento: se supera soglia warning segnala messaggio, se supera
|
||||
/// soglia limite ferma e basta...
|
||||
/// </summary>
|
||||
private async Task<bool> checkDurata()
|
||||
{
|
||||
// verifica presenza errori
|
||||
if (currRecord != null)
|
||||
{
|
||||
var durata = currRecord.Fine.Subtract(currRecord.Inizio).TotalMinutes;
|
||||
// controllo coerenza inizio
|
||||
if (durata > lapseMinLimit)
|
||||
{
|
||||
// BLOCCO prosecuzione...
|
||||
await JSRuntime.InvokeVoidAsync("alert", $"Errore! La durata dell'attività inserita supera il limite consentito di {lapseMinLimit} minuti. Impossibile salvare il record.");
|
||||
return false;
|
||||
}
|
||||
else if (durata > lapseMinWarn)
|
||||
{
|
||||
// chiedo se voglia proseguire...
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", $"Attenzione! La durata dell'attività inserita supera il limite standard di {lapseMinWarn} minuti. Sicuro di voler procedere con la modifica?"))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// init valori da config
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task initConf()
|
||||
{
|
||||
// leggo conf standard controllo RegAtt
|
||||
var sMaxDayDiff = await GDataServ.ConfigGetKey("maxDayDiffRA");
|
||||
if (sMaxDayDiff != null)
|
||||
{
|
||||
int.TryParse(sMaxDayDiff.valore, out maxDayDiff);
|
||||
}
|
||||
var sLapseMinWarn = await GDataServ.ConfigGetKey("lapseMinWarn");
|
||||
if (sLapseMinWarn != null)
|
||||
{
|
||||
int.TryParse(sLapseMinWarn.valore, out lapseMinWarn);
|
||||
}
|
||||
var sLapseMinLimit = await GDataServ.ConfigGetKey("lapseMinLimit");
|
||||
if (sLapseMinLimit != null)
|
||||
{
|
||||
int.TryParse(sLapseMinLimit.valore, out lapseMinLimit);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,11 @@
|
||||
else
|
||||
{ @if (isSendingData)
|
||||
{
|
||||
<ProgressDisplay Title="Salvataggio ed invio richiesta" CurrVal="@sendDataVal" MaxVal="@sendDataMaxVal" ExpTimeMSec="1000"></ProgressDisplay>
|
||||
<ProgressDisplay Title="Salvataggio ed invio richiesta" CurrVal="@sendDataVal" NextVal="@sendDataNextVal" MaxVal="@sendDataMaxVal" ExpTimeMSec="1000"></ProgressDisplay>
|
||||
}
|
||||
@if (ListRecords == null)
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -6,11 +6,11 @@ else
|
||||
{
|
||||
@if (isSendingData)
|
||||
{
|
||||
<ProgressDisplay Title="Salvataggio ed invio richiesta" CurrVal="@sendDataVal" MaxVal="@sendDataMaxVal" ExpTimeMSec="1000"></ProgressDisplay>
|
||||
<ProgressDisplay Title="Salvataggio ed invio richiesta" CurrVal="@sendDataVal" NextVal="@sendDataNextVal" MaxVal="@sendDataMaxVal" ExpTimeMSec="1000"></ProgressDisplay>
|
||||
}
|
||||
@if (ListRecords == null)
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
protected MessageService AppMServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected GpwDataService DataService { get; set; } = null!;
|
||||
protected GpwDataService GDataServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
||||
@@ -67,7 +67,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
dtFine = dtInizio.AddYears(2);
|
||||
currRecord.IdxDipendente = AppMServ.IdxDipendente;
|
||||
CodGiust = "";
|
||||
var rawGiust = await DataService.AnagGiust();
|
||||
var rawGiust = await GDataServ.AnagGiust();
|
||||
if (rawGiust != null)
|
||||
{
|
||||
ListGiust = rawGiust.Where(x => x.showReq).ToList();
|
||||
@@ -185,7 +185,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
await Task.Delay(1);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
var updTask = Task.Run(async () =>
|
||||
await DataService.RegRichiesteDelete(selItem)
|
||||
await GDataServ.RegRichiesteDelete(selItem)
|
||||
);
|
||||
await updTask;
|
||||
sendDataVal = 100;
|
||||
@@ -209,12 +209,12 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
private async Task initConf()
|
||||
{
|
||||
// leggo conf standard giorni permessi/ferie
|
||||
var sNumDayFerieRichAntic = await DataService.ConfigGetKey("NumDayFerieRichAntic");
|
||||
var sNumDayFerieRichAntic = await GDataServ.ConfigGetKey("NumDayFerieRichAntic");
|
||||
if (sNumDayFerieRichAntic != null)
|
||||
{
|
||||
int.TryParse(sNumDayFerieRichAntic.valore, out NumDayFerieRichAntic);
|
||||
}
|
||||
var sNumDayPermMax = await DataService.ConfigGetKey("NumDayPermMax");
|
||||
var sNumDayPermMax = await GDataServ.ConfigGetKey("NumDayPermMax");
|
||||
if (sNumDayPermMax != null)
|
||||
{
|
||||
int.TryParse(sNumDayPermMax.valore, out NumDayPermMax);
|
||||
@@ -257,7 +257,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
sendDataNextVal = 90;
|
||||
await Task.Delay(1);
|
||||
var updTask = Task.Run(async () =>
|
||||
await DataService.RegRichiesteUpsert(currRecord)
|
||||
await GDataServ.RegRichiesteUpsert(currRecord)
|
||||
);
|
||||
await updTask;
|
||||
// effettuo insert...
|
||||
@@ -311,7 +311,7 @@ namespace GPW.CORE.WRKLOG.Components
|
||||
ListRecords = null;
|
||||
await initConf();
|
||||
await Task.Delay(1);
|
||||
ListRecords = await DataService.RegRichiesteGetByDip(AppMServ.IdxDipendente, dtInizio, dtFine);
|
||||
ListRecords = await GDataServ.RegRichiesteGetByDip(AppMServ.IdxDipendente, dtInizio, dtFine);
|
||||
}
|
||||
|
||||
private async Task toggleAddNew()
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,7 +79,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EgwCoreLib.Utils;
|
||||
using GPW.CORE.Data;
|
||||
using GPW.CORE.Data.DbModels;
|
||||
using GPW.CORE.Data.DTO;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
@@ -51,6 +52,11 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
{
|
||||
dbController = new CORE.Data.Controllers.GPWController(configuration);
|
||||
}
|
||||
|
||||
// init datapipe...
|
||||
mPipeTimb = new MessagePipe(redisConn, Const.rPipeChTimb);
|
||||
mPipeRich = new MessagePipe(redisConn, Const.rPipeChRich);
|
||||
|
||||
_logger.LogInformation("Avviata classe GpwDataService");
|
||||
}
|
||||
|
||||
@@ -60,6 +66,16 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
|
||||
public string CodApp { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Pipe messaggi richieste
|
||||
/// </summary>
|
||||
public MessagePipe mPipeRich { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe messaggi timbrature
|
||||
/// </summary>
|
||||
public MessagePipe mPipeTimb { get; set; } = null!;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
@@ -711,12 +727,99 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
return await Task.FromResult(keyResult);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco dei dettaglio giornaliero attività di tutti i dipendenti, dato giorno riferimento
|
||||
/// </summary>
|
||||
/// <param name="dtRif">Data di riferimento</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<DailyDataDTO>> DailyDetailAllDip(DateTime dtRif)
|
||||
{
|
||||
string source = "DB";
|
||||
List<DailyDataDTO>? dbResult = new List<DailyDataDTO>();
|
||||
string currKey = $"{rKeyDailyData}:ALL:{dtRif.ToString("yyyy-MM-dd")}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<DailyDataDTO>>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dbResult = new List<DailyDataDTO>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = dbController.DailyDetailAllDip(dtRif);
|
||||
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, FastCache);
|
||||
}
|
||||
if (dbResult == null)
|
||||
{
|
||||
dbResult = new List<DailyDataDTO>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"DailyDetailAllDip | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco delle ultime attività inserite da un dipendente
|
||||
/// </summary>
|
||||
/// <param name="idxDipendente">Dipendente interessato</param>
|
||||
/// <param name="numRec">Num record da recuperare</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<RegAttivitaModel>> UserLastRec(int idxDipendente, int numRec)
|
||||
{
|
||||
string source = "DB";
|
||||
DateTime oggi = DateTime.Today;
|
||||
List<RegAttivitaModel>? dbResult = new List<RegAttivitaModel>();
|
||||
string currKey = $"{rKeyLastRegAtt}:{idxDipendente}:{oggi.ToString("yyyy-MM-dd")}:{numRec}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<RegAttivitaModel>>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dbResult = new List<RegAttivitaModel>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = dbController.UserLastRec(idxDipendente, numRec);
|
||||
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, FastCache);
|
||||
}
|
||||
if (dbResult == null)
|
||||
{
|
||||
dbResult = new List<RegAttivitaModel>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"UserLastRec | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera l'elenco dei dettagli giornalieri attività di un dipendente, dato periodo riferimento
|
||||
/// </summary>
|
||||
/// <param name="idxDipendente">Dipendente interessato</param>
|
||||
/// <param name="dtInizio">Data di riferimento (ultima/corrente)</param>
|
||||
/// <param name="dtFine">NUm settimane precedenti da recuperare</param>
|
||||
/// <param name="dtInizio">Data inizio periodo</param>
|
||||
/// <param name="dtFine">Data fine periodo</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<DailyDataDTO>> DailyDetails(int idxDipendente, DateTime dtInizio, DateTime dtFine)
|
||||
{
|
||||
@@ -907,6 +1010,48 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Righe presenze giornaliere
|
||||
/// </summary>
|
||||
/// <param name="dtRif">DataOra riferimento per richiesta presenze</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<StatsDayPresModel>> PresenzeDay(DateTime dtRif)
|
||||
{
|
||||
string source = "DB";
|
||||
List<StatsDayPresModel> dbResult = new List<StatsDayPresModel>();
|
||||
string currKey = $"{rKeyStatPresDay}:{dtRif:yyyy-MM-dd}";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
string? rawData = await redisDb.StringGetAsync(currKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
source = "REDIS";
|
||||
var tempResult = JsonConvert.DeserializeObject<List<StatsDayPresModel>>(rawData);
|
||||
if (tempResult == null)
|
||||
{
|
||||
dbResult = new List<StatsDayPresModel>();
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = tempResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dbResult = dbController.PresenzeDay(dtRif);
|
||||
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
||||
await redisDb.StringSetAsync(currKey, rawData, FastCache);
|
||||
}
|
||||
if (dbResult == null)
|
||||
{
|
||||
dbResult = new List<StatsDayPresModel>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"PresenzeDay | {source} in: {ts.TotalMilliseconds} ms");
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
public async Task<bool> RegAttDelete(RegAttivitaModel currItem)
|
||||
{
|
||||
bool answ = false;
|
||||
@@ -915,6 +1060,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
dbController.RegAttDelete(currItem);
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyLastRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyParetoRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyWeekStats}:*");
|
||||
answ = true;
|
||||
@@ -945,6 +1091,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
dbController.RegAttUpdate(currItem);
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyLastRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyParetoRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyWeekStats}:*");
|
||||
answ = true;
|
||||
@@ -967,8 +1114,19 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
answ = dbController.RegMalattieDelete(currItem);
|
||||
if (answ)
|
||||
{
|
||||
// recupero info dipendente
|
||||
var listDip = await DipendentiGetAll();
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoMal"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkMal"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1099,6 +1257,14 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoMal"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkMal"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1138,8 +1304,19 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
answ = dbController.RegRichiesteDelete(currItem);
|
||||
if (answ)
|
||||
{
|
||||
// recupero info dipendente
|
||||
var listDip = await DipendentiGetAll();
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoRich"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkRich"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1161,6 +1338,9 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyDipendenti}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyLastRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyParetoRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyWeekStats}:*");
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
@@ -1230,6 +1410,14 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
var currDip = listDip.FirstOrDefault(x => x.IdxDipendente == currItem.IdxDipendente);
|
||||
// gestisco email notifica...
|
||||
string emailDest = _configuration["MailDest:InfoRich"];
|
||||
if (currDip.idxResp > 0)
|
||||
{
|
||||
string mailResp = await emailResp(currDip.idxResp);
|
||||
if (!string.IsNullOrEmpty(mailResp) && !emailDest.Contains(mailResp))
|
||||
{
|
||||
emailDest += $",{mailResp}";
|
||||
}
|
||||
}
|
||||
string urlRedir = _configuration["AdmApp:LinkRich"];
|
||||
StringBuilder sbMain = new StringBuilder();
|
||||
DateTime adesso = DateTime.Now;
|
||||
@@ -1251,6 +1439,9 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyDipendenti}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyLastRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyParetoRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyWeekStats}:*");
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
@@ -1370,6 +1561,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
// invalido la cache...
|
||||
await ExecFlushRedisPattern($"{rKeyRilTemp}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyDailyData}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyLastRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyParetoRegAtt}:*");
|
||||
await ExecFlushRedisPattern($"{rKeyWeekStats}:*");
|
||||
answ = true;
|
||||
@@ -1438,6 +1630,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
#region Protected Fields
|
||||
|
||||
protected const string passPhrase = "6E1DA6B4-4647-4578-AB4F-01360E2B7E68";
|
||||
|
||||
protected const string redisBaseAddr = "WrkLog";
|
||||
|
||||
protected const string rKeyAKV = $"{redisBaseAddr}:Cache:AKV";
|
||||
@@ -1455,19 +1648,33 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
protected const string rKeyConfig = $"{redisBaseAddr}:Cache:Config";
|
||||
|
||||
protected const string rKeyDailyData = $"{redisBaseAddr}:Cache:DailyData";
|
||||
|
||||
protected const string rKeyLastRegAtt = $"{redisBaseAddr}:Cache:LastRegAtt";
|
||||
|
||||
protected const string rKeyDipendenti = $"{redisBaseAddr}:Cache:Dipendenti";
|
||||
|
||||
protected const string rKeyFasiAll = $"{redisBaseAddr}:Cache:FasiAll";
|
||||
|
||||
protected const string rKeyFasiByProj = $"{redisBaseAddr}:Cache:FasiByProj";
|
||||
|
||||
protected const string rKeyFasiSearch = $"{redisBaseAddr}:Cache:FasiSearch";
|
||||
|
||||
protected const string rKeyGiust = $"{redisBaseAddr}:Cache:Giustif";
|
||||
|
||||
protected const string rKeyGrpAll = $"{redisBaseAddr}:Cache:GrpAll";
|
||||
|
||||
protected const string rKeyGrpUser = $"{redisBaseAddr}:Cache:GrpUser";
|
||||
|
||||
protected const string rKeyParetoRegAtt = $"{redisBaseAddr}:Cache:ParetoRegAtt";
|
||||
|
||||
protected const string rKeyProjAll = $"{redisBaseAddr}:Cache:ProjAll";
|
||||
|
||||
protected const string rKeyReportData = $"{redisBaseAddr}:Cache:ReportData";
|
||||
|
||||
protected const string rKeyRilTemp = $"{redisBaseAddr}:Cache:RilTemp";
|
||||
|
||||
protected const string rKeyStatPresDay = $"{redisBaseAddr}:Cache:StatPresDay";
|
||||
|
||||
protected const string rKeyVC19 = $"{redisBaseAddr}:Cache:VC19";
|
||||
|
||||
protected const string rKeyVetoIns = $"{redisBaseAddr}:Cache:VetoInsert";
|
||||
@@ -1482,6 +1689,27 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calcola email del responsabile dato idx
|
||||
/// </summary>
|
||||
/// <param name="idxResp"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<string> emailResp(int idxResp)
|
||||
{
|
||||
string answ = "";
|
||||
var listDip = await DipendentiGetAll();
|
||||
// recupero email resp...
|
||||
if (idxResp > 0)
|
||||
{
|
||||
var recResp = listDip.FirstOrDefault(x => x.IdxDipendente == idxResp);
|
||||
if (recResp != null)
|
||||
{
|
||||
answ = $"{recResp.Email}";
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invio email tramite libreria
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@ using GPW.CORE.Data.DbModels;
|
||||
using Microsoft.Extensions.Caching.Distributed;
|
||||
using Newtonsoft.Json;
|
||||
using RestSharp;
|
||||
using StackExchange.Redis;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
||||
@@ -13,50 +14,6 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
/// </summary>
|
||||
public class LicenseService
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private static IConfiguration? _configuration;
|
||||
private static ILogger<LicenseService>? _logger;
|
||||
|
||||
/// <summary>
|
||||
/// URL dell'API x chiamate gestione licenze
|
||||
/// </summary>
|
||||
private static string apiUrl = "https://liman.egalware.com/ELM.API/";
|
||||
|
||||
private readonly IDistributedCache distributedCache;
|
||||
|
||||
/// <summary>
|
||||
/// Elenco obj in cache
|
||||
/// </summary>
|
||||
private List<string> cachedDataList = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Fattorte conversione cache sliding --> 1 h
|
||||
/// </summary>
|
||||
private int cacheFact = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Durata assoluta massima della cache IN SECONDI
|
||||
/// </summary>
|
||||
private int chAbsExp = 60 * 5;
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire rimossa
|
||||
/// NON estende oltre il tempo massimo di validità della cache (cacheTtlLong)
|
||||
/// </summary>
|
||||
private int chSliExp = 60 * 1;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Chiave redis x attivazioni della licenza
|
||||
/// </summary>
|
||||
protected const string rKeyAttByLic = "LongCache:AttByLic";
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -83,9 +40,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
#region Public Properties
|
||||
|
||||
public List<LiManObj.AttivazioneDTO> ActivList { get; set; } = new List<LiManObj.AttivazioneDTO>();
|
||||
|
||||
public List<AnagKeyValueModel> AKVList { get; set; } = new List<AnagKeyValueModel>();
|
||||
|
||||
public string Applicazione { get; set; } = "";
|
||||
|
||||
public bool HasActivData
|
||||
@@ -114,9 +69,7 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
}
|
||||
|
||||
public DateTime infoExpiry { get; set; } = DateTime.Today.AddDays(1);
|
||||
|
||||
public string Installazione { get; set; } = "";
|
||||
|
||||
public string MasterKey { get; set; } = "";
|
||||
|
||||
public bool ValidData
|
||||
@@ -131,51 +84,102 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Methods
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Opzioni cache con moltiplicatore durata risp durata base (1/5 minuti)
|
||||
/// </summary>
|
||||
/// <param name="multFact"></param>
|
||||
/// <returns></returns>
|
||||
private DistributedCacheEntryOptions cacheOpt(int multFact)
|
||||
public async Task<List<LiManObj.AttivazioneDTO>> ActivListCache()
|
||||
{
|
||||
var numSecAbsExp = chAbsExp * multFact;
|
||||
var numSecSliExp = chSliExp * multFact;
|
||||
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco attivazioni attuali
|
||||
/// </summary>
|
||||
private async Task<List<LiManObj.AttivazioneDTO>?> OnlineActivationList()
|
||||
{
|
||||
List<LiManObj.AttivazioneDTO>? answ = new List<LiManObj.AttivazioneDTO>();
|
||||
// cerco online
|
||||
RestClient client = new RestClient(apiUrl);
|
||||
//client.Authenticator = new HttpBasicAuthenticator("username", "password");
|
||||
string MKeyEnc = HttpUtility.UrlEncode(MasterKey);
|
||||
var request = new RestRequest($"/api/attivazioni/?chiave={MKeyEnc}", Method.Get);
|
||||
var response = await client.GetAsync(request);
|
||||
// controllo risposta
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||
List<LiManObj.AttivazioneDTO> dbResult = new List<LiManObj.AttivazioneDTO>();
|
||||
string cacheKey = $"{rKeyAttByLic}:{MasterKey}";
|
||||
trackCache(cacheKey);
|
||||
string rawData = await getRSV(cacheKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
// salvo in redis contenuto serializzato
|
||||
string rawData = $"{response.Content}";
|
||||
answ = JsonConvert.DeserializeObject<List<LiManObj.AttivazioneDTO>?>(rawData);
|
||||
var cacheRes = JsonConvert.DeserializeObject<List<LiManObj.AttivazioneDTO>?>(rawData);
|
||||
if (cacheRes != null)
|
||||
{
|
||||
dbResult = cacheRes;
|
||||
}
|
||||
}
|
||||
return await Task.FromResult(answ);
|
||||
|
||||
return await Task.FromResult(dbResult);
|
||||
}
|
||||
|
||||
private void ReportUpdated()
|
||||
/// <summary>
|
||||
/// Init della classe con variabili di base da Redis/DB
|
||||
/// </summary>
|
||||
public bool InitAkv()
|
||||
{
|
||||
bool fatto = false;
|
||||
Installazione = getAVKStr("installazione");
|
||||
MasterKey = getAVKStr(Installazione);
|
||||
fatto = !string.IsNullOrEmpty($"{Installazione}{MasterKey}");
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init della classe con variabili di base da Redis/DB
|
||||
/// </summary>
|
||||
public async Task<bool> RefreshLicense()
|
||||
{
|
||||
bool fatto = false;
|
||||
var onlineAct = await OnlineActivationList();
|
||||
if (onlineAct != null)
|
||||
{
|
||||
if (onlineAct.Count > 0)
|
||||
{
|
||||
// scadenza info a 15 gg...
|
||||
int numDays = 15;
|
||||
infoExpiry = DateTime.Now.AddDays(numDays);
|
||||
ActivList = onlineAct;
|
||||
fatto = await setActivList(onlineAct, numDays);
|
||||
}
|
||||
}
|
||||
await Task.Delay(1);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
public async Task<bool> resetActivList()
|
||||
{
|
||||
await Task.Delay(1);
|
||||
string cacheKey = $"{rKeyAttByLic}:{MasterKey}";
|
||||
bool answ = false;
|
||||
try
|
||||
{
|
||||
await distributedCache.RemoveAsync(cacheKey);
|
||||
if (EA_InfoUpdated != null)
|
||||
{
|
||||
EA_InfoUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
|
||||
public async Task<bool> setActivList(List<LiManObj.AttivazioneDTO> newActList, int numDays)
|
||||
{
|
||||
bool fatto = false;
|
||||
string cacheKey = $"{rKeyAttByLic}:{MasterKey}";
|
||||
var rawData = JsonConvert.SerializeObject(newActList);
|
||||
await setRSV(cacheKey, rawData, numDays * cacheFact * 24);
|
||||
fatto = true;
|
||||
if (EA_InfoUpdated != null)
|
||||
{
|
||||
EA_InfoUpdated?.Invoke();
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Chiave redis x attivazioni della licenza
|
||||
/// </summary>
|
||||
protected const string rKeyAttByLic = "LongCache:AttByLic";
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
@@ -260,74 +264,85 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Public Methods
|
||||
#region Private Fields
|
||||
|
||||
public async Task<List<LiManObj.AttivazioneDTO>> ActivListCache()
|
||||
private static IConfiguration? _configuration;
|
||||
private static ILogger<LicenseService>? _logger;
|
||||
|
||||
/// <summary>
|
||||
/// URL dell'API x chiamate gestione licenze
|
||||
/// </summary>
|
||||
private static string apiUrl = "https://liman.egalware.com/ELM.API/";
|
||||
|
||||
private readonly IDistributedCache distributedCache;
|
||||
|
||||
/// <summary>
|
||||
/// Elenco obj in cache
|
||||
/// </summary>
|
||||
private List<string> cachedDataList = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// Fattorte conversione cache sliding --> 1 h
|
||||
/// </summary>
|
||||
private int cacheFact = 12;
|
||||
|
||||
/// <summary>
|
||||
/// Durata assoluta massima della cache IN SECONDI
|
||||
/// </summary>
|
||||
private int chAbsExp = 60 * 5;
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire
|
||||
/// rimossa NON estende oltre il tempo massimo di validità della cache (cacheTtlLong)
|
||||
/// </summary>
|
||||
private int chSliExp = 60 * 1;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Opzioni cache con moltiplicatore durata risp durata base (1/5 minuti)
|
||||
/// </summary>
|
||||
/// <param name="multFact"></param>
|
||||
/// <returns></returns>
|
||||
private DistributedCacheEntryOptions cacheOpt(int multFact)
|
||||
{
|
||||
List<LiManObj.AttivazioneDTO> dbResult = new List<LiManObj.AttivazioneDTO>();
|
||||
string cacheKey = $"{rKeyAttByLic}:{MasterKey}";
|
||||
trackCache(cacheKey);
|
||||
string rawData = await getRSV(cacheKey);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
var cacheRes = JsonConvert.DeserializeObject<List<LiManObj.AttivazioneDTO>?>(rawData);
|
||||
if (cacheRes != null)
|
||||
{
|
||||
dbResult = cacheRes;
|
||||
}
|
||||
}
|
||||
|
||||
return await Task.FromResult(dbResult);
|
||||
var numSecAbsExp = chAbsExp * multFact;
|
||||
var numSecSliExp = chSliExp * multFact;
|
||||
return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init della classe con variabili di base da Redis/DB
|
||||
/// Elenco attivazioni attuali
|
||||
/// </summary>
|
||||
public bool InitAkv()
|
||||
private async Task<List<LiManObj.AttivazioneDTO>?> OnlineActivationList()
|
||||
{
|
||||
bool fatto = false;
|
||||
Installazione = getAVKStr("installazione");
|
||||
MasterKey = getAVKStr(Installazione);
|
||||
fatto = !string.IsNullOrEmpty($"{Installazione}{MasterKey}");
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Init della classe con variabili di base da Redis/DB
|
||||
/// </summary>
|
||||
public async Task<bool> RefreshLicense()
|
||||
{
|
||||
bool fatto = false;
|
||||
var onlineAct = await OnlineActivationList();
|
||||
if (onlineAct != null)
|
||||
List<LiManObj.AttivazioneDTO>? answ = new List<LiManObj.AttivazioneDTO>();
|
||||
// cerco online
|
||||
RestClient client = new RestClient(apiUrl);
|
||||
//client.Authenticator = new HttpBasicAuthenticator("username", "password");
|
||||
string MKeyEnc = HttpUtility.UrlEncode(MasterKey);
|
||||
var request = new RestRequest($"/api/attivazioni/?chiave={MKeyEnc}", Method.Get);
|
||||
var response = await client.GetAsync(request);
|
||||
// controllo risposta
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
if (onlineAct.Count > 0)
|
||||
{
|
||||
// scadenza info a 15 gg...
|
||||
int numDays = 15;
|
||||
infoExpiry = DateTime.Now.AddDays(numDays);
|
||||
ActivList = onlineAct;
|
||||
fatto = await setActivList(onlineAct, numDays);
|
||||
}
|
||||
// salvo in redis contenuto serializzato
|
||||
string rawData = $"{response.Content}";
|
||||
answ = JsonConvert.DeserializeObject<List<LiManObj.AttivazioneDTO>?>(rawData);
|
||||
}
|
||||
await Task.Delay(1);
|
||||
return fatto;
|
||||
return await Task.FromResult(answ);
|
||||
}
|
||||
|
||||
public async Task<bool> setActivList(List<LiManObj.AttivazioneDTO> newActList, int numDays)
|
||||
private void ReportUpdated()
|
||||
{
|
||||
bool fatto = false;
|
||||
string cacheKey = $"{rKeyAttByLic}:{MasterKey}";
|
||||
var rawData = JsonConvert.SerializeObject(newActList);
|
||||
await setRSV(cacheKey, rawData, numDays * cacheFact * 24);
|
||||
fatto = true;
|
||||
if (EA_InfoUpdated != null)
|
||||
{
|
||||
EA_InfoUpdated?.Invoke();
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -189,13 +189,15 @@ namespace GPW.CORE.WRKLOG.Data
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
private void ReportSearch()
|
||||
{
|
||||
if (EA_SearchUpdated != null)
|
||||
{
|
||||
EA_SearchUpdated?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Version>3.0.2312.0618</Version>
|
||||
<Version>3.0.2408.1910</Version>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
@@ -32,14 +32,14 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BlazorCalendar" Version="2.5.3" />
|
||||
<PackageReference Include="EgwCoreLib.Razor" Version="1.4.2307.3111" />
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.4.2307.3111" />
|
||||
<PackageReference Include="EgwCoreLib.Razor" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="EgwCoreLib.Utils" Version="1.5.2402.2411" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="6.0.14" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="6.0.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="NLog" Version="5.2.2" />
|
||||
<PackageReference Include="RestSharp" Version="108.0.3" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.6.96" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.7.27" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
@page "/ActHistory"
|
||||
@attribute [Authorize]
|
||||
@using GPW.CORE.WRKLOG.Components
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header table-primary py-1">
|
||||
<div class="row">
|
||||
<div class="col-8 col-lg-9 text-start">
|
||||
<h2><i class="fas fa-home"></i> Last Activity Inserted</h2>
|
||||
</div>
|
||||
<div class="col-4 col-lg-3 text-end">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text">Mostra Ultimi</span>
|
||||
<input type="text" class="form-control" @bind="@numRecLast" />
|
||||
<span class="input-group-text">record</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@if (ListRecords == null || isLoading)
|
||||
{
|
||||
<LoadingData></LoadingData>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
@foreach (var item in ListRecords)
|
||||
{
|
||||
<div class="@getItemCss(item)">
|
||||
<DettAtt CurrData="item" Periodo="@(item.Durata.TotalHours)" ListFasi="@ListFasi" IdxDipSel="@IdxDipendente" ItemSelected="ReportSelected" ItemDeleted="() => ReportDeleted()" MaxChar="@MaxChar" ShowDate="true"></DettAtt>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer py-1">
|
||||
<EgwCoreLib.Razor.DataPager PageSize="@numRecord" currPage="@currPage" numRecordChanged="SetNumRec" numPageChanged="SetPage" totalCount="@numRecLast" showLoading="@isLoading"></EgwCoreLib.Razor.DataPager>
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="py-1 px-2">
|
||||
<span>@lastRefresh.ToString("HH:mm:ss")</span> <i class="far fa-clock"></i>
|
||||
</div>
|
||||
<div class="py-1 px-2">
|
||||
@if (clonedRA != null)
|
||||
{
|
||||
<div class="d-flex">
|
||||
<div class="px-2 flex-grow-1">
|
||||
<RegAtt CurrData="@clonedRA" Periodo="@periodoClonato" ListFasi="@ListFasi" ItemSelected="ReportSelect" IdxDipSel="@IdxDipendente" IsClipboard="true"></RegAtt>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<button class="btn w-100 btn-warning" @onclick="ResetClone" title="Reset Clipboard">
|
||||
<i class="fas fa-clipboard"></i><br>
|
||||
<i class="far fa-times-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="my-4"> </div>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
using GPW.CORE.Data;
|
||||
using GPW.CORE.Data.DbModels;
|
||||
using GPW.CORE.Data.DTO;
|
||||
using GPW.CORE.WRKLOG.Data;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Pages
|
||||
{
|
||||
/// <summary>
|
||||
/// Gestione pagina principale del planner
|
||||
///
|
||||
/// modale: vedere qui: https://gist.github.com/conficient/ba98d1662c659e170ec16650acea05c8
|
||||
/// </summary>
|
||||
//[Authorize(Roles = "SuperAdmin, Admin")]
|
||||
public partial class ActHistory : IDisposable
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
public int MaxChar { get; set; } = 30;
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UITimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected DateTime lastRefresh = DateTime.Now;
|
||||
|
||||
protected int numRecLast = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Timer per refresh dati
|
||||
///
|
||||
/// https://stackoverflow.com/questions/63060065/blazor-timer-call-async-api-task-to-update-ui https://www.janduniec.blog/index.php/100/timers-in-blazor/
|
||||
/// </summary>
|
||||
protected System.Timers.Timer UITimer = new System.Timers.Timer();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected string actionCss
|
||||
{
|
||||
get => isLoading ? "disabled" : "";
|
||||
}
|
||||
|
||||
[Inject]
|
||||
protected MessageService AppMServ { get; set; } = null!;
|
||||
|
||||
protected RegAttivitaModel? clonedRA
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppMServ.clonedRA;
|
||||
}
|
||||
set
|
||||
{
|
||||
AppMServ.clonedRA = value;
|
||||
}
|
||||
}
|
||||
|
||||
[Inject]
|
||||
protected GpwDataService DataService { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Dipendente corrente
|
||||
/// </summary>
|
||||
protected int IdxDipendente
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppMServ.IdxDipendente;
|
||||
}
|
||||
}
|
||||
|
||||
[Inject]
|
||||
protected IJSRuntime JSRuntime { get; set; } = null!;
|
||||
|
||||
protected List<AnagFasiModel> ListFasi { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected NavigationManager NavManager { get; set; } = null!;
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected string getItemCss(RegAttivitaModel itemRecord)
|
||||
{
|
||||
string answ = "";
|
||||
if (currRecord != null)
|
||||
{
|
||||
if (itemRecord.Equals(currRecord))
|
||||
{
|
||||
answ = "bg-info bg-opacity-25";
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ListRecords = null;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await Task.Delay(1);
|
||||
|
||||
await TryReload();
|
||||
// avvio un timer infinito x refresh pagina COMUNQUE ogni 60 sec anche non succedesse nulla...
|
||||
UITimer = new System.Timers.Timer
|
||||
{
|
||||
Interval = 1000 * 60,
|
||||
AutoReset = true,
|
||||
Enabled = true
|
||||
};
|
||||
UITimer.Elapsed += async (s, ea) => await TryReload();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indico item selezionato
|
||||
/// </summary>
|
||||
protected async void ReportDeleted()
|
||||
{
|
||||
isLoading = true;
|
||||
currRecord = null;
|
||||
await InvokeAsync(ReloadData);
|
||||
await Task.Delay(50);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indico item selezionato
|
||||
/// </summary>
|
||||
protected void ReportSelect(RegAttivitaModel selRecord)
|
||||
{
|
||||
//selPeriod = false;
|
||||
// recupero attivita selezionata in curr record
|
||||
currRecord = selRecord;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indico item selezionato
|
||||
/// </summary>
|
||||
protected async void ReportSelected(RegAttivitaModel selRecord)
|
||||
{
|
||||
currRecord = selRecord;
|
||||
await Task.Delay(1);
|
||||
//await InvokeAsync(ReloadData);
|
||||
}
|
||||
|
||||
protected void ResetClone()
|
||||
{
|
||||
clonedRA = null;
|
||||
}
|
||||
|
||||
protected async Task SetNumRec(int newNum)
|
||||
{
|
||||
numRecord = newNum;
|
||||
currPage = 1;
|
||||
await InvokeAsync(ReloadData);
|
||||
}
|
||||
|
||||
protected async Task SetPage(int newNum)
|
||||
{
|
||||
currPage = newNum;
|
||||
await InvokeAsync(ReloadData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gestione refresh condizionale
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task TryReload()
|
||||
{
|
||||
await Task.Delay(1);
|
||||
await ReloadData();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private RegAttivitaModel? currRecord = null;
|
||||
private List<RegAttivitaModel>? ListRecords = null;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private int currPage { get; set; } = 1;
|
||||
private bool isLoading { get; set; } = false;
|
||||
private int numRecord { get; set; } = 5;
|
||||
|
||||
private double periodoClonato
|
||||
{
|
||||
get
|
||||
{
|
||||
double answ = 8;
|
||||
// se ho record clonato --> uso quello
|
||||
if (clonedRA != null)
|
||||
{
|
||||
answ = clonedRA.Durata.TotalHours;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private string ConvOre(double oreComm)
|
||||
{
|
||||
TimeSpan tSpan = TimeSpan.FromHours(oreComm);
|
||||
return $"{tSpan.Hours}h {tSpan.Minutes}'";
|
||||
}
|
||||
|
||||
private double oreLav(DailyDataDTO DayDTO)
|
||||
{
|
||||
double answ = 0;
|
||||
if (DayDTO != null && DayDTO.TimbrExpl != null && DayDTO.TimbrExpl.HLav != null)
|
||||
{
|
||||
answ = (double)DayDTO.TimbrExpl.HLav;
|
||||
if (DayDTO.DtRif == DateTime.Today)
|
||||
{
|
||||
if (DayDTO.ListTimbr != null)
|
||||
{
|
||||
// aggiungo ultima timb fino ad adesso...
|
||||
var lastIn = DayDTO.ListTimbr.Where(x => x.Entrata == true).OrderByDescending(x => x.DataOra).FirstOrDefault();
|
||||
var lastOut = DayDTO.ListTimbr.Where(x => x.Entrata == false).OrderByDescending(x => x.DataOra).FirstOrDefault();
|
||||
// se MANCA timb uscita finale...
|
||||
if (lastIn != null)
|
||||
{
|
||||
if (lastOut == null || lastOut.DataOra < lastIn.DataOra)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
answ += adesso.Subtract(lastIn.DataOra).TotalHours;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
private async Task ReloadData()
|
||||
{
|
||||
isLoading = true;
|
||||
UITimer.Stop();
|
||||
var searcRecords = await DataService.UserLastRec(IdxDipendente, numRecLast);
|
||||
ListRecords = searcRecords
|
||||
.Skip((currPage - 1) * numRecord)
|
||||
.Take(numRecord)
|
||||
.ToList();
|
||||
lastRefresh = DateTime.Now;
|
||||
UITimer.Start();
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
@page "/ListPlan"
|
||||
@page "/DayList"
|
||||
@attribute [Authorize]
|
||||
@using GPW.CORE.WRKLOG.Components
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingDataSmall></LoadingDataSmall>
|
||||
<LoadingData DisplaySize="LoadingData.CtrlSize.Small"></LoadingData>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -13,7 +13,7 @@ namespace GPW.CORE.WRKLOG.Pages
|
||||
/// modale: vedere qui: https://gist.github.com/conficient/ba98d1662c659e170ec16650acea05c8
|
||||
/// </summary>
|
||||
//[Authorize(Roles = "SuperAdmin, Admin")]
|
||||
public partial class ListPlan : IDisposable
|
||||
public partial class DayList : IDisposable
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
@@ -246,13 +246,6 @@ namespace GPW.CORE.WRKLOG.Pages
|
||||
Enabled = true
|
||||
};
|
||||
UITimer.Elapsed += async (s, ea) => await TryReload();
|
||||
AppMServ.EA_SearchUpdated += OnSearchUpdated;
|
||||
}
|
||||
|
||||
protected void OnSearchUpdated()
|
||||
{
|
||||
var pUpd = Task.Run(async () => await TryReload());
|
||||
pUpd.Wait();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -281,6 +274,19 @@ namespace GPW.CORE.WRKLOG.Pages
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
protected async Task ReportDeleted()
|
||||
{
|
||||
selPeriod = false;
|
||||
showDay = false;
|
||||
showTemp = false;
|
||||
showTimb = false;
|
||||
currRecord = null;
|
||||
ListTimbr = null;
|
||||
SelDayDTO = null;
|
||||
await InitData(true);
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indico item selezionato
|
||||
/// </summary>
|
||||
@@ -321,19 +327,6 @@ namespace GPW.CORE.WRKLOG.Pages
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
protected async Task ReportDeleted()
|
||||
{
|
||||
selPeriod = false;
|
||||
showDay = false;
|
||||
showTemp = false;
|
||||
showTimb = false;
|
||||
currRecord = null;
|
||||
ListTimbr = null;
|
||||
SelDayDTO = null;
|
||||
await InitData(true);
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
protected async Task ResetDayCheck()
|
||||
{
|
||||
selPeriod = false;
|
||||
@@ -32,7 +32,7 @@
|
||||
await Task.Delay(1);
|
||||
|
||||
// passo a pagina home
|
||||
NavManager.NavigateTo("");
|
||||
NavManager.NavigateTo("", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
@page "/Presenze"
|
||||
@attribute [Authorize]
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header table-primary py-1">
|
||||
<div class="row">
|
||||
<h3>Presenze</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row detPresenze">
|
||||
<div class="col-12">
|
||||
<DayHoriz IsTitle="true" StartHour="@startHour" EndHour="@endHour" ListFasi="@ListFasi" IdxDipSel="@IdxDipendente" MultiUser="true" DtRif="@DtSelected"></DayHoriz>
|
||||
</div>
|
||||
@if (ListRecords == null)
|
||||
{
|
||||
@for (int i = 0; i < 7; i++)
|
||||
{
|
||||
<div class="col-12 my-3">
|
||||
<div class="placeholder-glow">
|
||||
<span class="placeholder col-6 mb-1"></span>
|
||||
<span class="placeholder col-5 mb-1"></span>
|
||||
<span class="placeholder fs-1 col-6"></span>
|
||||
<span class="placeholder fs-1 col-5"></span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (var currItem in ListRecords)
|
||||
{
|
||||
<div class="col-12">
|
||||
<DayHoriz DayDTO="@currItem" StartHour="@startHour" EndHour="@endHour" ListFasi="@ListFasi" IdxDipSel="@currItem.IdxDipendente" MultiUser="true"></DayHoriz>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,223 @@
|
||||
using GPW.CORE.Data.DbModels;
|
||||
using GPW.CORE.Data.DTO;
|
||||
using GPW.CORE.WRKLOG.Data;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace GPW.CORE.WRKLOG.Pages
|
||||
{
|
||||
public partial class Presenze : IDisposable
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UITimer?.Dispose();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected DateTime lastRefresh = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// Timer per refresh dati
|
||||
///
|
||||
/// https://stackoverflow.com/questions/63060065/blazor-timer-call-async-api-task-to-update-ui https://www.janduniec.blog/index.php/100/timers-in-blazor/
|
||||
/// </summary>
|
||||
protected System.Timers.Timer UITimer = new System.Timers.Timer();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
[Inject]
|
||||
protected MessageService AppMServ { get; set; } = null!;
|
||||
|
||||
[Inject]
|
||||
protected GpwDataService GDataServ { get; set; } = null!;
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private int _endHour = 18;
|
||||
|
||||
private int _startHour = 8;
|
||||
|
||||
private DateTime DtSelected = DateTime.Today;
|
||||
|
||||
private int IdxDipendente = 0;
|
||||
|
||||
private List<AnagFasiModel> ListFasi = new List<AnagFasiModel>();
|
||||
|
||||
private List<DailyDataDTO>? ListRecords = null;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private int endHour
|
||||
{
|
||||
get => _endHour;
|
||||
set
|
||||
{
|
||||
// fix --> max 24...
|
||||
_endHour = value < 25 ? value : 24;
|
||||
}
|
||||
}
|
||||
|
||||
private bool isLoading { get; set; } = false;
|
||||
|
||||
private int startHour
|
||||
{
|
||||
get => _startHour;
|
||||
set
|
||||
{
|
||||
// fix --> MIN 0...
|
||||
_startHour = value > 0 ? value : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void checkHourRange()
|
||||
{
|
||||
int minHour = 12;
|
||||
int maxHour = 14;
|
||||
int currStart = 12;
|
||||
int currEnd = 12;
|
||||
int roundMin = 30;
|
||||
//int extraEnd = 30;
|
||||
if (ListRecords != null)
|
||||
{
|
||||
// per ogni giornata
|
||||
foreach (var giornata in ListRecords)
|
||||
{
|
||||
if (giornata.ListTimbr != null)
|
||||
{
|
||||
var minRecTimb = giornata.ListTimbr
|
||||
.Where(x => x.Entrata == true)
|
||||
.OrderBy(x => x.DataOra)
|
||||
.FirstOrDefault();
|
||||
if (minRecTimb != null)
|
||||
{
|
||||
if (minHour > minRecTimb.DataOra.AddMinutes(roundMin / 3).Hour)
|
||||
{
|
||||
minHour = minRecTimb.DataOra.AddMinutes(roundMin / 3).Hour;
|
||||
}
|
||||
}
|
||||
var maxRecTimb = giornata.ListTimbr
|
||||
.Where(x => x.Entrata == false)
|
||||
.OrderByDescending(x => x.DataOra)
|
||||
.FirstOrDefault();
|
||||
if (maxRecTimb != null)
|
||||
{
|
||||
if (maxHour < maxRecTimb.DataOra.AddMinutes(-roundMin / 3).Hour)
|
||||
{
|
||||
maxHour = maxRecTimb.DataOra.AddMinutes(-roundMin / 3).Hour + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (giornata.ListRA != null)
|
||||
{
|
||||
var minRecRa = giornata.ListRA
|
||||
.OrderBy(x => x.Inizio)
|
||||
.FirstOrDefault();
|
||||
if (minRecRa != null)
|
||||
{
|
||||
// verifico se cambia giorno inizio/fine --> seleziono la mezzanotte
|
||||
currStart = minRecRa.Inizio.AddMinutes(-roundMin).Date.Equals(minRecRa.Fine.Date) ? minRecRa.Inizio.AddMinutes(-roundMin).Hour : 0;
|
||||
if (minHour > currStart)
|
||||
{
|
||||
minHour = currStart;
|
||||
}
|
||||
}
|
||||
var maxRecRa = giornata.ListRA
|
||||
.OrderByDescending(x => x.Fine)
|
||||
.FirstOrDefault();
|
||||
if (maxRecRa != null)
|
||||
{
|
||||
// verifico se cambia giorno inizio/fine --> seleziono la mezzanotte
|
||||
currEnd = maxRecRa.Inizio.Date.Equals(maxRecRa.Fine.AddMinutes(roundMin).Date) ? maxRecRa.Fine.AddMinutes(roundMin).Hour + 1 : 24;
|
||||
if (maxHour < currEnd)
|
||||
{
|
||||
maxHour = currEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
startHour = minHour;// - 1;
|
||||
checkOrarioDip();
|
||||
// minimo 6 h... x cui "allungo" verso fine
|
||||
if (maxHour - minHour < AppMServ.orarioDip)
|
||||
{
|
||||
minHour--;
|
||||
maxHour = minHour + AppMServ.orarioDip;
|
||||
}
|
||||
endHour = maxHour;// + 1;
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
ListRecords = null;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
await Task.Delay(1);
|
||||
|
||||
await TryReload();
|
||||
// avvio un timer infinito x refresh pagina COMUNQUE ogni 60 sec anche non succedesse nulla...
|
||||
UITimer = new System.Timers.Timer
|
||||
{
|
||||
Interval = 1000 * 60,
|
||||
AutoReset = true,
|
||||
Enabled = true
|
||||
};
|
||||
UITimer.Elapsed += async (s, ea) => await TryReload();
|
||||
}
|
||||
|
||||
protected async Task TryReload()
|
||||
{
|
||||
// effettuo reload SOLO SE no ho editing in corso...
|
||||
await ReloadData();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private void checkOrarioDip()
|
||||
{
|
||||
// calcolo minimo da cod orario dipendente
|
||||
if (AppMServ.orarioDip == 0)
|
||||
{
|
||||
AnagOrariModel? schemaOrario = null;
|
||||
// recupero da DB schema settimanale...
|
||||
var pUpd = Task.Run(async () =>
|
||||
{
|
||||
schemaOrario = await GDataServ.AnagOrarioByDip(AppMServ.IdxDipendente);
|
||||
});
|
||||
pUpd.Wait();
|
||||
if (schemaOrario != null)
|
||||
{
|
||||
AppMServ.orarioDip = (int)(Math.Ceiling(schemaOrario.oreOrdSett / 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ReloadData()
|
||||
{
|
||||
isLoading = true;
|
||||
UITimer.Stop();
|
||||
ListRecords = await GDataServ.DailyDetailAllDip(DtSelected);
|
||||
await Task.Delay(1);
|
||||
checkHourRange();
|
||||
await Task.Delay(1);
|
||||
lastRefresh = DateTime.Now;
|
||||
UITimer.Start();
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user