SPEC: continuo pagina setup TemplateKit
This commit is contained in:
@@ -70,6 +70,9 @@ namespace MP.Core
|
||||
|
||||
public const string redisXdlData = redisBaseAddr + "Cache:XDL:";
|
||||
|
||||
public const string redisKitTempl = redisBaseAddr + "Cache:Kit:Templ";
|
||||
public const string redisKitInst = redisBaseAddr + "Cache:Kit:Inst";
|
||||
|
||||
#endregion Public Fields
|
||||
|
||||
#region Public Properties
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static EgwCoreLib.Utils.DtUtils;
|
||||
using MP.Core.DTO;
|
||||
using MP.Data.Translate;
|
||||
|
||||
namespace MP.Data.Controllers
|
||||
{
|
||||
@@ -30,6 +31,47 @@ namespace MP.Data.Controllers
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Elenco di tutti i counter coi valori correnti
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<AnagCountersModel> AnagCounters()
|
||||
{
|
||||
List<AnagCountersModel> dbResult = new List<AnagCountersModel>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetAnagCount
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stacca un nuovo counter x il tipo richiesto
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public AnagCountersModel AnagCountersGetNext(string cntType)
|
||||
{
|
||||
AnagCountersModel answ = new AnagCountersModel();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var pCntType = new SqlParameter("@CntType", cntType);
|
||||
|
||||
var dbResult = dbCtx
|
||||
.DbSetAnagCount
|
||||
.FromSqlRaw("EXEC dbo.stp_getNextNumb @CntType", pCntType)
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault();
|
||||
if (dbResult != null)
|
||||
{
|
||||
answ = dbResult;
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco Gruppi tipo Azienda
|
||||
/// </summary>
|
||||
@@ -1587,6 +1629,86 @@ namespace MP.Data.Controllers
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elimina record
|
||||
/// </summary>
|
||||
/// <param name="rec2del"></param>
|
||||
public bool TemplateKitDelete(TemplateKitModel rec2del)
|
||||
{
|
||||
bool fatto = false;
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var actRec = dbCtx
|
||||
.DbSetTempKit
|
||||
.Where(x => x.CodArtParent == rec2del.CodArtParent && x.CodArtChild == rec2del.CodArtChild)
|
||||
.FirstOrDefault();
|
||||
// se ci fosse aggiorno...
|
||||
if (actRec != null)
|
||||
{
|
||||
dbCtx
|
||||
.DbSetTempKit
|
||||
.Remove(actRec);
|
||||
}
|
||||
var res = dbCtx.SaveChanges();
|
||||
fatto = res != 0;
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco template da ricerca
|
||||
/// </summary>
|
||||
/// <param name="codParent"></param>
|
||||
/// <param name="codCHild"></param>
|
||||
/// <returns></returns>
|
||||
public List<TemplateKitModel> TemplateKitFilt(string codParent, string codChild)
|
||||
{
|
||||
List<TemplateKitModel> dbResult = new List<TemplateKitModel>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetTempKit
|
||||
.Where(x => (string.IsNullOrEmpty(codParent) && string.IsNullOrEmpty(codChild)) || (x.CodArtParent.Contains(codParent) && !string.IsNullOrEmpty(codParent)) || (x.CodArtChild.Contains(codChild) && !string.IsNullOrEmpty(codChild)))
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue upsert record
|
||||
/// </summary>
|
||||
/// <param name="editRec"></param>
|
||||
public bool TemplateKitUpsert(TemplateKitModel editRec)
|
||||
{
|
||||
bool fatto = false;
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var actRec = dbCtx
|
||||
.DbSetTempKit
|
||||
.Where(x => x.CodArtParent == editRec.CodArtParent && x.CodArtChild == editRec.CodArtChild)
|
||||
.FirstOrDefault();
|
||||
|
||||
// se ci fosse aggiorno...
|
||||
if (actRec == null)
|
||||
{
|
||||
dbCtx
|
||||
.DbSetTempKit
|
||||
.Add(editRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
actRec.CodArtParent = editRec.CodArtParent;
|
||||
actRec.CodArtChild = editRec.CodArtChild;
|
||||
actRec.Qty = editRec.Qty;
|
||||
dbCtx.Entry(actRec).State = EntityState.Modified;
|
||||
}
|
||||
var res = dbCtx.SaveChanges();
|
||||
fatto = res != 0;
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco Vocabolario (completo)
|
||||
/// </summary>
|
||||
|
||||
@@ -2281,98 +2281,6 @@ namespace MP.Data.Controllers
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco template da ricerca
|
||||
/// </summary>
|
||||
/// <param name="searchVal"></param>
|
||||
/// <returns></returns>
|
||||
public List<TemplateKitModel> TemplateKitFilt(string searchVal)
|
||||
{
|
||||
List<TemplateKitModel> dbResult = new List<TemplateKitModel>();
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
dbResult = dbCtx
|
||||
.DbSetTempKit
|
||||
.Where(x => x.CodArtParent.Contains(searchVal) || x.CodArtChild.Contains(searchVal))
|
||||
.AsNoTracking()
|
||||
.ToList();
|
||||
}
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elimina record
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public bool TemplateKitDelete(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
#if false
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var actRec = dbCtx
|
||||
.DbSetInsManuali
|
||||
.Where(x => currRecord.IdxInsMan > 0 && x.IdxInsMan == currRecord.IdxInsMan)
|
||||
.FirstOrDefault();
|
||||
// se ci fosse aggiorno...
|
||||
if (actRec != null)
|
||||
{
|
||||
dbCtx
|
||||
.DbSetInsManuali
|
||||
.Remove(actRec);
|
||||
}
|
||||
var res = dbCtx.SaveChanges();
|
||||
fatto = res != 0;
|
||||
}
|
||||
#endif
|
||||
return fatto;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Esegue upsert record
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public bool TemplateKitUpsert(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
#if false
|
||||
using (var dbCtx = new MoonProContext(_configuration))
|
||||
{
|
||||
var actRec = dbCtx
|
||||
.DbSetInsManuali
|
||||
.Where(x => currRecord.IdxInsMan > 0 && x.IdxInsMan == currRecord.IdxInsMan)
|
||||
.FirstOrDefault();
|
||||
// se ci fosse aggiorno...
|
||||
if (actRec == null)
|
||||
{
|
||||
dbCtx
|
||||
.DbSetInsManuali
|
||||
.Add(currRecord);
|
||||
}
|
||||
else
|
||||
{
|
||||
actRec.CodArticolo = currRecord.CodArticolo;
|
||||
actRec.FineStato = currRecord.FineStato;
|
||||
actRec.IdxMacchina = currRecord.IdxMacchina;
|
||||
actRec.IdxTipoEv = currRecord.IdxTipoEv;
|
||||
actRec.Imported = currRecord.Imported;
|
||||
actRec.InizioStato = currRecord.InizioStato;
|
||||
actRec.KeyRichiesta = currRecord.KeyRichiesta;
|
||||
actRec.MatrOpr = currRecord.MatrOpr;
|
||||
actRec.MinProd = currRecord.MinProd;
|
||||
actRec.PzBuoni = currRecord.PzBuoni;
|
||||
actRec.TCiclo = currRecord.TCiclo;
|
||||
dbCtx.Entry(actRec).State = EntityState.Modified;
|
||||
}
|
||||
var res = dbCtx.SaveChanges();
|
||||
fatto = res != 0;
|
||||
}
|
||||
#endif
|
||||
return fatto;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Elenco turni macchina (all)
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
#nullable disable
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace MP.Data.DbModels
|
||||
{
|
||||
[Table("AnagCounters")]
|
||||
public partial class AnagCountersModel
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.None), MaxLength(50)]
|
||||
public string CntType { get; set; } = "";
|
||||
|
||||
[MaxLength(50)]
|
||||
public string CntCode { get; set; } = "";
|
||||
|
||||
public int LastNum { get; set; } = 0;
|
||||
|
||||
[MaxLength(250)]
|
||||
public string Descript { get; set; } = "";
|
||||
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,7 @@ namespace MP.Data
|
||||
public virtual DbSet<vSelCauScartoModel> DbSetVSCS { get; set; }
|
||||
|
||||
public virtual DbSet<InsManualiModel> DbSetInsManuali { get; set; }
|
||||
public virtual DbSet<AnagCountersModel> DbSetAnagCount { get; set; }
|
||||
public virtual DbSet<IstanzeKitModel> DbSetInstKit { get; set; }
|
||||
public virtual DbSet<TemplateKitModel> DbSetTempKit { get; set; }
|
||||
|
||||
|
||||
@@ -3441,71 +3441,6 @@ namespace MP.Data.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elimina record + svuotamento cache
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public async Task<bool> TemplateKitDelete(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
// salvo
|
||||
fatto = dbTabController.TemplateKitDelete(currRecord);
|
||||
// svuoto cache
|
||||
RedisValue pattern = $"{redisBaseKey}:KitTemplate:*";
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco template da ricerca
|
||||
/// </summary>
|
||||
/// <param name="searchVal"></param>
|
||||
/// <returns></returns>
|
||||
public List<TemplateKitModel> TemplateKitFilt(string searchVal)
|
||||
{
|
||||
string source = "DB";
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
List<TemplateKitModel>? result = new List<TemplateKitModel>();
|
||||
// cerco in redis...
|
||||
string currKey = $"{redisBaseKey}:KitTemplate:{searchVal}";
|
||||
RedisValue rawData = redisDb.StringGet(currKey);
|
||||
if (rawData.HasValue)
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<List<TemplateKitModel>>($"{rawData}");
|
||||
source = "REDIS";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = dbTabController.TemplateKitFilt(searchVal);
|
||||
// serializzo e salvo...
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
redisDb.StringSet(currKey, rawData, FastCache);
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new List<TemplateKitModel>();
|
||||
}
|
||||
sw.Stop();
|
||||
Log.Debug($"TemplateKitFilt | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue salvataggio record + svuotamento cache
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public async Task<bool> TemplateKitUpsert(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
// salvo
|
||||
fatto = dbTabController.TemplateKitUpsert(currRecord);
|
||||
// svuoto cache
|
||||
RedisValue pattern = $"{redisBaseKey}:KitTemplate:*";
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turno macchina
|
||||
/// </summary>
|
||||
|
||||
@@ -232,8 +232,8 @@ namespace MP.SPEC.Components
|
||||
await MDService.ConfigResetCache();
|
||||
ListGruppiFase = await MDService.ElencoGruppiFase();
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
selAzienda = await MDService.ConfigTryGet("AZIENDA");
|
||||
giacenzeConf = await MDService.ConfigTryGet("SPEC_ShowGiacenze");
|
||||
selAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
||||
giacenzeConf = await MDService.ConfigTryGetAsync("SPEC_ShowGiacenze");
|
||||
ListArticoli = await MDService.ArticoliGetSearch(100000, selAzienda, "");
|
||||
ListMacchine = await MDService.MacchineGetFilt("*");
|
||||
await ReloadData(true);
|
||||
|
||||
@@ -182,17 +182,17 @@ namespace MP.SPEC.Components
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGet("SPEC_PODL_gest");
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGetAsync("SPEC_PODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_PODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_PODL_gest, out enableStartPODL);
|
||||
}
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGet("SPEC_ODL_gest");
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGetAsync("SPEC_ODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_ODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_ODL_gest, out enableStopODL);
|
||||
}
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGet("SPEC_XODL_sync");
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGetAsync("SPEC_XODL_sync");
|
||||
if (!string.IsNullOrEmpty(SPEC_XODL_sync))
|
||||
{
|
||||
bool.TryParse(SPEC_XODL_sync, out enableForceSync);
|
||||
|
||||
@@ -148,22 +148,22 @@ namespace MP.SPEC.Components
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
string strMachRecipe = await MDService.ConfigTryGet("MachineWithRecipe");
|
||||
string strMachRecipe = await MDService.ConfigTryGetAsync("MachineWithRecipe");
|
||||
if (!string.IsNullOrEmpty(strMachRecipe))
|
||||
{
|
||||
bool.TryParse(strMachRecipe, out MachineWithRecipe);
|
||||
}
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGet("SPEC_PODL_gest");
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGetAsync("SPEC_PODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_PODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_PODL_gest, out enableStartPODL);
|
||||
}
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGet("SPEC_ODL_gest");
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGetAsync("SPEC_ODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_ODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_ODL_gest, out enableStopODL);
|
||||
}
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGet("SPEC_XODL_sync");
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGetAsync("SPEC_XODL_sync");
|
||||
if (!string.IsNullOrEmpty(SPEC_XODL_sync))
|
||||
{
|
||||
bool.TryParse(SPEC_XODL_sync, out enableForceSync);
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace MP.SPEC.Components
|
||||
{
|
||||
SelFilter = new SelectFluxParams();
|
||||
await MDService.ConfigResetCache();
|
||||
var result = await MDService.ConfigTryGet("SPEC_ParamTempoAgg");
|
||||
var result = await MDService.ConfigTryGetAsync("SPEC_ParamTempoAgg");
|
||||
if (result != null)
|
||||
{
|
||||
refreshRate = int.Parse(result);
|
||||
@@ -184,7 +184,7 @@ namespace MP.SPEC.Components
|
||||
ListMacchine = await MDService.MacchineWithFlux(dtStart, dtEnd);
|
||||
ListFlux = await MDService.ParametriGetFilt(selMacchina);
|
||||
|
||||
var configData = await MDService.ConfigGetAll();
|
||||
var configData = await MDService.ConfigGetAllAsync();
|
||||
var currRec = configData.FirstOrDefault(x => x.Chiave == "numOreAnticipoSnapshot");
|
||||
if (currRec != null)
|
||||
{
|
||||
@@ -200,7 +200,7 @@ namespace MP.SPEC.Components
|
||||
{
|
||||
// copio il filtro
|
||||
var currFilt = SelFilter;
|
||||
// fermo update
|
||||
// fermo DoUpdate
|
||||
currFilt.LiveUpdate = true;
|
||||
currFilt.CurrPage = 0;
|
||||
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
||||
@@ -289,7 +289,7 @@ namespace MP.SPEC.Components
|
||||
{
|
||||
// copio il filtro
|
||||
var currFilt = SelFilter;
|
||||
// fermo update
|
||||
// fermo DoUpdate
|
||||
currFilt.LiveUpdate = (value == null);
|
||||
currFilt.CurrPage = 0;
|
||||
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
||||
@@ -309,7 +309,7 @@ namespace MP.SPEC.Components
|
||||
{
|
||||
// copio il filtro
|
||||
var currFilt = SelFilter;
|
||||
// fermo update
|
||||
// fermo DoUpdate
|
||||
currFilt.LiveUpdate = false;
|
||||
currFilt.CurrPage = 0;
|
||||
currFilt.lastUpdate = $"{DateTime.Now:yyyy/MM/dd HH:mm:ss}";
|
||||
|
||||
+192
-23
@@ -1,9 +1,11 @@
|
||||
using EgwCoreLib.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MP.Core.Conf;
|
||||
using MP.Core.DTO;
|
||||
using MP.Core.Objects;
|
||||
using MP.Data;
|
||||
using MP.Data.Controllers;
|
||||
using MP.Data.DbModels;
|
||||
using MP.Data.MgModels;
|
||||
using MP.Data.Services;
|
||||
@@ -12,6 +14,7 @@ using NLog;
|
||||
using StackExchange.Redis;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using ZXing;
|
||||
|
||||
namespace MP.SPEC.Data
|
||||
{
|
||||
@@ -399,7 +402,11 @@ namespace MP.SPEC.Data
|
||||
return mongoController.CalcRecipe(currRecipe);
|
||||
}
|
||||
|
||||
public async Task<List<ConfigModel>> ConfigGetAll()
|
||||
/// <summary>
|
||||
/// Recupero tab config in modalità Asincrona
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ConfigModel>> ConfigGetAllAsync()
|
||||
{
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
@@ -411,7 +418,7 @@ namespace MP.SPEC.Data
|
||||
result = JsonConvert.DeserializeObject<List<ConfigModel>>($"{rawData}");
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"ConfigGetAll Read from REDIS: {ts.TotalMilliseconds}ms");
|
||||
Log.Debug($"ConfigGetAllAsync Read from REDIS: {ts.TotalMilliseconds}ms");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -421,7 +428,7 @@ namespace MP.SPEC.Data
|
||||
await redisDb.StringSetAsync(Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"ConfigGetAll Read from DB: {ts.TotalMilliseconds}ms");
|
||||
Log.Debug($"ConfigGetAllAsync Read from DB: {ts.TotalMilliseconds}ms");
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
@@ -430,6 +437,39 @@ namespace MP.SPEC.Data
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero tab config in modalità Sincrona
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ConfigModel> ConfigGetAll()
|
||||
{
|
||||
string currMode = "REDIS";
|
||||
Stopwatch stopWatch = new Stopwatch();
|
||||
stopWatch.Start();
|
||||
List<ConfigModel>? result = new List<ConfigModel>();
|
||||
// cerco in redis...
|
||||
RedisValue rawData = redisDb.StringGet(Utils.redisConfKey);
|
||||
if (!string.IsNullOrEmpty($"{rawData}"))
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<List<ConfigModel>>($"{rawData}");
|
||||
}
|
||||
else
|
||||
{
|
||||
currMode = "DB";
|
||||
result = dbController.ConfigGetAll();
|
||||
// serializzo e salvo...
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
redisDb.StringSet(Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new List<ConfigModel>();
|
||||
}
|
||||
stopWatch.Stop();
|
||||
Log.Debug($"ConfigGetAll Read from {currMode}: {stopWatch.Elapsed.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset dati cache config
|
||||
/// </summary>
|
||||
@@ -444,12 +484,24 @@ namespace MP.SPEC.Data
|
||||
/// </summary>
|
||||
/// <param name="keyName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> ConfigTryGet(string keyName)
|
||||
public string ConfigTryGet(string keyName)
|
||||
{
|
||||
string answ = "";
|
||||
// preselezione valori
|
||||
var configData = await ConfigGetAll();
|
||||
if(configData==null || configData.Count==0)
|
||||
{
|
||||
configData = ConfigGetAll();
|
||||
}
|
||||
var currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
||||
|
||||
// se non trovato provo a ricaricare..
|
||||
if (currRec == null)
|
||||
{
|
||||
configData = ConfigGetAll();
|
||||
currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
||||
}
|
||||
|
||||
// verifico se ci sia il dato...
|
||||
if (currRec != null)
|
||||
{
|
||||
answ = currRec.Valore;
|
||||
@@ -458,6 +510,38 @@ namespace MP.SPEC.Data
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restituisce valore della stringa (SE disponibile) - modalità async
|
||||
/// </summary>
|
||||
/// <param name="keyName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> ConfigTryGetAsync(string keyName)
|
||||
{
|
||||
string answ = "";
|
||||
// preselezione valori
|
||||
var currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
||||
|
||||
// se non trovato provo a ricaricare..
|
||||
if (currRec != null)
|
||||
{
|
||||
configData = await ConfigGetAllAsync();
|
||||
currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
|
||||
}
|
||||
|
||||
// verifico se ci sia il dato...
|
||||
if (currRec != null)
|
||||
{
|
||||
answ = currRec.Valore;
|
||||
}
|
||||
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cache dati config
|
||||
/// </summary>
|
||||
private List<ConfigModel> configData { get; set; } = new List<ConfigModel>();
|
||||
|
||||
/// <summary>
|
||||
/// Update chiave config
|
||||
/// </summary>
|
||||
@@ -512,7 +596,7 @@ namespace MP.SPEC.Data
|
||||
result = await dbController.DossiersDeleteRecord(selRecord);
|
||||
// elimino cache redis...
|
||||
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
|
||||
bool answ = await RedisFlushPatternAsync(pattern);
|
||||
bool answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
stopWatch.Stop();
|
||||
TimeSpan ts = stopWatch.Elapsed;
|
||||
Log.Debug($"DossiersDeleteRecord | IdxMacchina {selRecord.IdxMacchina} | DtRif {selRecord.DtRif} | IdxODL {selRecord.IdxODL} | {ts.TotalMilliseconds}ms");
|
||||
@@ -587,7 +671,7 @@ namespace MP.SPEC.Data
|
||||
dbController.DossiersTakeParamsSnapshotLast(IdxMacchina, dtMin, dtMax);
|
||||
// elimino cache redis...
|
||||
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
Log.Info($"Svuotata cache dossier | {pattern}");
|
||||
return answ;
|
||||
}
|
||||
@@ -703,7 +787,7 @@ namespace MP.SPEC.Data
|
||||
{
|
||||
bool answ = false;
|
||||
RedisValue pattern = new RedisValue($"{Utils.redisParetoFLKey}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
|
||||
return answ;
|
||||
}
|
||||
@@ -712,7 +796,7 @@ namespace MP.SPEC.Data
|
||||
{
|
||||
await Task.Delay(1);
|
||||
RedisValue pattern = Utils.RedValue("*");
|
||||
bool answ = await RedisFlushPatternAsync(pattern);
|
||||
bool answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
// rileggo vocabolario.,..
|
||||
ObjVocabolario = VocabolarioGetAll();
|
||||
return answ;
|
||||
@@ -722,7 +806,7 @@ namespace MP.SPEC.Data
|
||||
{
|
||||
await Task.Delay(1);
|
||||
RedisValue pattern = Utils.RedValue(redKey);
|
||||
bool answ = await RedisFlushPatternAsync(pattern);
|
||||
bool answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
return answ;
|
||||
}
|
||||
|
||||
@@ -797,7 +881,7 @@ namespace MP.SPEC.Data
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
if (string.IsNullOrEmpty(canCacheParametri))
|
||||
{
|
||||
canCacheParametri = await ConfigTryGet("SPEC_ParametriEnableRedisCache");
|
||||
canCacheParametri = await ConfigTryGetAsync("SPEC_ParametriEnableRedisCache");
|
||||
}
|
||||
if (canCacheParametri != "false")
|
||||
{
|
||||
@@ -1226,7 +1310,7 @@ namespace MP.SPEC.Data
|
||||
bool fatto = false;
|
||||
await Task.Delay(1);
|
||||
// recupero dati x conf modalità conferma
|
||||
var configData = await ConfigGetAll();
|
||||
var configData = await ConfigGetAllAsync();
|
||||
if (configData != null)
|
||||
{
|
||||
bool confRett = false;
|
||||
@@ -1700,7 +1784,7 @@ namespace MP.SPEC.Data
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
public bool RedisFlushPattern(string pattern)
|
||||
public bool ExecFlushRedisPattern(string pattern)
|
||||
{
|
||||
bool answ = false;
|
||||
var listEndpoints = redisConnAdmin.GetEndPoints();
|
||||
@@ -1726,7 +1810,7 @@ namespace MP.SPEC.Data
|
||||
/// </summary>
|
||||
/// <param name="pattern"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> RedisFlushPatternAsync(RedisValue pattern)
|
||||
public async Task<bool> ExecFlushRedisPatternAsync(RedisValue pattern)
|
||||
{
|
||||
bool answ = false;
|
||||
var listEndpoints = redisConnAdmin.GetEndPoints();
|
||||
@@ -1877,6 +1961,91 @@ namespace MP.SPEC.Data
|
||||
return answ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Elimina record + svuotamento cache
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public async Task<bool> TemplateKitDelete(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
// salvo
|
||||
fatto = dbController.TemplateKitDelete(currRecord);
|
||||
// svuoto cache
|
||||
RedisValue pattern = $"{Utils.redisKitTempl}:*";
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stacca un nuovo counter x il tipo richiesto
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public AnagCountersModel AnagCountersGetNext(string cntType)
|
||||
{
|
||||
AnagCountersModel result = new AnagCountersModel();
|
||||
string source = "DB";
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
result = dbController.AnagCountersGetNext(cntType);
|
||||
sw.Stop();
|
||||
Log.Debug($"AnagCountersGetNext | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco template da ricerca
|
||||
/// </summary>
|
||||
/// <param name="codParent"></param>
|
||||
/// <param name="codChild"></param>
|
||||
/// <returns></returns>
|
||||
public List<TemplateKitModel> TemplateKitFilt(string codParent, string codChild)
|
||||
{
|
||||
string source = "DB";
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
List<TemplateKitModel>? result = new List<TemplateKitModel>();
|
||||
// cerco in redis...
|
||||
string currKey = $"{Utils.redisKitTempl}:{codParent}:{codChild}";
|
||||
RedisValue rawData = redisDb.StringGet(currKey);
|
||||
if (rawData.HasValue)
|
||||
{
|
||||
result = JsonConvert.DeserializeObject<List<TemplateKitModel>>($"{rawData}");
|
||||
source = "REDIS";
|
||||
}
|
||||
else
|
||||
{
|
||||
result = dbController.TemplateKitFilt(codParent, codChild);
|
||||
// serializzo e salvo...
|
||||
rawData = JsonConvert.SerializeObject(result);
|
||||
redisDb.StringSet(currKey, rawData, TimeSpan.FromMinutes(redisLongTimeCache));
|
||||
}
|
||||
if (result == null)
|
||||
{
|
||||
result = new List<TemplateKitModel>();
|
||||
}
|
||||
sw.Stop();
|
||||
Log.Debug($"TemplateKitFilt | {source} | {sw.Elapsed.TotalMilliseconds}ms");
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue salvataggio record + svuotamento cache
|
||||
/// </summary>
|
||||
/// <param name="currRecord"></param>
|
||||
public async Task<bool> TemplateKitUpsert(TemplateKitModel currRecord)
|
||||
{
|
||||
bool fatto = false;
|
||||
// salvo
|
||||
fatto = dbController.TemplateKitUpsert(currRecord);
|
||||
// svuoto cache
|
||||
RedisValue pattern = $"{Utils.redisKitTempl}:*";
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco completo tabella Vocabolario
|
||||
/// </summary>
|
||||
@@ -1928,13 +2097,13 @@ namespace MP.SPEC.Data
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Restituisce un timeout dai minuti richiesti + tempo random 1..60 sec
|
||||
/// Restituisce un timeout dai minuti richiesti + tempo random -15..+15 sec
|
||||
/// </summary>
|
||||
/// <param name="stdMinutes"></param>
|
||||
/// <returns></returns>
|
||||
protected TimeSpan getRandTOut(double stdMinutes)
|
||||
{
|
||||
double rndValue = stdMinutes + (double)rand.Next(1, 60) / 60;
|
||||
double rndValue = stdMinutes + (double)rand.Next(-15, 15) / 60;
|
||||
return TimeSpan.FromMinutes(rndValue);
|
||||
}
|
||||
|
||||
@@ -2060,7 +2229,7 @@ namespace MP.SPEC.Data
|
||||
answ = true;
|
||||
}
|
||||
}
|
||||
// notifico update ai client in ascolto x reset cache
|
||||
// notifico DoUpdate ai client in ascolto x reset cache
|
||||
NotifyReloadRequest($"FlushRedisCache | {pattern}");
|
||||
return answ;
|
||||
}
|
||||
@@ -2069,13 +2238,13 @@ namespace MP.SPEC.Data
|
||||
{
|
||||
bool answ = false;
|
||||
RedisValue pattern = new RedisValue($"{Utils.redisXdlData}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
pattern = new RedisValue($"{Utils.redisPOdlByOdl}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
pattern = new RedisValue($"{Utils.redisPOdlByPOdl}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
pattern = new RedisValue($"{Utils.redisPOdlList}:*");
|
||||
answ = await RedisFlushPatternAsync(pattern);
|
||||
answ = await ExecFlushRedisPatternAsync(pattern);
|
||||
|
||||
return answ;
|
||||
}
|
||||
@@ -2098,9 +2267,9 @@ namespace MP.SPEC.Data
|
||||
private async Task resetCacheArticoli()
|
||||
{
|
||||
RedisValue pattern = new RedisValue($"{Utils.redisArtByDossier}:*");
|
||||
await RedisFlushPatternAsync(pattern);
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
pattern = new RedisValue($"{Utils.redisArtList}:*");
|
||||
await RedisFlushPatternAsync(pattern);
|
||||
await ExecFlushRedisPatternAsync(pattern);
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>MP.SPEC</RootNamespace>
|
||||
<Version>6.16.2504.913</Version>
|
||||
<Version>6.16.2504.919</Version>
|
||||
<UserSecretsId>1800a78a-6ff1-40f9-b490-87fb8bfc1394</UserSecretsId>
|
||||
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace MP.SPEC.Pages
|
||||
selAzienda = currRec.Valore;
|
||||
}
|
||||
#endif
|
||||
selAzienda = await MDService.ConfigTryGet("AZIENDA");
|
||||
selAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
||||
ListAziende = await MDService.ElencoAziende();
|
||||
ListTipoArt = await MDService.AnagTipoArtLV();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ namespace MP.SPEC.Pages
|
||||
{
|
||||
CurrPeriodo.Fine = DateTime.Today;
|
||||
}
|
||||
// processo i flussi 1:1 x mandare update ad avanzamento
|
||||
// processo i flussi 1:1 x mandare DoUpdate ad avanzamento
|
||||
await MDataServ.FluxLogDataRedux(idxMaccSel, new List<string> { item }, CurrPeriodo, ValMode, IntReq, NumItem);
|
||||
currStep++;
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace MP.SPEC.Pages
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await MDService.ConfigResetCache();
|
||||
giacenzeConf = await MDService.ConfigTryGet("SPEC_ShowGiacenze");
|
||||
giacenzeConf = await MDService.ConfigTryGetAsync("SPEC_ShowGiacenze");
|
||||
await Task.Delay(1);
|
||||
padCodXdl = await MDService.ConfigTryGet("padCodXdl");
|
||||
padCodXdl = await MDService.ConfigTryGetAsync("padCodXdl");
|
||||
var uri = NavManager.ToAbsoluteUri(NavManager.Uri);
|
||||
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("IdxOdl", out var _idxOdl))
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace MP.SPEC.Pages
|
||||
}
|
||||
}
|
||||
#endif
|
||||
currAzienda = await MDService.ConfigTryGet("AZIENDA");
|
||||
currAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
|
||||
+57
-85
@@ -1,6 +1,5 @@
|
||||
@page "/KIT"
|
||||
|
||||
|
||||
<div class="card mb-5">
|
||||
<div class="card-header table-primary">
|
||||
<div class="d-flex justify-content-between">
|
||||
@@ -10,25 +9,25 @@
|
||||
<h3>KIT </h3>
|
||||
</div>
|
||||
<div class="px-2">
|
||||
<button class="btn btn-success" @onclick="() => addNew()">Nuovo <i class="bi bi-plus-square"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="px-0 align-content-center">
|
||||
<div class="input-group">
|
||||
<div class="px-0 align-content-center d-flex justify-content-end">
|
||||
@if (enabKitCount)
|
||||
{
|
||||
<div class="input-group me-2">
|
||||
<button class="btn btn-success" style="min-width: 8rem;" @onclick="() => DoAddNew(true)">Nuovo <i class="bi bi-plus-square"></i></button>
|
||||
</div>
|
||||
}
|
||||
<div class="input-group me-2" style="min-width: 20rem;">
|
||||
<span class="input-group-text"><i class="fa fa-search"></i></span>
|
||||
<input type="text" class="form-control" placeholder="Cerca (3+ char)" aria-label="Ricerca" title="Ricerca (3+ char)" @bind="@SearchVal">
|
||||
<button class="btn @searchCss" @onclick="() => resetSearch()"><i class="fa fa-ban"></i></button>
|
||||
<label class="input-group-text" for="maxRecord" title="Selezionare l'azienda da visualizzare"><i class="fa-solid fa-industry"></i></label>
|
||||
<select @bind="@selAzienda" class="form-select" title="Selezionare l'azienda da visualizzare">
|
||||
@if (ListAziende != null)
|
||||
{
|
||||
foreach (var item in ListAziende)
|
||||
{
|
||||
<option value="@item.CodGruppo">@item.DescrGruppo</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
<input type="text" class="form-control" placeholder="@($"Parent {minChar}+ | Ctrl-R")" aria-label="Ricerca" title="@($"Ricerca Parent | {minChar}+ | Ctrl-R")" @bind="@SearchParent" accesskey="R">
|
||||
<button class="btn @sParentCss" @onclick="() => ResetParent()"><i class="fa fa-ban"></i></button>
|
||||
</div>
|
||||
<div class="input-group" style="min-width: 20rem;">
|
||||
<span class="input-group-text"><i class="fa fa-search"></i></span>
|
||||
<input type="text" class="form-control" placeholder="@($"Child {minChar}+ | Ctrl-R")" aria-label="Ricerca" title="@($"Ricerca Child | {minChar}+ | Ctrl-R")" @bind="@SearchChild" accesskey="R">
|
||||
<button class="btn @sChildCss" @onclick="() => ResetChild()"><i class="fa fa-ban"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -43,66 +42,37 @@
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Codice</span>
|
||||
<input type="text" class="form-control" placeholder="Articolo" @bind-value="@currRecord.CodArticolo">
|
||||
<span class="input-group-text">Art Parent</span>
|
||||
<input type="text" class="form-control disabled" placeholder="Cod Parent" @bind-value="@currRecord.CodArtParent">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Disegno</span>
|
||||
<input type="text" class="form-control" placeholder="Disegno" @bind-value="@currRecord.Disegno">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="input-group" title="Azienda">
|
||||
<span class="input-group-text">Azienda</span>
|
||||
<select @bind="@currRecord.Azienda" class="form-select text-end">
|
||||
@if (ListAziende != null)
|
||||
{
|
||||
foreach (var item in ListAziende.Where(x => x.CodGruppo != "*").ToList())
|
||||
{
|
||||
<option value="@item.CodGruppo">@item.DescrGruppo</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col-3">
|
||||
<div class="input-group" title="Tipo">
|
||||
<span class="input-group-text">Tipo</span>
|
||||
<select @bind="@currRecord.Tipo" class="form-select text-end">
|
||||
@if (ListTipoArt != null)
|
||||
{
|
||||
foreach (var item in ListTipoArt)
|
||||
{
|
||||
<option value="@item.value">@item.label</option>
|
||||
}
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">Descrizione</span>
|
||||
<input type="text" class="form-control" placeholder="Descrizione Articolo" @bind-value="@currRecord.DescArticolo">
|
||||
<span class="input-group-text">Art Child</span>
|
||||
<input type="text" class="form-control" placeholder="CodChild" @bind-value="@currRecord.CodArtChild">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-warning" @onclick="() => cancel()">Annulla <i class="bi bi-x-circle"></i></button>
|
||||
<div class="input-group" title="Qty">
|
||||
<span class="input-group-text">Qty relativa</span>
|
||||
<input type="number" class="form-control" placeholder="Qty child/parent" @bind-value="@currRecord.Qty">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-success" @onclick="() => update(currRecord)">Salva <i class="bi bi-save"></i></button>
|
||||
</div>
|
||||
<button class="btn btn-warning w-100" @onclick="() => DoCancel()">Annulla <i class="bi bi-x-circle"></i></button>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
@if (currRecord.Qty > 0 && !string.IsNullOrEmpty(currRecord.CodArtParent) && !string.IsNullOrEmpty(currRecord.CodArtChild))
|
||||
{
|
||||
<button class="btn btn-success w-100" @onclick="() => DoUpdate(currRecord)">Salva <i class="bi bi-save"></i></button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="btn btn-secondary w-100 disabled">Salva <i class="bi bi-save"></i></button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@*<div class="card-footer">Footer</div>*@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -116,7 +86,15 @@
|
||||
}
|
||||
else if (totalCount == 0)
|
||||
{
|
||||
<div class="alert alert-warning text-center display-4">Nessun record trovato</div>
|
||||
<div class="alert alert-warning text-center display-4">
|
||||
Nessun record trovato
|
||||
@if (enabKitSearch && !string.IsNullOrEmpty(SearchParent) && totalCount == 0)
|
||||
{
|
||||
<div class="input-group me-2">
|
||||
<button class="btn btn-success" style="min-width: 8rem;" @onclick="() => DoAddNew(false)">Aggiungi Cod Parent Cercato <i class="bi bi-plus-square"></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -128,43 +106,34 @@
|
||||
<th>
|
||||
@if (currRecord != null)
|
||||
{
|
||||
<button @onclick="() => resetSel()" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||||
<button @onclick="() => ResetSel()" class="btn btn-primary btn-sm"><i class="bi bi-arrow-counterclockwise"></i></button>
|
||||
}
|
||||
</th>
|
||||
<th><i class="fa-solid fa-file"></i> Articolo</th>
|
||||
<th><i class="fa-solid fa-compass-drafting"></i> Disegno</th>
|
||||
<th><i class="fa-solid fa-file-word"></i> Descrizione</th>
|
||||
<th><i class="fa-solid fa-rectangle-list"></i> Tipo</th>
|
||||
<th><i class="fa-solid fa-industry"></i> Azienda</th>
|
||||
<th><i class="fa-solid fa-sitemap"></i> Articolo Parent</th>
|
||||
<th><i class="fa-solid fa-file"></i> Articolo Child</th>
|
||||
<th><i class="fa-solid fa-hashtag"></i> KIT Qty</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var record in ListRecords)
|
||||
{
|
||||
<tr class="@checkSelect(@record.CodArticolo)">
|
||||
<tr class="@checkSelect(record)">
|
||||
<td>
|
||||
<button @onclick="() => selRecord(record)" class="btn btn-primary btn-sm" title="Modifica Record"><i class="bi bi-pencil-square"></i></button>
|
||||
<button @onclick="() => cloneRecord(record)" class="btn btn-info btn-sm" title="Duplica Record"><i class="bi bi-clipboard-check"></i></button>
|
||||
<button @onclick="() => SelRecord(record)" class="btn btn-primary btn-sm" title="Modifica Record"><i class="bi bi-pencil-square"></i></button>
|
||||
<button @onclick="() => DoClone(record)" class="btn btn-info btn-sm" title="Duplica Record"><i class="bi bi-clipboard-check"></i></button>
|
||||
</td>
|
||||
<td>
|
||||
<div>@record.CodArticolo</div>
|
||||
<div>@record.CodArtParent</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small">@record.Disegno</div>
|
||||
<div>@record.CodArtChild</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="small">@record.DescArticolo</div>
|
||||
<div>@record.Qty</div>
|
||||
</td>
|
||||
<td>
|
||||
<div>@record.Tipo</div>
|
||||
</td>
|
||||
<td>@record.Azienda</td>
|
||||
<td>
|
||||
@if (ArticoloDelEnabled(record.CodArticolo))
|
||||
{
|
||||
<button @onclick="() => deleteRecord(record)" class="btn btn-danger btn-sm"><i class="bi bi-trash-fill"></i></button>
|
||||
}
|
||||
<button @onclick="() => DoDelete(record)" class="btn btn-danger btn-sm"><i class="bi bi-trash-fill"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
@@ -175,6 +144,9 @@
|
||||
}
|
||||
</div>
|
||||
<div class="card-footer py-1">
|
||||
<DataPager PageSize="numRecord" currPage="currPage" numRecordChanged="ForceReload" numPageChanged="ForceReloadPage" totalCount="totalCount" showLoading="isLoading" />
|
||||
@if (totalCount > numRecord)
|
||||
{
|
||||
<DataPager PageSize="numRecord" currPage="currPage" numRecordChanged="SetNumRec" numPageChanged="SetNumPage" totalCount="totalCount" showLoading="isLoading" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
+165
-154
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.JSInterop;
|
||||
using MP.Data.DbModels;
|
||||
using MP.SPEC.Data;
|
||||
@@ -9,9 +10,10 @@ namespace MP.SPEC.Pages
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
public string checkSelect(string CodArticolo)
|
||||
public string checkSelect(TemplateKitModel currRec)
|
||||
{
|
||||
string answ = "";
|
||||
#if false
|
||||
if (currRecord != null)
|
||||
{
|
||||
try
|
||||
@@ -21,11 +23,10 @@ namespace MP.SPEC.Pages
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
|
||||
private SelectArticoliParams currFilter = new SelectArticoliParams();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
currRecord = null;
|
||||
@@ -36,16 +37,6 @@ namespace MP.SPEC.Pages
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
public async void OnSeachUpdated()
|
||||
{
|
||||
await InvokeAsync(() =>
|
||||
{
|
||||
currPage = 1;
|
||||
Task task = UpdateData();
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Properties
|
||||
@@ -59,6 +50,63 @@ namespace MP.SPEC.Pages
|
||||
[Inject]
|
||||
protected NavigationManager NavManager { get; set; } = null!;
|
||||
|
||||
protected string sChildCss
|
||||
{
|
||||
get => string.IsNullOrEmpty(sCodChild) ? "btn-secondary" : "btn-primary";
|
||||
}
|
||||
|
||||
protected string SearchChild
|
||||
{
|
||||
get => sCodChild;
|
||||
set
|
||||
{
|
||||
// salvo solo se minChar+ chars
|
||||
if (value.Length >= minChar || string.IsNullOrEmpty(value))
|
||||
{
|
||||
if (sCodChild != value)
|
||||
{
|
||||
sCodChild = value;
|
||||
currPage = 1;
|
||||
#if false
|
||||
var pUpd = Task.Run(async () =>
|
||||
{
|
||||
ListRecords = null;
|
||||
await Task.Delay(1);
|
||||
await ReloadData();
|
||||
});
|
||||
pUpd.Wait();
|
||||
#endif
|
||||
ListRecords = null;
|
||||
ReloadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string SearchParent
|
||||
{
|
||||
get => sCodParent;
|
||||
set
|
||||
{
|
||||
// salvo solo se minChar+ chars
|
||||
if (value.Length >= minChar || string.IsNullOrEmpty(value))
|
||||
{
|
||||
if (sCodParent != value)
|
||||
{
|
||||
sCodParent = value;
|
||||
currPage = 1;
|
||||
ListRecords = null;
|
||||
ReloadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string sParentCss
|
||||
{
|
||||
get => string.IsNullOrEmpty(sCodParent) ? "btn-secondary" : "btn-primary";
|
||||
}
|
||||
|
||||
protected int totalCount
|
||||
{
|
||||
get
|
||||
@@ -79,59 +127,51 @@ namespace MP.SPEC.Pages
|
||||
/// <summary>
|
||||
/// Crea nuovo record e va in editing...
|
||||
/// </summary>
|
||||
/// <param name="AutoGen">Genera codice numerico in automatico da counter</param>
|
||||
/// <returns></returns>
|
||||
protected async Task addNew()
|
||||
protected async Task DoAddNew(bool AutoGen)
|
||||
{
|
||||
currRecord = new AnagArticoliModel()
|
||||
// imposto a ricerca x iniziare
|
||||
string codParent = SearchParent;
|
||||
// se deve essere autogenerato da counter...
|
||||
if (AutoGen)
|
||||
{
|
||||
CodArticolo = $"_NEW_{DateTime.Now:yyyyMMdd.HHmmss}",
|
||||
DescArticolo = "Nuovo articolo",
|
||||
Azienda = selAzienda != "*" ? selAzienda : "MAPO",
|
||||
Disegno = "",
|
||||
Tipo = "ART"
|
||||
var cntRec = MDService.AnagCountersGetNext("NumKitArt");
|
||||
if (cntRec != null)
|
||||
{
|
||||
codParent = $"{cntRec.CntCode}{cntRec.LastNum:000000}";
|
||||
}
|
||||
else
|
||||
{
|
||||
codParent = "";
|
||||
}
|
||||
}
|
||||
currRecord = new TemplateKitModel()
|
||||
{
|
||||
CodArtParent = codParent,
|
||||
CodArtChild = "",
|
||||
Qty = 1
|
||||
};
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
protected async Task resetSearch()
|
||||
{
|
||||
SearchVal = "";
|
||||
await ReloadData();
|
||||
}
|
||||
|
||||
protected string searchCss
|
||||
{
|
||||
get => string.IsNullOrEmpty(searchVal) ? "btn-secondary" : "btn-primary";
|
||||
}
|
||||
|
||||
protected string SearchVal
|
||||
{
|
||||
get => searchVal;
|
||||
set
|
||||
{
|
||||
// salvo solo se 3+ chars
|
||||
if (value.Length > 2 || string.IsNullOrEmpty(value))
|
||||
{
|
||||
if (searchVal != value)
|
||||
{
|
||||
searchVal = value;
|
||||
var pUpd = Task.Run(async () =>
|
||||
{
|
||||
ListRecords = null;
|
||||
await Task.Delay(1);
|
||||
await ReloadData();
|
||||
});
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private string searchVal { get; set; } = "";
|
||||
|
||||
protected async Task cancel()
|
||||
protected async Task DoCancel()
|
||||
{
|
||||
currRecord = null;
|
||||
await ReloadData();
|
||||
ReloadData();
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
protected async Task DoClone(TemplateKitModel selRec)
|
||||
{
|
||||
// creo record duplicato...
|
||||
TemplateKitModel newRec = new TemplateKitModel()
|
||||
{
|
||||
CodArtParent = selRec.CodArtParent,
|
||||
CodArtChild = "",//selRec.CodArtParent,
|
||||
Qty = selRec.Qty
|
||||
};
|
||||
currRecord = newRec;
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
@@ -140,46 +180,61 @@ namespace MP.SPEC.Pages
|
||||
/// </summary>
|
||||
/// <param name="selRec"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task deleteRecord(AnagArticoliModel selRec)
|
||||
protected async Task DoDelete(TemplateKitModel selRec)
|
||||
{
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione Articolo: sei sicuro di voler procedere?"))
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Eliminazione riga KIT: sei sicuro di voler procedere?"))
|
||||
return;
|
||||
|
||||
await Task.Delay(1);
|
||||
var done = await MDService.ArticoliDeleteRecord(selRec);
|
||||
var done = await MDService.TemplateKitDelete(selRec);
|
||||
currRecord = null;
|
||||
await ReloadData();
|
||||
ReloadData();
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
protected void ForceReload(int newNum)
|
||||
protected async Task DoUpdate(TemplateKitModel selRec)
|
||||
{
|
||||
numRecord = newNum;
|
||||
}
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
||||
return;
|
||||
|
||||
protected void ForceReloadPage(int newNum)
|
||||
{
|
||||
currPage = newNum;
|
||||
await Task.Delay(1);
|
||||
var done = await MDService.TemplateKitUpsert(selRec);
|
||||
currRecord = null;
|
||||
ReloadData();
|
||||
await Task.Delay(1);
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
numRecord = 10;
|
||||
#if false
|
||||
configData = await MDService.ConfigGetAll();
|
||||
var currRec = configData.FirstOrDefault(x => x.Chiave == "AZIENDA");
|
||||
if (currRec != null)
|
||||
string rawVal = MDService.ConfigTryGet("SPEC_nArtSearch");
|
||||
if (!string.IsNullOrEmpty(rawVal))
|
||||
{
|
||||
selAzienda = currRec.Valore;
|
||||
}
|
||||
#endif
|
||||
selAzienda = await MDService.ConfigTryGet("AZIENDA");
|
||||
int.TryParse(rawVal, out minChar);
|
||||
}
|
||||
rawVal = MDService.ConfigTryGet("SPEC_Kit_enabCount");
|
||||
if (!string.IsNullOrEmpty(rawVal))
|
||||
{
|
||||
bool.TryParse(rawVal, out enabKitCount);
|
||||
}
|
||||
rawVal = MDService.ConfigTryGet("SPEC_Kit_enabSearch");
|
||||
if (!string.IsNullOrEmpty(rawVal))
|
||||
{
|
||||
bool.TryParse(rawVal, out enabKitSearch);
|
||||
}
|
||||
ListAziende = await MDService.ElencoAziende();
|
||||
ListTipoArt = await MDService.AnagTipoArtLV();
|
||||
}
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
await ReloadData();
|
||||
ReloadData();
|
||||
}
|
||||
|
||||
protected void ResetChild()
|
||||
{
|
||||
SearchChild = "";
|
||||
ReloadData();
|
||||
}
|
||||
|
||||
protected void ResetData()
|
||||
@@ -187,60 +242,52 @@ namespace MP.SPEC.Pages
|
||||
currRecord = null;
|
||||
}
|
||||
|
||||
protected async Task resetSel()
|
||||
protected void ResetParent()
|
||||
{
|
||||
currRecord = null;
|
||||
await Task.Delay(1);
|
||||
SearchParent = "";
|
||||
ReloadData();
|
||||
}
|
||||
|
||||
protected async Task selRecord(AnagArticoliModel selRec)
|
||||
protected void ResetSel()
|
||||
{
|
||||
currRecord = null;
|
||||
}
|
||||
|
||||
protected void SelRecord(TemplateKitModel selRec)
|
||||
{
|
||||
currRecord = selRec;
|
||||
await Task.Delay(1);
|
||||
}
|
||||
protected async Task cloneRecord(AnagArticoliModel selRec)
|
||||
|
||||
protected void SetNumPage(int newNum)
|
||||
{
|
||||
// creo record duplicato...
|
||||
AnagArticoliModel newRec = new AnagArticoliModel()
|
||||
{
|
||||
Azienda = selRec.Azienda,
|
||||
CodArticolo = selRec.CodArticolo,
|
||||
DescArticolo = $"CLONE - {selRec.DescArticolo}",
|
||||
Disegno = selRec.Disegno,
|
||||
Tipo = selRec.Tipo
|
||||
};
|
||||
currRecord = newRec;
|
||||
await Task.Delay(1);
|
||||
currPage = newNum;
|
||||
}
|
||||
|
||||
|
||||
protected async Task update(AnagArticoliModel selRec)
|
||||
protected void SetNumRec(int newNum)
|
||||
{
|
||||
if (!await JSRuntime.InvokeAsync<bool>("confirm", "Confermi di voler salvare le modifiche?"))
|
||||
return;
|
||||
await Task.Delay(1);
|
||||
var done = await MDService.ArticoliUpdateRecord(selRec);
|
||||
currRecord = null;
|
||||
await ReloadData();
|
||||
await Task.Delay(1);
|
||||
currPage = 1;
|
||||
numRecord = newNum;
|
||||
}
|
||||
|
||||
protected async Task UpdateData()
|
||||
protected void UpdateData()
|
||||
{
|
||||
currRecord = null;
|
||||
await ReloadData();
|
||||
ReloadData();
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private string _selAzienda = "*";
|
||||
private AnagArticoliModel? currRecord = null;
|
||||
private TemplateKitModel? currRecord = null;
|
||||
private bool enabKitCount = false;
|
||||
private bool enabKitSearch = false;
|
||||
private List<AnagGruppi>? ListAziende;
|
||||
private List<AnagArticoliModel>? ListRecords;
|
||||
private List<TemplateKitModel>? ListRecords;
|
||||
private List<ListValues>? ListTipoArt;
|
||||
private List<AnagArticoliModel>? SearchRecords;
|
||||
private int minChar = 2;
|
||||
private string sCodChild = "";
|
||||
private List<TemplateKitModel>? SearchRecords;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
@@ -257,8 +304,7 @@ namespace MP.SPEC.Pages
|
||||
if (_currPage != value)
|
||||
{
|
||||
_currPage = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
ReloadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,61 +319,26 @@ namespace MP.SPEC.Pages
|
||||
if (_numRecord != value)
|
||||
{
|
||||
_numRecord = value;
|
||||
var pUpd = Task.Run(async () => await ReloadData());
|
||||
pUpd.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string selAzienda
|
||||
{
|
||||
get => _selAzienda;
|
||||
set
|
||||
{
|
||||
if (value != _selAzienda)
|
||||
{
|
||||
_selAzienda = value;
|
||||
var pUpd = Task.Run(async () =>
|
||||
{
|
||||
// svuoto cache redis...
|
||||
ConfigModel updRec = new ConfigModel()
|
||||
{
|
||||
Chiave = "AZIENDA",
|
||||
Valore = value
|
||||
};
|
||||
await MDService.ConfigUpdate(updRec);
|
||||
await MDService.ConfigResetCache();
|
||||
// ricarico
|
||||
await Task.Delay(1);
|
||||
await ReloadData();
|
||||
});
|
||||
pUpd.Wait();
|
||||
ReloadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string sCodParent { get; set; } = "";
|
||||
private bool ShowCharts { get; set; } = false;
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Seleziona record x editing
|
||||
/// </summary>
|
||||
/// <param name="selRec"></param>
|
||||
/// <returns></returns>
|
||||
private bool ArticoloDelEnabled(string codArt)
|
||||
{
|
||||
bool answ = MDService.ArticoloDelEnabled(codArt);
|
||||
return answ;
|
||||
}
|
||||
|
||||
private async Task ReloadData()
|
||||
private void ReloadData()
|
||||
{
|
||||
isLoading = true;
|
||||
SearchRecords = await MDService.ArticoliGetSearch(100000, selAzienda, SearchVal);
|
||||
ListRecords = SearchRecords.Skip(numRecord * (currPage - 1)).Take(numRecord).ToList();
|
||||
SearchRecords = MDService.TemplateKitFilt(SearchParent, SearchChild);
|
||||
ListRecords = SearchRecords
|
||||
.Skip(numRecord * (currPage - 1))
|
||||
.Take(numRecord)
|
||||
.ToList();
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace MP.SPEC.Pages
|
||||
}
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
ListMacchine = await MDService.MacchineGetFilt(selReparto);
|
||||
padCodXdl = await MDService.ConfigTryGet("padCodXdl");
|
||||
padCodXdl = await MDService.ConfigTryGetAsync("padCodXdl");
|
||||
}
|
||||
|
||||
protected async Task pgResetReq(bool doReset)
|
||||
|
||||
@@ -131,26 +131,26 @@ namespace MP.SPEC.Pages
|
||||
ListGruppiFase = allGruppiData.Where(x => x.SelEnabled).ToList();
|
||||
}
|
||||
ListStati = await MDService.AnagStatiComm();
|
||||
currAzienda = await MDService.ConfigTryGet("AZIENDA");
|
||||
padCodXdl = await MDService.ConfigTryGet("padCodXdl");
|
||||
useFasi4KeyRich = await MDService.ConfigTryGet("SPEC_KeyRichiesta");
|
||||
currAzienda = await MDService.ConfigTryGetAsync("AZIENDA");
|
||||
padCodXdl = await MDService.ConfigTryGetAsync("padCodXdl");
|
||||
useFasi4KeyRich = await MDService.ConfigTryGetAsync("SPEC_KeyRichiesta");
|
||||
// carico opzioni gestione PODL/ODL/sync
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGet("SPEC_PODL_gest");
|
||||
string SPEC_PODL_gest = await MDService.ConfigTryGetAsync("SPEC_PODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_PODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_PODL_gest, out enableStartPODL);
|
||||
}
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGet("SPEC_ODL_gest");
|
||||
string SPEC_ODL_gest = await MDService.ConfigTryGetAsync("SPEC_ODL_gest");
|
||||
if (!string.IsNullOrEmpty(SPEC_ODL_gest))
|
||||
{
|
||||
bool.TryParse(SPEC_ODL_gest, out enableStopODL);
|
||||
}
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGet("SPEC_XODL_sync");
|
||||
string SPEC_XODL_sync = await MDService.ConfigTryGetAsync("SPEC_XODL_sync");
|
||||
if (!string.IsNullOrEmpty(SPEC_XODL_sync))
|
||||
{
|
||||
bool.TryParse(SPEC_XODL_sync, out enableForceSync);
|
||||
}
|
||||
string SPEC_nArtSearch = await MDService.ConfigTryGet("SPEC_nArtSearch");
|
||||
string SPEC_nArtSearch = await MDService.ConfigTryGetAsync("SPEC_nArtSearch");
|
||||
if (!string.IsNullOrEmpty(SPEC_nArtSearch))
|
||||
{
|
||||
int.TryParse(SPEC_nArtSearch, out nArtSearch);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>Modulo MAPOSPEC </i>
|
||||
<h4>Versione: 6.16.2504.913</h4>
|
||||
<h4>Versione: 6.16.2504.919</h4>
|
||||
<br /> Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.16.2504.913
|
||||
6.16.2504.919
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>6.16.2504.913</version>
|
||||
<version>6.16.2504.919</version>
|
||||
<url>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/MP.SPEC.zip</url>
|
||||
<changelog>https://nexus.steamware.net/repository/SWS/MP-SPEC/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user