| WebUI / Pages : | |||||
| =============== | |||||
| private async Task Export() | |||||
| { | |||||
| item.DT_WORK_FORCE_ID_WORK_FORCE = listDT_WORK_FORCE_ID_WORK_FORCE!.Where(e => e.ID_WORK_FORCE == item.ID_WORK_FORCE).FirstOrDefault(); | |||||
| if(item.DATE_START>item.DATE_END) | |||||
| { | |||||
| var dtFin = item.DATE_START; | |||||
| var dtDebut = item.DATE_END; | |||||
| item.DATE_START = dtDebut; | |||||
| item.DATE_END = dtFin; | |||||
| } | |||||
| try | |||||
| { | |||||
| var resultat = await ApiService.GetExportByFiltersAsync($"api/DT_TIME_SHEET/export", item); | |||||
| if (resultat == null || resultat.Length == 0) | |||||
| { | |||||
| // Gérer le cas d'erreur ou pas de données | |||||
| ToastService.ShowInfo($"Il n'y a pas de données disponibles.", settings => { settings.Timeout = 2000; settings.IconType = IconType.None; settings.Position = ToastPosition.BottomCenter; }); | |||||
| return; | |||||
| } | |||||
| // Nom de fichier avec timestamp | |||||
| var now = DateTime.Now; | |||||
| var fileName = $"reportings_{now:yyyyMMdd_HHmmss}.xlsx"; | |||||
| // Convertir en base64 | |||||
| var base64 = Convert.ToBase64String(resultat); | |||||
| // Appel JS pour lancer le téléchargement | |||||
| await JS!.InvokeVoidAsync("downloadFileFromByteArray", fileName, base64); | |||||
| } | |||||
| catch (Exception ex) | |||||
| { | |||||
| ToastService.ShowError($"Erreur dans les exports. Faites CTRL + F5 et recommencez... Si le soucis persiste, voir avec l'administrateur.", settings => { settings.Timeout = 2000; settings.IconType = IconType.None; settings.Position = ToastPosition.BottomCenter; }); | |||||
| } | |||||
| } | |||||
| WebUI / Services : | |||||
| ================== | |||||
| public async Task<byte[]?> GetExportByFiltersAsync<T>(string url, T data) | |||||
| { | |||||
| var response = await _httpClient.PostAsJsonAsync<T>(url, data); | |||||
| if (!response.IsSuccessStatusCode) | |||||
| return null; | |||||
| return await response.Content.ReadAsByteArrayAsync(); | |||||
| } | |||||
| API / CONTROLLER | |||||
| ================ | |||||
| using Microsoft.AspNetCore.Authorization; | |||||
| using Microsoft.AspNetCore.Mvc; | |||||
| using Temporis.Domain; | |||||
| namespace Temporis.Api.Controllers | |||||
| { | |||||
| public partial class DT_TIME_SHEETController | |||||
| { | |||||
| [HttpPost("export")] | |||||
| [Authorize(Roles = "Admin,Manager")] | |||||
| public async Task<ActionResult> Export([FromBody] DT_TIME_SHEET dt_time_sheet) | |||||
| { | |||||
| var bytes = await dt_time_sheetService.ExportReportings(dt_time_sheet); | |||||
| if (bytes == null || bytes.Length == 0) | |||||
| return NotFound("Aucune donnée à exporter."); | |||||
| return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"reportings.xlsx"); | |||||
| } | |||||
| } | |||||
| } | |||||
| APPLICATION / Service : | |||||
| ======================= | |||||
| >>> D'abord : Installer le nuget ClosedXML sur le projet "Application" | |||||
| #region Exports | |||||
| public async Task<byte[]?> ExportReportings(DT_TIME_SHEET filters) | |||||
| { | |||||
| if (filters == null) | |||||
| return null; | |||||
| var lst = await dt_time_sheetRepository.GetAll_by_filters_Async(filters); | |||||
| var lstItems = lst.ToList(); | |||||
| if (lstItems == null || lstItems.Count == 0) | |||||
| return null; | |||||
| using (var workbook = new XLWorkbook()) | |||||
| { | |||||
| // Grouper les lignes par ID_TIME_SHEET | |||||
| var groupByTimeSheet = lstItems | |||||
| .GroupBy(l => l.ID_TIME_SHEET) | |||||
| .ToList(); | |||||
| foreach (var group in groupByTimeSheet) | |||||
| { | |||||
| var timeSheet = group.First().DT_TIME_SHEET; | |||||
| string nomOnglet = timeSheet?.LIBELLE ?? $"TimeSheet_{group.Key.ToString().Substring(0, 8)}"; | |||||
| // Crée l'onglet | |||||
| var worksheet = workbook.Worksheets.Add(nomOnglet); | |||||
| int row = 0; | |||||
| // Identification | |||||
| worksheet.Cell(row + 1, 1).Value = "Nom"; | |||||
| worksheet.Cell(row + 2, 1).Value = "Prénom"; | |||||
| worksheet.Cell(row + 3, 1).Value = "Début Période"; | |||||
| worksheet.Cell(row + 4, 1).Value = "Fin Période"; | |||||
| worksheet.Cell(row + 5, 1).Value = "Validation manager ?"; | |||||
| worksheet.Cell(row + 1, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row + 2, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row + 3, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row + 4, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row + 5, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row + 1, 2).Value = timeSheet!.DT_WORK_FORCE_ID_WORK_FORCE!.LAST_NAME; | |||||
| worksheet.Cell(row + 2, 2).Value = timeSheet!.DT_WORK_FORCE_ID_WORK_FORCE!.FIRST_NAME; | |||||
| worksheet.Cell(row + 3, 2).Value = timeSheet!.DATE_START.ToString("dd-MM-yyyy"); | |||||
| worksheet.Cell(row + 4, 2).Value = timeSheet!.DATE_END.ToString("dd-MM-yyyy"); | |||||
| worksheet.Cell(row + 5, 2).Value = timeSheet!.IsValidat ? "Oui" : "Non"; | |||||
| row = row + 7; | |||||
| // Entêtes de lignes | |||||
| worksheet.Cell(row, 1).Value = "Date"; | |||||
| worksheet.Cell(row, 2).Value = "Projet"; | |||||
| worksheet.Cell(row, 3).Value = "Quantité (j)"; | |||||
| worksheet.Cell(row, 4).Value = "Télétravail"; | |||||
| worksheet.Row(row).Style.Font.Bold = true; | |||||
| // Remplir les lignes | |||||
| row = row + 1; | |||||
| double nbrTeleTravail = 0; | |||||
| var lstAlternance = group.Where(e=>e.DT_PROJECT?.ID_PROJECT_TYPE == ToolsRepo.ID_PROJECT_TYPE_ALTERNANCE).ToList(); | |||||
| foreach (var line in group) | |||||
| { | |||||
| worksheet.Cell(row, 1).Value = line.DAY.ToString("dd-MM-yyyy"); | |||||
| worksheet.Cell(row, 2).Value = line.DT_PROJECT?.LIBELLE_PROJECT ?? ""; | |||||
| worksheet.Cell(row, 3).Value = line.QUANTITY; | |||||
| worksheet.Cell(row, 4).Value = line.TELETRAVAIL ? "Oui" : "Non"; | |||||
| if(line.TELETRAVAIL) | |||||
| { | |||||
| nbrTeleTravail = nbrTeleTravail + line.QUANTITY; | |||||
| } | |||||
| row++; | |||||
| } | |||||
| row = row + 2; | |||||
| worksheet.Cell(row, 1).Value = "Total télétravail (j)"; | |||||
| worksheet.Cell(row, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row, 2).Value = nbrTeleTravail; | |||||
| var lstAbs = await dt_day_offRepository.GetAll_By_ID_WORK_FORCE_And_Dates_Async(timeSheet!.ID_WORK_FORCE, timeSheet!.DATE_START, timeSheet!.DATE_END); | |||||
| var lstAbsences = lstAbs.ToList(); | |||||
| var nbrJoursOuvres = Infrastructure.Tools.NbrJoursOuvres(timeSheet!.DATE_START, timeSheet!.DATE_END); | |||||
| row = row + 2; | |||||
| worksheet.Cell(row, 1).Value = "Nbre de Tickets Restaurant"; | |||||
| worksheet.Cell(row, 1).Style.Font.Bold = true; | |||||
| worksheet.Cell(row, 2).Value = nbrJoursOuvres - lstAbsences.Count - lstAlternance.Count; | |||||
| row = row + 2; | |||||
| if (lstAbsences != null && lstAbsences.Count() > 0) | |||||
| { | |||||
| worksheet.Cell(row, 1).Value = "Absences"; | |||||
| worksheet.Cell(row, 1).Style.Font.Bold = true; | |||||
| row = row + 1; | |||||
| foreach (var item in lstAbsences) | |||||
| { | |||||
| worksheet.Cell(row, 1).Value = item.DATE_DAY_OFF.ToString("dd-MM-yyyy"); | |||||
| worksheet.Cell(row, 2).Value = item.DT_DAY_OFF!.DT_REF_DAY_OFF_TYPE!.LIBELLE_DAY_OFF_TYPE; | |||||
| row++; | |||||
| } | |||||
| } | |||||
| // Ajustement automatique des colonnes | |||||
| worksheet.Columns().AdjustToContents(); | |||||
| } | |||||
| using var stream = new MemoryStream(); | |||||
| workbook.SaveAs(stream); | |||||
| return stream.ToArray(); | |||||
| } | |||||
| } | |||||
| #endregion |