using EgwCoreLib.Razor; using Newtonsoft.Json; using WebWindowComplex; using WebWindowComplex.DTO; using static EgwCoreLib.Lux.Core.Enums; using static WebWindowComplex.LayoutConst; namespace Lux.UI.Components.Compo.Templates { public partial class TemplateRowList : IDisposable { #region Public Properties /// /// Modello dell'offerta corrente (bindato dal genitore). /// [Parameter] public TemplateModel CurrParent { get; set; } = null!; /// /// Ricerca libera da parent /// [Parameter] public string CurrSearchVal { get; set; } = ""; [Parameter] public DisplayMode DisplayMode { get; set; } = DisplayMode.Standard; [Parameter] public EventCallback EC_ReqFullPage { get; set; } [Parameter] public EventCallback EC_Updated { get; set; } #endregion Public Properties #region Public Methods /// /// Dispose sottoscrizione canale /// public void Dispose() { DLService.PipeUpdate.EA_NewMessage -= PipeUpdate_EA_NewMessage; DLService.PipePng.EA_NewMessage -= PipePng_EA_NewMessage; DLService.PipeSvg.EA_NewMessage -= PipeSvg_EA_NewMessage; DLService.PipeHwOpt.EA_NewMessage -= PipeHwOpt_EA_NewMessage; DLService.PipeProfElement.EA_NewMessage -= PipeProfElement_EA_NewMessage; DLService.PipeProfList.EA_NewMessage -= PipeProfList_EA_NewMessage; DLService.PipeShape.EA_NewMessage -= PipeShape_EA_NewMessage; } #endregion Public Methods #region Protected Properties [Inject] protected IMessageService UserMServ { get; set; } = null!; #endregion Protected Properties #region Protected Methods /// /// Verifica after render x stato interattivo pagina /// /// protected override void OnAfterRender(bool firstRender) { if (firstRender) { // JS interop or data fetches go here isInteractive = true; } } /// /// init obj /// protected override async Task OnInitializedAsync() { ConfInit(); prevJwd = ""; await ReloadBaseList(); DLService.PipeUpdate.EA_NewMessage += PipeUpdate_EA_NewMessage; DLService.PipePng.EA_NewMessage += PipePng_EA_NewMessage; DLService.PipeSvg.EA_NewMessage += PipeSvg_EA_NewMessage; DLService.PipeHwOpt.EA_NewMessage += PipeHwOpt_EA_NewMessage; DLService.PipeProfElement.EA_NewMessage += PipeProfElement_EA_NewMessage; DLService.PipeProfList.EA_NewMessage += PipeProfList_EA_NewMessage; DLService.PipeShape.EA_NewMessage += PipeShape_EA_NewMessage; } protected override async Task OnParametersSetAsync() { await ReloadDataAsync(); currPage = 1; UpdateTable(); } #endregion Protected Methods #region Private Fields private static Logger Log = LogManager.GetCurrentClassLogger(); private List AllColors = new(); private List AllConfEnvir = new(); private List AllConfGlass = new(); private List AllConfHardware = new(); private List AllConfWood = new(); private List AllRecords = new List(); private string apiUrl = ""; private List AvailColorMaterialList = new List(); private List AvailFamilyHardwareList = new List(); private List AvailGlassList = new List(); private List AvailHardwareList = new(); /// /// Lista profili da DB /// private List AvailProfileList = new(); /// /// Lista profili da Redis (old way) /// private List AvailProfileListOld = new List(); private List AvailWoodList = new List(); /// /// Base path x network share files /// private string basePath = "unsafe_uploads"; private string calcTag = "calc"; private EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS cEnvir = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW; /// /// Channel update HwOptions /// private string chHwOpt = ""; /// /// Channel update PNG /// private string chPng = ""; /// /// Channel update Profile List /// private string chProfElem = ""; /// /// Channel update Profile List /// private string chProfList = ""; /// /// Channel update Shape /// private string chShape = ""; /// /// Channel update SVG /// private string chSvg = ""; private List currAreaProfiles = new(); /// /// Predisposizione valori live SVG/JWD /// private LivePayload CurrData = new LivePayload(); /// /// Modalit� editint attiva /// private EditMode CurrEditMode = EditMode.None; private Dictionary currGroupShape = new(); private Dictionary currHwOption = new(); private int currPage = 1; private string currPng = ""; private int CurrSellingItemId = 0; private string currSvg = ""; private TemplateRowModel? EditRecord = null; private string genericBasePath = ""; private string imgBasePath = ""; /// /// Semaforo x definire se sia gia in modalita ionterattiva o di prerendering /// private bool isInteractive = false; private bool isLoading = false; private List ListFilt = new List(); private List ListRecords = new List(); private List ListSellItems = new List(); private int numRecord = 5; /// /// Versione precedente JWD x test e confronto /// private string prevJwd = ""; /// /// Dizionario richieste /// private Dictionary reqDict = new Dictionary(); private TemplateRowModel? SelRecord = null; /// /// Configurazione elenchi anagrafiche /// private BaseListPayload SetupList = new BaseListPayload(); private int totalCount = 0; private BootstrapModal Modal = new(); private string mTitle = ""; private string mMessage = ""; private BootstrapModal.ModalMode mMode = BootstrapModal.ModalMode.ND; private Dictionary modalOpt = new Dictionary(); /// /// Elenco delle richieste pensding da DB x RigaOfferta corrente /// private Dictionary CurrPendReq = new(); /// /// Dizionario traduzioni x componente WebWindowManager /// private Dictionary? WindowDict = new(); #endregion Private Fields #region Private Properties [Inject] private IConfigDataService CDService { get; set; } = null!; [Inject] private IConfGlassService CGService { get; set; } = null!; [Inject] private IConfiguration Config { get; set; } = null!; [Inject] private IConfProfileService CPService { get; set; } = null!; [Inject] private ICalcRuidService CRService { get; set; } = null!; [Inject] private ICalcRequestService CService { get; set; } = null!; [Inject] private IConfWoodService CWService { get; set; } = null!; /// /// Servizi di accesso ai dati iniettati dal framework. /// [Inject] private IDataLayerServices DLService { get; set; } = null!; [Inject] private IEnvirParamService EPService { get; set; } = null!; [Inject] private IGenValService GVService { get; set; } = default!; [Inject] private IImageCacheService ICService { get; set; } = null!; [Inject] private IJSRuntime JSRuntime { get; set; } = null!; [Inject] private ISellingItemService SIService { get; set; } = null!; /// /// ID Template corrente /// private int TemplateID { get => CurrParent.TemplateID; } [Inject] private ITemplateService TplService { get; set; } = default!; [Inject] private ITemplateRowService TRService { get; set; } = default!; #endregion Private Properties #region Private Methods /// /// Effettua vera richiesta della BOM /// /// private async Task callRefreshProfList() { Dictionary DictExec = new Dictionary(); var cMode = Egw.Window.Data.Enums.QuestionModes.CONFIG; var cSubMode = Egw.Window.Data.Enums.QuestionConfSubModes.PROFILELIST; // compongo righiesta string reqUid = "Default"; DictExec.Add("Mode", $"{(int)cMode}"); DictExec.Add("UID", reqUid); // creo registrazione richiesta... var ruid = await CRService.AddRequestAsync($"{cEnvir}", $"{cMode}-{cSubMode}", reqUid); // aggiungo RUID effettivo DictExec.Add("RUID", ruid); DictExec.Add("SubMode", $"{(int)cSubMode}"); CalcRequestDTO req = new CalcRequestDTO() { EnvType = cEnvir, DictExec = DictExec }; // chiamo la chiamata POST alla API, che manda la richiesta via REDIS await CService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{reqUid}", req); } private string CheckSelect(TemplateRowModel curRec) { string answ = ""; if (SelRecord != null) { answ = curRec.TemplateRowID == SelRecord.TemplateRowID ? "table-info" : ""; } return answ; } /// /// Chiude edit andando eventualmente a salvare /// /// /// private async Task CloseEdit(bool doSave) { // Proseguo solo se sono in interattivo (NO prerender pagina) if (isInteractive) { // ...se ho editing if (EditRecord != null) { // SE richiesto salvataggio... if (doSave) { // salvo su DB! await TRService.UpdateSerStructAsync(EditRecord.TemplateRowID, prevJwd); // salvo nel record corrente! EditRecord.SerStruct = prevJwd; } else // altrimenti ricalcolo valore salvato { prevJwd = EditRecord.SerStruct; CurrData.CurrJwd = EditRecord.SerStruct; } // aggiorno nel dizionari if (reqDict.ContainsKey("SerializedData")) { reqDict["SerializedData"] = prevJwd; } // chiamo comunque update IMG await reqImgUpdate(EditRecord); // reimposto il select record... SelRecord = EditRecord; // ora resetto EditRecord = null; CurrEditMode = EditMode.None; } } } /// /// Chiude edit con preprocess x caso JWD /// /// /// private async Task CloseEditJwd(DataSave infoSave) { prevJwd = infoSave.currJwd; // elimino richiesta full // reset preview await CloseEdit(infoSave.ForceSave); await Task.Delay(200); CurrData.SvgPreview = ""; await EC_ReqFullPage.InvokeAsync(false); } private void ConfInit() { basePath = Config.GetValue("ServerConf:FileSharePath") ?? "unsafe_uploads"; apiUrl = Config.GetValue("ServerConf:Prog.ApiUrl") ?? ""; imgBasePath = Config.GetValue("ServerConf:ImageBaseUrl") ?? ""; genericBasePath = Config.GetValue("ServerConf:GenericBaseUrl") ?? ""; calcTag = Config.GetValue("ServerConf:CalcTag") ?? "calc"; chHwOpt = Config.GetValue("ServerConf:ChannelHwOpt") ?? ""; chPng = Config.GetValue("ServerConf:ChannelPng") ?? ""; chProfElem = Config.GetValue("ServerConf:ChannelProfElem") ?? ""; chProfList = Config.GetValue("ServerConf:ChannelProfList") ?? ""; chShape = Config.GetValue("ServerConf:ChannelShape") ?? ""; chSvg = Config.GetValue("ServerConf:ChannelSvg") ?? ""; } /// /// Eliminazione file (old) /// /// Nome secure da impiegare /// Contenuto file private bool DeleteOldFile(string folderPath, string secureName) { bool answ = false; if (!string.IsNullOrEmpty(folderPath)) { // calcolo path file... string filePath = Path.Combine(basePath, folderPath, secureName); // se esiste... if (File.Exists(filePath)) { File.Delete(filePath); } } return answ; } /// /// Esecuzione azione richiesta /// /// Azione richiesta private void DoAction(LayoutConst.DataAction actReq) { switch (actReq) { case LayoutConst.DataAction.None: break; case LayoutConst.DataAction.ResetDictShape: CurrData.DictShape = new Dictionary(); break; case LayoutConst.DataAction.ResetHwOpt: CurrData.DictOptionsXml = new Dictionary(); break; case DataAction.ResetDimElem: CurrData.ProfElementList = new List(); break; default: break; } } private void DoAdd() { // valori helper DateTime adesso = DateTime.Now; int newRow = 1 + (AllRecords.Count > 0 ? AllRecords.Max(x => x.RowNum) : 0); EditRecord = new TemplateRowModel() { TemplateID = CurrParent.TemplateID, Envir = CurrParent.Envir, Name = $"New Template ITEM {adesso.Year}", RowNum = newRow, SerStruct = "{}", SellingItemID = CurrSellingItemId }; } private async Task DoClone(TemplateRowModel rec2clone) { mTitle = "Attenzione"; mMessage = "Confermi di voler duplicare la riga corrente?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; // calcolo indice riga... int numRow = totalCount + 1; TemplateRowModel newRec = new TemplateRowModel() { AwaitBom = true, AwaitPrice = true, Envir = rec2clone.Envir, FileName = rec2clone.FileName, FileResource = rec2clone.FileResource, FileSize = rec2clone.FileSize, Inserted = DateTime.Now, ItemBOM = rec2clone.ItemBOM, ItemSteps = rec2clone.ItemSteps, Note = rec2clone.Note, TemplateID = TemplateID, TemplateRowUID = "", Qty = rec2clone.Qty, RowNum = numRow, SellingItemID = rec2clone.SellingItemID, SerStruct = rec2clone.SerStruct, StepCost = rec2clone.StepCost, StepPrice = rec2clone.StepPrice, }; // salvo sul DB await TRService.UpsertAsync(newRec); // chiamo update record che non hanno UID x questo ordine var list2fix = await TRService.FixRowUidAsync(TemplateID); if (list2fix != null && list2fix.Count > 0) { // rileggo i miei record... await ReloadDataAsync(); var listCalc = SorListCalc(); foreach (var item in listCalc) { // se UID � tra quelli da ricalcolare... if (list2fix.Contains(item.TemplateRowUID)) { // chiedo BOM e immagine await reqBomUpdate(item); } } } await ReloadDataAsync(); UpdateTable(); } private void DoClose() { SelRecord = null; EditRecord = null; } /// /// Esegue lettura file + invio richiesta specifica /// /// /// private async Task DoDelete(TemplateRowModel curRec) { mTitle = "Attenzione"; mMessage = $"Confermi di voler eliminare il template selezionato?\n" + $"Env: {curRec.Envir} | {curRec.Name}"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; await TRService.DeleteAsync(curRec); // elimino cache img await ICService.DeleteSvgAsync(curRec.TemplateRowUID, curRec.Envir); // rileggo await ReloadDataAsync(); UpdateTable(); } private Task DoEdit(TemplateRowModel curRec) { EditRecord = curRec; // chiamo comunque update IMG return reqImgUpdate(curRec); } /// /// Edit del file: /// - abilitazione fileUpload /// - anteprima grande (live) /// /// private Task DoEditFile(TemplateRowModel curRec) { EditRecord = curRec; /// modalit�edit: gestione JWD CurrEditMode = EditMode.File; return EC_ReqFullPage.InvokeAsync(true); } /// /// Apre editor finestre del record richiesto /// /// private async Task DoEditJwd(TemplateRowModel curRec) { EditRecord = curRec; /// modalit�edit: gestione JWD CurrEditMode = EditMode.SerStruc; // preparazione dati da record corrente PrepareWindowData(EditRecord.SerStruct); // chiamo comunque update IMG await reqImgUpdate(EditRecord); // reset prev prevJwd = ""; await EC_ReqFullPage.InvokeAsync(true); } private async Task DoRecalcTemplate(bool forceResetCalc) { isLoading = true; if (forceResetCalc) { await setAwaitPrice(true, false); UpdateTable(); await InvokeAsync(StateHasChanged); await Task.Delay(300); } await TplService.UpdateCostAsync(TemplateID); if (forceResetCalc) { await Task.Delay(300); await setAwaitPrice(false, true); } // rileggo dati await ReloadDataAsync(); UpdateTable(); isLoading = false; await EC_Updated.InvokeAsync(true); } private async Task DoReset() { EditRecord = null; SelRecord = null; await ReloadDataAsync(); UpdateTable(); } /// /// Salva record ed avanza compilazione /// /// /// private async Task DoSave(TemplateRowModel updRec) { // salvo record await TRService.UpsertAsync(updRec); // chiamo comunque update IMG await reqImgUpdate(updRec); EditRecord = null; SelRecord = null; // faccio fix UID del gruppo... await TRService.FixRowUidAsync(TemplateID); await ReloadDataAsync(); UpdateTable(); } /// /// Salvataggio del JWD aggiornato nella mia riga di offerta /// /// private async Task ExecRequest(Dictionary CurrArgs) { // Proseguo solo se sono in interattivo (NO prerender pagina) if (isInteractive) { // ...se ho editing if (EditRecord != null) { // SE contiene il mio Jwd... if (CurrArgs.ContainsKey("SerializedData")) { string serStruct = CurrArgs["SerializedData"]; // controllo SE variato... if (!prevJwd.Equals(serStruct) || !EgwCoreLib.Utils.DictUtils.DictAreEqual(reqDict, CurrArgs)) { // aggiorno val prev reqDict = CurrArgs; prevJwd = serStruct; // aggiorno live data CurrData.CurrJwd = serStruct; // chiamo richiesta update CalcRequestDTO calcRequestDTO = new CalcRequestDTO(); calcRequestDTO.EnvType = EditRecord.Envir; calcRequestDTO.DictExec = reqDict; // chiamo la chiamata POST alla API, che manda la richiesta via REDIS await ICService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{EditRecord.TemplateRowUID}", calcRequestDTO); } } } } } /// /// Path da parent record /// /// /// private string FolderPath(int objID) { return $"TP-{objID:X8}"; } /// /// Display fileSize scalato /// /// /// private string fSize(long size) { return EgwCoreLib.Utils.FileHelpers.SizeSuffix(size, 1); } /// /// Calcola src immagine direttamente da modello dati + base path /// /// /// private string imgSrc(string imgUrl) { return $"{apiUrl}/{imgBasePath}/{imgUrl}"; } /// /// Restituisce il contenuto del file salvato /// /// /// /// private string LoadFileContent(string folderPath, string secureName) { string answ = ""; if (!string.IsNullOrEmpty(folderPath)) { try { // calcolo path file... string filePath = Path.Combine(basePath, folderPath, secureName); if (File.Exists(filePath)) { answ = File.ReadAllText(filePath); } } catch (Exception exc) { Log.Error($"Exception on LoadFileContent{Environment.NewLine}{exc}"); } } return answ; } /// /// Aggiornamento costing completo: /// - verifica UID /// - ricalcolo BOM /// - update prezzi /// /// private async Task OfferUpdateAllCosting() { mTitle = "Attenzione"; mMessage = "Confermi di voler ricalcolare/validare in toto i Template del gruppo?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; // metto a waiting tutte le righe con bom... var listCalc = SorListCalc(); foreach (var item in listCalc) { await TRService.UpdateAwaitStateAsync(item.TemplateRowID, true, true); } await InvokeAsync(StateHasChanged); // verifica preliminare UID await TRService.FixRowUidAsync(TemplateID); // ricalcolo di tutte le BOM e relativi prezzi... foreach (var item in listCalc) { // chiedo BOM e immagine await reqBomUpdate(item); } } /// /// Ricevuto HwOpt, processo /// /// /// private async void PipeHwOpt_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly dati HwOpt if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.Equals($"{chHwOpt}:{EditRecord.TemplateRowUID}")) { // se non è vuoto deserializzo if (currArgs.newMessage.Count() > 2) { var rawDict = JsonConvert.DeserializeObject>(currArgs.newMessage) ?? new Dictionary(); currHwOption = rawDict; } else { currHwOption = new Dictionary(); } // salvo in live data... CurrData.DictOptionsXml = currHwOption; } await InvokeAsync(StateHasChanged); } } } private async void PipePng_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly PNG da mostrare if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.Equals($"{chPng}:{EditRecord.TemplateRowUID}")) { currPng = currArgs.newMessage; } await InvokeAsync(StateHasChanged); } } } /// /// Ricevuto ProfElem, processo /// /// /// private async void PipeProfElement_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly Profile if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.StartsWith($"{chProfElem}:{EditRecord.TemplateRowUID}")) { // deserializzo il dizionario delle risposte... var rawDict = JsonConvert.DeserializeObject>(currArgs.newMessage); currAreaProfiles = rawDict ?? new List(); CurrData.ProfElementList = currAreaProfiles; } await InvokeAsync(StateHasChanged); } } } /// /// Ricevuta profile list, processo /// /// /// private async void PipeProfList_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly ProfileListAsync if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.Equals($"{chProfList}:{EditRecord.TemplateRowUID}")) { try { // nuova gestione da DB: attendo 500ms che il DB sia aggiornato await Task.Delay(500); // rileggo DB x info profili AvailProfileList = await CPService.GetAllAsync(); // converto i profili nel nuovo formato x payload... var profList = AvailProfileList.Select(x => new ProfilePayload() { ProfileName = x.Code, ThresholdList = x.ThresholdList, ParameterDict = x.ProfileDataDict }).ToList(); SetupList.ProfileList = profList; } catch { } } await InvokeAsync(StateHasChanged); } } } /// /// Ricevuta shape, procersso /// /// /// private async void PipeShape_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly SVG da mostrare if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.StartsWith($"{chShape}:{EditRecord.TemplateRowUID}")) { // deserializzo il dizionario delle risposte... var rawDict = JsonConvert.DeserializeObject>(currArgs.newMessage); currGroupShape = rawDict ?? new Dictionary(); CurrData.DictShape = currGroupShape; } await InvokeAsync(StateHasChanged); } } } /// /// Ricevuto SVG, se � il mio lo aggiorno... /// /// /// private async void PipeSvg_EA_NewMessage(object? sender, EventArgs e) { // vale SOLO SE sono in editing... if (EditRecord != null) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly SVG da mostrare if (!string.IsNullOrEmpty(currArgs.newMessage)) { if (currArgs.msgUid.Equals($"{chSvg}:{EditRecord.TemplateRowUID}")) { currSvg = currArgs.newMessage; // salvo in live data... CurrData.SvgPreview = currSvg; } await InvokeAsync(StateHasChanged); } } } /// /// Task verifica update ricevuti /// /// /// private async void PipeUpdate_EA_NewMessage(object? sender, EventArgs e) { // aggiorno visualizzazione PubSubEventArgs currArgs = (PubSubEventArgs)e; // conversione on-the-fly SVG da mostrare if (!string.IsNullOrEmpty(currArgs.newMessage)) { // cerco se faccia parte dei record correnti... var recFound = AllRecords.Any(x => x.TemplateRowUID == currArgs.newMessage); if (recFound) { isLoading = true; await Task.Delay(1); // se si tratta dell'UID corrente --> fa update await DoRecalcTemplate(false); await InvokeAsync(StateHasChanged); } } await Task.Delay(1); } /// /// Preparazione dati x componente edit JWD /// /// private void PrepareWindowData(string currJwd) { // converto i profili nel nuovo formato x payload... var profList = AvailProfileList.Select(x => new ProfilePayload() { ProfileName = x.Code, ThresholdList = x.ThresholdList, ParameterDict = x.ProfileDataDict }).ToList(); // preparo conf oggetti x controllo SetupList = new BaseListPayload() { ColorMaterial = AvailColorMaterialList, FamilyHardware = AvailFamilyHardwareList, Glass = AvailGlassList, Hardware = AvailHardwareList, Wood = AvailWoodList, ProfileList = profList }; CurrData = new LivePayload() { CurrJwd = currJwd, SvgPreview = "" //currSvg }; } /// /// init classi configurazione /// /// private async Task ReloadBaseList() { // lettura config setup varie da DB/Cache Redis AllConfEnvir = await EPService.GetAllAsync(); AllConfGlass = await CGService.GetAllAsync(); AvailProfileList = await CPService.GetAllAsync(); // FixMe Todo: eliminare da REDIS e usare elenco DB solamente... var rawProfiles = await CDService.ProfileListAsync(cEnvir, "Default"); // se fosse vuoto chiamo update... if (rawProfiles == null || rawProfiles.Count == 0) { await callRefreshProfList(); // aspetto 200ms... e richiedo! await Task.Delay(200); rawProfiles = await CDService.ProfileListAsync(cEnvir, "Default"); } AvailProfileListOld = rawProfiles; var rawHw = await CDService.HwModelListAsync(cEnvir, "HW.AGB"); // hw filtro solo validi... AllConfHardware = rawHw .Where(x => !x.FamilyName.Equals(x.Description, StringComparison.OrdinalIgnoreCase)) .ToList(); AllConfWood = await CWService.GetAllAsync(); AllColors = await GVService.GetFiltAsync("WoodCol"); // conversione tipi AvailGlassList = AllConfGlass .Select(x => x.Description) .ToList(); AvailFamilyHardwareList = AllConfHardware .DistinctBy(x => x.FamilyName) .OrderBy(x => x.FamilyName) .Select(x => x.FamilyName) .ToList(); AvailHardwareList = AllConfHardware .Select(x => new Egw.Window.Data.Hardware(x.Id, x.FamilyName, x.Description, x.OpeningType, x.Shape, x.SashQty, x.SashPosition)) .ToList(); AvailWoodList = AllConfWood .Select(x => x.Description) .ToList(); // FixMe Todo: aggiunta profili (manca anche nel costruttore...) AvailColorMaterialList = AllColors .OrderBy(x => x.Index) .Select(x => x.ValString) .ToList(); } private async Task ReloadDataAsync() { // leggo i selling items ListSellItems = await SIService.GetByEnvirAsync(CurrParent.Envir); // leggo i dati principali if (CurrParent != null) { AllRecords = await TRService.GetByParentAsync(CurrParent.TemplateID); } else { AllRecords.Clear(); } } /// /// Effettua vera richiesta della BOM /// /// /// private async Task reqBomUpdate(TemplateRowModel currRec) { // salvo richiesta BOM su record currRec.AwaitBom = true; currRec.AwaitPrice = true; await TRService.UpdateAwaitStateAsync(currRec.TemplateRowID, true, true); // preparo la domanda serializzata Dictionary DictExec = new Dictionary(); // verifico parametri da conf envir... var envRec = AllConfEnvir.FirstOrDefault(x => x.EnvirID == currRec.Envir); string serKey = envRec != null ? envRec.SerStrucKey : "SerializedData"; // cablata la BOM DictExec.Add("Mode", $"{(int)Egw.Window.Data.Enums.QuestionModes.BOM}"); // UID cablato x ora... DictExec.Add("UID", currRec.TemplateRowUID); // aggiungo file secondo ambiente... switch (currRec.Envir) { case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW: DictExec.Add(serKey, currRec.SerStruct); break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET: // rileggo da file... string folderPath = FolderPath(currRec.TemplateID); string rawData = LoadFileContent(folderPath, currRec.FileResource); DictExec.Add(serKey, rawData); DictExec.Add("FileName", currRec.FileName); break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL: default: break; } CalcRequestDTO req = new CalcRequestDTO() { EnvType = currRec.Envir, DictExec = DictExec }; await InvokeAsync(StateHasChanged); // chiamo la chiamata POST alla API, che manda la richiesta via REDIS await CService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{currRec.TemplateRowUID}", req); } /// /// Effettua richiesta update IMG /// /// /// private async Task reqImgUpdate(TemplateRowModel currRec) { // preparo la domanda serializzata Dictionary DictExec = new Dictionary(); string rawData = ""; // verifico parametri da conf envir... var envRec = AllConfEnvir.FirstOrDefault(x => x.EnvirID == currRec.Envir); string serKey = envRec != null ? envRec.SerStrucKey : "SerializedData"; // cablata la generazione IMG DictExec.Add("Mode", $"{(int)Egw.Window.Data.Enums.QuestionModes.PREVIEW}"); // UID cablato x ora... DictExec.Add("UID", currRec.TemplateRowUID); // aggiungo file secondo ambiente... switch (currRec.Envir) { case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW: DictExec.Add(serKey, currRec.SerStruct); if (DictExec.ContainsKey(serKey)) { rawData = DictExec[serKey]; } break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET: // rileggo da file... string folderPath = FolderPath(currRec.TemplateID); rawData = LoadFileContent(folderPath, currRec.FileResource); DictExec.Add(serKey, rawData); DictExec.Add("FileName", currRec.FileName); break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL: default: break; } // Procedo SOLO SE i dati serializzati sono + di "{}" if (!string.IsNullOrEmpty(rawData) && rawData.Length > 2) { CalcRequestDTO req = new CalcRequestDTO() { EnvType = currRec.Envir, DictExec = DictExec }; await InvokeAsync(StateHasChanged); // chiamo la chiamata POST alla API, che manda la richiesta via REDIS await CService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{currRec.TemplateRowUID}", req); } } /// /// Lancia la richiesta di ricaolo della BOM dal JWD (o equivalente) /// /// private async Task RequestBom(TemplateRowModel currRec) { mTitle = "Attenzione"; mMessage = "Confermi di voler ricalcolare la BOM?"; mMode = BootstrapModal.ModalMode.Confirm; modalOpt = new(); modalOpt.Add(true, "Si"); modalOpt.Add(false, "No"); if (!await Modal!.ShowAsync()) return; await reqBomUpdate(currRec); } /// /// Salvataggio dei dati del file caricato /// /// Dizionario info file private void SaveFile(Dictionary fileDict) { // verifico di essere in edit... if (EditRecord != null) { string folderPath = FolderPath(EditRecord.TemplateID); // verifico di avere parametri... if (fileDict != null && fileDict.Count > 0) { string secureName = ""; string content = ""; if (fileDict.ContainsKey("secureName")) { secureName = fileDict["secureName"]; } if (fileDict.ContainsKey("content")) { content = fileDict["content"]; } if (!string.IsNullOrEmpty(folderPath) && !string.IsNullOrEmpty(secureName) && !string.IsNullOrEmpty(content)) { // salvo! SaveFileContent(folderPath, secureName, content); } } // altrimenti signifca cleanup eventuale vecchio file... else { DeleteOldFile(folderPath, EditRecord.FileResource); } } } /// /// Esegue salvataggio del file ricevuto /// /// Path relativo x file (tipicamente UID parent order) /// Nome secure da impiegare /// Contenuto file private bool SaveFileContent(string folderPath, string secureName, string content) { bool answ = false; if (!string.IsNullOrEmpty(folderPath)) { // calcolo path file... string filePath = Path.Combine(basePath, folderPath, secureName); string? directoryPath = Path.GetDirectoryName(filePath); try { if (!string.IsNullOrEmpty(directoryPath)) { Directory.CreateDirectory(directoryPath); } File.WriteAllText(filePath, content); } catch (Exception exc) { Log.Error($"Exception on save{Environment.NewLine}{exc}"); } } return answ; } private void SaveNumRec(int newNum) { numRecord = newNum; UpdateTable(); } private void SavePage(int newNum) { currPage = newNum; UpdateTable(); } private async Task setAwaitPrice(bool awaitPrice, bool flushCache) { foreach (var item in AllRecords) { item.AwaitPrice = awaitPrice; await TRService.UpdateAwaitStateAsync(item.TemplateRowID, null, awaitPrice, flushCache); } } /// /// Verifia ammissibilit� display btn ricalcolo BOM da item /// /// /// private bool ShowBom(TemplateRowModel reqItem) { bool answ = false; switch (reqItem.Envir) { case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WINDOW: answ = !string.IsNullOrEmpty(reqItem.SerStruct) && reqItem.SerStruct.Length > 2; break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.WALL: case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.CABINET: // da cambiare con ricerca file su disco?!? answ = !string.IsNullOrEmpty(reqItem.FileResource) && !string.IsNullOrEmpty(reqItem.FileName); break; case EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.NULL: default: break; } return answ; } /// /// Elenco Rows calcolabili: /// - contengono serializzazione come JWD /// - contengono file come BTL /// private List SorListCalc() { var rawList = AllRecords .Where(x => (!string.IsNullOrEmpty(x.SerStruct) && x.SerStruct.Length > 2) || (!string.IsNullOrEmpty(x.FileName) && !string.IsNullOrEmpty(x.FileResource))) .ToList(); return rawList ?? new List(); } private void UpdateTable() { //ListFilt.Clear(); ListFilt = AllRecords; if (!string.IsNullOrEmpty(CurrSearchVal)) { ListFilt = AllRecords .Where(x => x.Name.Contains(CurrSearchVal, StringComparison.InvariantCultureIgnoreCase) || x.TemplateRowUID.Contains(CurrSearchVal, StringComparison.InvariantCultureIgnoreCase)) .ToList(); } totalCount = ListFilt.Count; // gestione paginazione ListRecords = ListFilt .Skip(numRecord * (currPage - 1)) .Take(numRecord) .ToList(); } private async Task UploadFile(InputFileChangeEventArgs e) { // Proseguo solo se sono in interattivo (NO prerender pagina) if (isInteractive) { if (EditRecord != null) { // init dizionari arg richiesta update Dictionary fileArgs = new Dictionary(); // leggo il contenuto del PRIMO (singolo) file IBrowserFile file = e.File; // limite file size (al momento 10 MB) var maxAllowedSize = 10 * 1024 * 1024; using var stream = file.OpenReadStream(maxAllowedSize); using var reader = new StreamReader(stream); string rawContent = await reader.ReadToEndAsync(); // calcolo il nome del file trusted... string trustedFileName = Path.GetRandomFileName(); EditRecord.FileResource = trustedFileName; EditRecord.FileName = file.Name; EditRecord.FileSize = rawContent.LongCount(); // salvo sul DB i dati (nome, nome sicuro, size...) await TRService.UpdateFileDataAsync(EditRecord); // parametri richiesta fileArgs.Add("Mode", $"{(int)Egw.Window.Data.Enums.QuestionModes.PREVIEW}"); fileArgs.Add("SubMode", "2"); fileArgs.Add("FileName", $"{file.Name}"); fileArgs.Add("Height", "1200"); fileArgs.Add("Width", "1800"); //fileArgs.Add("Btl", rawContent); fileArgs.Add("SerializedData", rawContent); // invio! CalcRequestDTO calcRequestDTO = new CalcRequestDTO(); calcRequestDTO.EnvType = EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS.BEAM; calcRequestDTO.DictExec = fileArgs; await ICService.CallRestPost($"{apiUrl}/{genericBasePath}", $"{calcTag}/{EditRecord.TemplateRowUID}", calcRequestDTO); } } } /// /// Aggiorna valore corrente reqPending x salvare poi con JWD su richiesta /// /// /// private void DoUpdatePend(Dictionary newPendReq) { CurrPendReq = newPendReq; } /// /// Traduzione delle voci richieste tramite dizionario /// /// /// private void DoTranslate(List args) { if (args != null && args.Count > 0) { // aggiorno WindowDict con i lemmi richiesti Dictionary tmpDict = new(); foreach (var item in args) { tmpDict.Add(item, Traduci(item)); } WindowDict = tmpDict; } } /// /// Rieseguo traduzione /// /// private void UserMServ_EA_LangChanged() { // se ho già un dizionario tradotto... if (WindowDict != null && WindowDict.Count > 0) { var listTerm = WindowDict.Select(x => x.Key).ToList(); string langCode = UserMServ.UserLang; // aggiorno WindowDict con i lemmi richiesti Dictionary tmpDict = new(); foreach (var item in listTerm) { tmpDict.Add(item, Traduci(item, langCode)); } WindowDict = tmpDict; } } #endregion Private Methods } }