Gestite immagini allegate
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SteUp.Shared.Core.Entities;
|
||||
|
||||
namespace SteUp.Data.LocalDb;
|
||||
@@ -23,5 +24,12 @@ public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(op
|
||||
|
||||
modelBuilder.Entity<Scheda>()
|
||||
.HasIndex(x => new { x.CodMdep, x.Data, x.Rilevatore });
|
||||
|
||||
modelBuilder.Entity<Scheda>()
|
||||
.Property(x => x.ImageNames)
|
||||
.HasConversion(
|
||||
v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
|
||||
v => JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions?)null) ?? new List<string>()
|
||||
);
|
||||
}
|
||||
}
|
||||
105
SteUp.Data/Migrations/20260223154219_AddListImage.Designer.cs
generated
Normal file
105
SteUp.Data/Migrations/20260223154219_AddListImage.Designer.cs
generated
Normal file
@@ -0,0 +1,105 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using SteUp.Data.LocalDb;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SteUp.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20260223154219_AddListImage")]
|
||||
partial class AddListImage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||
|
||||
modelBuilder.Entity("SteUp.Shared.Core.Entities.Ispezione", b =>
|
||||
{
|
||||
b.Property<string>("CodMdep")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateOnly>("Data")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Rilevatore")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Stato")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("CodMdep", "Data", "Rilevatore");
|
||||
|
||||
b.ToTable("Ispezioni");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SteUp.Shared.Core.Entities.Scheda", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ActivityTypeId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CodJfas")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CodMdep")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateOnly>("Data")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("DescrizioneReparto")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ImageNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Note")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Responsabile")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Rilevatore")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Scadenza")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CodMdep", "Data", "Rilevatore");
|
||||
|
||||
b.ToTable("Schede");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SteUp.Shared.Core.Entities.Scheda", b =>
|
||||
{
|
||||
b.HasOne("SteUp.Shared.Core.Entities.Ispezione", "Ispezione")
|
||||
.WithMany("Schede")
|
||||
.HasForeignKey("CodMdep", "Data", "Rilevatore")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ispezione");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("SteUp.Shared.Core.Entities.Ispezione", b =>
|
||||
{
|
||||
b.Navigation("Schede");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
28
SteUp.Data/Migrations/20260223154219_AddListImage.cs
Normal file
28
SteUp.Data/Migrations/20260223154219_AddListImage.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace SteUp.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddListImage : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "ImageNames",
|
||||
table: "Schede",
|
||||
type: "TEXT",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ImageNames",
|
||||
table: "Schede");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace SteUp.Data.Migrations
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.13");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "10.0.3");
|
||||
|
||||
modelBuilder.Entity("SteUp.Shared.Core.Entities.Ispezione", b =>
|
||||
{
|
||||
@@ -58,6 +58,9 @@ namespace SteUp.Data.Migrations
|
||||
b.Property<string>("DescrizioneReparto")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ImageNames")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Note")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using SteUp.Shared.Core.Dto;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using SteUp.Shared.Core.Dto;
|
||||
using SteUp.Shared.Core.Entities;
|
||||
using SteUp.Shared.Core.Helpers;
|
||||
using SteUp.Shared.Core.Interface.System;
|
||||
|
||||
@@ -80,6 +82,80 @@ public class AttachedService : IAttachedService
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<AttachedDto> ConvertToDto(FileInfo file, AttachedDto.TypeAttached type)
|
||||
{
|
||||
var (origUrl, thumbUrl) = await SaveAndCreateThumbAsync(
|
||||
await File.ReadAllBytesAsync(file.FullName),
|
||||
file.Name
|
||||
);
|
||||
|
||||
return new AttachedDto
|
||||
{
|
||||
Name = file.Name,
|
||||
Path = file.FullName,
|
||||
TempPath = origUrl,
|
||||
ThumbPath = thumbUrl,
|
||||
Type = type,
|
||||
SavedOnAppData = true
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<List<AttachedDto>?> GetInspectionFiles(Ispezione ispezione)
|
||||
{
|
||||
var baseDir = FileSystem.AppDataDirectory;
|
||||
var inspectionDir = Path.Combine(baseDir, $"attached_{GetInspectionKey(ispezione)}");
|
||||
var directory = new DirectoryInfo(inspectionDir);
|
||||
|
||||
if (!directory.Exists) return null;
|
||||
|
||||
var fileList = directory.GetFiles().ToList();
|
||||
|
||||
var returnList = new List<AttachedDto>();
|
||||
foreach (var file in fileList)
|
||||
{
|
||||
returnList.Add(await ConvertToDto(file, AttachedDto.TypeAttached.Image));
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public async Task<string?> SaveInspectionFile(Ispezione ispezione, byte[] file, string fileName,
|
||||
CancellationToken ct)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(ispezione);
|
||||
ArgumentNullException.ThrowIfNull(file);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(fileName);
|
||||
|
||||
var baseDir = FileSystem.AppDataDirectory;
|
||||
var inspectionDir = Path.Combine(baseDir, $"attached_{GetInspectionKey(ispezione)}");
|
||||
if (!Directory.Exists(inspectionDir)) Directory.CreateDirectory(inspectionDir);
|
||||
|
||||
var filePath = Path.Combine(inspectionDir, fileName);
|
||||
await File.WriteAllBytesAsync(filePath, file, ct);
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public bool RemoveInspectionFile(Ispezione ispezione, string fileName)
|
||||
{
|
||||
var baseDir = FileSystem.AppDataDirectory;
|
||||
var inspectionDir = Path.Combine(baseDir, $"attached_{GetInspectionKey(ispezione)}");
|
||||
|
||||
if (!Directory.Exists(inspectionDir)) return false;
|
||||
if (string.IsNullOrWhiteSpace(fileName)) return false;
|
||||
|
||||
var filePath = Path.Combine(inspectionDir, fileName);
|
||||
|
||||
if (!File.Exists(filePath)) return false;
|
||||
|
||||
File.Delete(filePath);
|
||||
|
||||
if (!Directory.EnumerateFileSystemEntries(inspectionDir).Any())
|
||||
Directory.Delete(inspectionDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<string> SaveToTempStorage(Stream file, string fileName, CancellationToken ct = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(file);
|
||||
@@ -146,4 +222,7 @@ public class AttachedService : IAttachedService
|
||||
var name = Path.GetFileName(fileName);
|
||||
return Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, '_'));
|
||||
}
|
||||
|
||||
private static string GetInspectionKey(Ispezione ispezione) =>
|
||||
$"{ispezione.CodMdep}_{ispezione.Data:ddMMyyyy}_{ispezione.Rilevatore.ToLower()}";
|
||||
}
|
||||
@@ -49,7 +49,13 @@
|
||||
</MudSelectExtended>
|
||||
</CardFormModal>
|
||||
|
||||
@if (!AttachedList.IsNullOrEmpty())
|
||||
@if (FileLoading)
|
||||
{
|
||||
<div class="container-attached">
|
||||
<MudProgressLinear Color="Color.Primary" Indeterminate="true" Class="my-3"/>
|
||||
</div>
|
||||
}
|
||||
else if (!AttachedList.IsNullOrEmpty())
|
||||
{
|
||||
<div class="container-attached">
|
||||
<div class="scroll-attached">
|
||||
@@ -62,7 +68,8 @@
|
||||
}
|
||||
<MudCardContent Class="image_card">
|
||||
<MudText Typo="Typo.subtitle1"><b>@item.p.Name</b></MudText>
|
||||
<MudIconButton Variant="Variant.Outlined" Icon="@Icons.Material.Rounded.Close"
|
||||
<MudIconButton Variant="Variant.Outlined"
|
||||
Icon="@Icons.Material.Rounded.Close"
|
||||
Size="Size.Small" Color="Color.Error"
|
||||
OnClick="@(() => OnRemoveAttached(item.index))"/>
|
||||
</MudCardContent>
|
||||
@@ -140,6 +147,8 @@
|
||||
private bool VisibleOverlay { get; set; }
|
||||
private bool SuccessAnimation { get; set; }
|
||||
|
||||
private bool FileLoading { get; set; }
|
||||
|
||||
private ConfirmUpdateActivity _confirmUpdateMessage = null!;
|
||||
private MudForm _form = null!;
|
||||
|
||||
@@ -152,6 +161,34 @@
|
||||
{
|
||||
_originalScheda = Scheda.Clone();
|
||||
Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter;
|
||||
|
||||
LoadAttached();
|
||||
}
|
||||
|
||||
private void LoadAttached()
|
||||
{
|
||||
FileLoading = true;
|
||||
StateHasChanged();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var fileList = await AttachedService.GetInspectionFiles(
|
||||
new Ispezione
|
||||
{
|
||||
CodMdep = CodMdep,
|
||||
Data = Data,
|
||||
Rilevatore = UserSession.User.Username
|
||||
}
|
||||
);
|
||||
|
||||
await InvokeAsync(() =>
|
||||
{
|
||||
AttachedList = fileList;
|
||||
FileLoading = false;
|
||||
|
||||
StateHasChanged();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
@@ -159,10 +196,10 @@
|
||||
VisibleOverlay = true;
|
||||
StateHasChanged();
|
||||
|
||||
if (IsNew)
|
||||
await IspezioniService.AddSchedaAsync(CodMdep, Data, UserSession.User.Username, Scheda);
|
||||
else
|
||||
await IspezioniService.UpdateSchedaAsync(Scheda);
|
||||
if (IsNew) await NewSave();
|
||||
else await Update();
|
||||
|
||||
await AttachedService.CleanTempStorageAsync();
|
||||
|
||||
SuccessAnimation = true;
|
||||
StateHasChanged();
|
||||
@@ -171,6 +208,65 @@
|
||||
MudDialog.Close(Scheda);
|
||||
}
|
||||
|
||||
private async Task NewSave()
|
||||
{
|
||||
if (!AttachedList.IsNullOrEmpty())
|
||||
{
|
||||
foreach (var attached in AttachedList!)
|
||||
{
|
||||
var fileNameAdded = await AttachedService.SaveInspectionFile(
|
||||
new Ispezione
|
||||
{
|
||||
CodMdep = CodMdep,
|
||||
Data = Data,
|
||||
Rilevatore = UserSession.User.Username
|
||||
},
|
||||
attached.FileBytes!,
|
||||
attached.Name!
|
||||
);
|
||||
|
||||
Scheda.ImageNames ??= [];
|
||||
if (fileNameAdded != null)
|
||||
Scheda.ImageNames.Add(fileNameAdded);
|
||||
}
|
||||
}
|
||||
|
||||
await IspezioniService.AddSchedaAsync(CodMdep, Data, UserSession.User.Username, Scheda);
|
||||
}
|
||||
|
||||
private async Task Update()
|
||||
{
|
||||
if (!AttachedList.IsNullOrEmpty())
|
||||
{
|
||||
foreach (var attached in AttachedList!.Where(x => !x.SavedOnAppData))
|
||||
{
|
||||
var ispezione = new Ispezione
|
||||
{
|
||||
CodMdep = CodMdep,
|
||||
Data = Data,
|
||||
Rilevatore = UserSession.User.Username
|
||||
};
|
||||
|
||||
if (!attached.ToRemove)
|
||||
{
|
||||
var fileNameAdded = await AttachedService.SaveInspectionFile(
|
||||
ispezione,
|
||||
attached.FileBytes!,
|
||||
attached.Name!
|
||||
);
|
||||
|
||||
Scheda.ImageNames ??= [];
|
||||
if (fileNameAdded != null)
|
||||
Scheda.ImageNames.Add(fileNameAdded);
|
||||
}
|
||||
else
|
||||
_ = AttachedService.RemoveInspectionFile(ispezione, attached.Name!);
|
||||
}
|
||||
}
|
||||
|
||||
await IspezioniService.UpdateSchedaAsync(Scheda);
|
||||
}
|
||||
|
||||
private async Task Cancel()
|
||||
{
|
||||
if (await CheckSavePreAction())
|
||||
@@ -188,9 +284,9 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void RecalcDirty()
|
||||
private void RecalcDirty(bool forceTrue = false)
|
||||
{
|
||||
IsDirty = !ValueComparer.AreEqual(Scheda, _originalScheda);
|
||||
IsDirty = forceTrue || !ValueComparer.AreEqual(Scheda, _originalScheda);
|
||||
|
||||
if (IsDirty) LabelSave = !IsNew ? "Aggiorna" : "Salva";
|
||||
else LabelSave = null;
|
||||
@@ -256,6 +352,8 @@
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
RecalcDirty(true);
|
||||
|
||||
// Processa in background e aggiorna UI man mano (o a blocchi)
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
@@ -285,10 +383,13 @@
|
||||
|
||||
private void OnRemoveAttached(int index)
|
||||
{
|
||||
if (AttachedList is null || index < 0 || index >= AttachedList.Count)
|
||||
return;
|
||||
if (AttachedList is null || index < 0 || index >= AttachedList.Count) return;
|
||||
|
||||
if (AttachedList[index].SavedOnAppData)
|
||||
AttachedList[index].ToRemove = true;
|
||||
|
||||
AttachedList.RemoveAt(index);
|
||||
RecalcDirty(true);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
@@ -318,5 +419,4 @@
|
||||
await InvokeAsync(StateHasChanged);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,6 +14,9 @@ public class AttachedDto
|
||||
public string? TempPath { get; set; }
|
||||
public string? ThumbPath { get; set; }
|
||||
|
||||
public bool SavedOnAppData { get; set; }
|
||||
public bool ToRemove { get; set; }
|
||||
|
||||
public Stream? FileContent =>
|
||||
FileBytes is null ? null : new MemoryStream(FileBytes);
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ public class Scheda : EntityBase<Scheda>
|
||||
public string Rilevatore { get; set; } = string.Empty;
|
||||
public Ispezione? Ispezione { get; set; }
|
||||
|
||||
public List<string>? ImageNames { get; set; }
|
||||
|
||||
public string? DescrizioneReparto { get; set; }
|
||||
public string? ActivityTypeId { get; set; }
|
||||
public string? Note { get; set; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using SteUp.Shared.Core.Dto;
|
||||
using SteUp.Shared.Core.Entities;
|
||||
|
||||
namespace SteUp.Shared.Core.Interface.System;
|
||||
|
||||
@@ -7,6 +8,10 @@ public interface IAttachedService
|
||||
Task<AttachedDto?> SelectImageFromCamera();
|
||||
Task<List<AttachedDto>?> SelectImageFromGallery();
|
||||
|
||||
Task<List<AttachedDto>?> GetInspectionFiles(Ispezione ispezione);
|
||||
Task<string?> SaveInspectionFile(Ispezione ispezione, byte[] file, string fileName, CancellationToken ct = default);
|
||||
bool RemoveInspectionFile(Ispezione ispezione, string fileName);
|
||||
|
||||
Task<string> SaveToTempStorage(Stream file, string fileName, CancellationToken ct = default);
|
||||
Task CleanTempStorageAsync(CancellationToken ct = default);
|
||||
Task OpenFile(string fileName, string filePath);
|
||||
|
||||
@@ -138,12 +138,16 @@
|
||||
|
||||
.container-button {
|
||||
width: 100%;
|
||||
/*background: var(--mud-palette-table-striped);*/
|
||||
background: var(--mud-palette-table-striped);
|
||||
padding: .5rem 0;
|
||||
border-radius: 20px;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.container-button.mud-elevation-1 {
|
||||
background: unset !important;
|
||||
}
|
||||
|
||||
.container-button .divider {
|
||||
margin: .5rem 0 .5rem 3rem;
|
||||
width: unset;
|
||||
|
||||
Reference in New Issue
Block a user