Add MassData feature with API, paging, and Blazor grid
Introduces MassData management to backend and Blazor frontend: - Adds API endpoint for MassData count and paging - Updates repository and controller for count support - Implements MediatR query/handler for count - Adds Blazor page and grid for viewing/editing MassData - Registers MassDataApiClient and integrates with DI - Supports paging, upsert, and UI feedback in grid
This commit is contained in:
@@ -17,6 +17,13 @@ public class MassDataController : ControllerBase
|
||||
_mediator = mediator;
|
||||
}
|
||||
|
||||
[HttpGet("count")]
|
||||
public async Task<ActionResult<int>> GetCount(CancellationToken cancellationToken)
|
||||
{
|
||||
var count = await _mediator.Send(new GetMassDataCountQuery(), cancellationToken);
|
||||
return Ok(count);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<MassDataReadDto>>> GetAll([FromQuery] int? skip, [FromQuery] int? take, CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using DbFirst.Application.Repositories;
|
||||
using MediatR;
|
||||
|
||||
namespace DbFirst.Application.MassData.Queries;
|
||||
|
||||
public class GetMassDataCountHandler : IRequestHandler<GetMassDataCountQuery, int>
|
||||
{
|
||||
private readonly IMassDataRepository _repository;
|
||||
|
||||
public GetMassDataCountHandler(IMassDataRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public async Task<int> Handle(GetMassDataCountQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _repository.GetCountAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using MediatR;
|
||||
|
||||
namespace DbFirst.Application.MassData.Queries;
|
||||
|
||||
public record GetMassDataCountQuery : IRequest<int>;
|
||||
@@ -4,6 +4,7 @@ namespace DbFirst.Application.Repositories;
|
||||
|
||||
public interface IMassDataRepository
|
||||
{
|
||||
Task<int> GetCountAsync(CancellationToken cancellationToken = default);
|
||||
Task<List<Massdata>> GetAllAsync(int? skip = null, int? take = null, CancellationToken cancellationToken = default);
|
||||
Task<Massdata?> GetByCustomerNameAsync(string customerName, CancellationToken cancellationToken = default);
|
||||
Task<Massdata> UpsertByCustomerNameAsync(string customerName, decimal amount, bool statusFlag, string category, CancellationToken cancellationToken = default);
|
||||
|
||||
196
DbFirst.BlazorWasm/Components/MassDataGrid.razor
Normal file
196
DbFirst.BlazorWasm/Components/MassDataGrid.razor
Normal file
@@ -0,0 +1,196 @@
|
||||
@inject MassDataApiClient Api
|
||||
|
||||
<style>
|
||||
.action-panel { margin-bottom: 16px; }
|
||||
.grid-section { margin-top: 12px; }
|
||||
.pager-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(errorMessage))
|
||||
{
|
||||
<div class="alert alert-danger" role="alert">@errorMessage</div>
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(infoMessage))
|
||||
{
|
||||
<div class="alert alert-success" role="alert">@infoMessage</div>
|
||||
}
|
||||
|
||||
<div class="mb-3">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="@StartCreate">Neuen Eintrag anlegen</DxButton>
|
||||
</div>
|
||||
|
||||
@if (showForm)
|
||||
{
|
||||
<div class="action-panel">
|
||||
<EditForm Model="formModel" OnValidSubmit="HandleSubmit" Context="editCtx">
|
||||
<DxFormLayout ColCount="2">
|
||||
<DxFormLayoutItem Caption="CustomerName" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="formModel.CustomerName" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Amount" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="amountText" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Category" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="formModel.Category" ReadOnly="true" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Status" Context="itemCtx">
|
||||
<DxCheckBox @bind-Checked="formModel.StatusFlag" ReadOnly="true" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption=" " Context="itemCtx">
|
||||
<DxStack Orientation="Orientation.Horizontal" Spacing="8">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Success" ButtonType="ButtonType.Submit" SubmitFormOnClick="true" Context="btnCtx">Speichern</DxButton>
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Click="@CancelEdit" Context="btnCtx">Abbrechen</DxButton>
|
||||
</DxStack>
|
||||
</DxFormLayoutItem>
|
||||
</DxFormLayout>
|
||||
</EditForm>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p><em>Lade Daten...</em></p>
|
||||
}
|
||||
else if (items.Count == 0)
|
||||
{
|
||||
<p>Keine Einträge vorhanden.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="grid-section">
|
||||
<DxGrid Data="@items" TItem="MassDataReadDto" KeyFieldName="@nameof(MassDataReadDto.Id)" ShowFilterRow="true" ShowGroupPanel="true" AllowColumnResize="true" PagerVisible="false" PageSize="100" CssClass="mb-3 massdata-grid">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed" />
|
||||
<DxGridDataColumn Caption="" Width="220px" AllowSort="false">
|
||||
<CellDisplayTemplate Context="cell">
|
||||
@{ var item = (MassDataReadDto)cell.DataItem; }
|
||||
<div style="white-space: nowrap;">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Size="ButtonSize.Small" Click="@(() => StartEdit(item))">Bearbeiten</DxButton>
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Danger" Size="ButtonSize.Small" Click="@ShowDeleteNotReady">Löschen</DxButton>
|
||||
</div>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
</Columns>
|
||||
</DxGrid>
|
||||
|
||||
<div class="pager-container">
|
||||
<DxPager PageCount="@pageCount" ActivePageIndex="@pageIndex" ActivePageIndexChanged="OnPageChanged" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private const int PageSize = 100;
|
||||
private List<MassDataReadDto> items = new();
|
||||
private MassDataWriteDto formModel = new();
|
||||
private string amountText = string.Empty;
|
||||
private bool isLoading;
|
||||
private bool showForm;
|
||||
private string? errorMessage;
|
||||
private string? infoMessage;
|
||||
private int pageIndex;
|
||||
private int pageCount = 1;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadPage(0);
|
||||
}
|
||||
|
||||
private async Task LoadPage(int page)
|
||||
{
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
try
|
||||
{
|
||||
var total = await Api.GetCountAsync();
|
||||
pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)PageSize));
|
||||
pageIndex = Math.Clamp(page, 0, pageCount - 1);
|
||||
|
||||
var skip = pageIndex * PageSize;
|
||||
items = await Api.GetAllAsync(skip, PageSize);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"MassData konnten nicht geladen werden: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int index)
|
||||
{
|
||||
await LoadPage(index);
|
||||
}
|
||||
|
||||
private void StartCreate()
|
||||
{
|
||||
infoMessage = "Anlegen ist aktuell noch nicht verfügbar.";
|
||||
}
|
||||
|
||||
private void StartEdit(MassDataReadDto item)
|
||||
{
|
||||
formModel = new MassDataWriteDto
|
||||
{
|
||||
CustomerName = item.CustomerName,
|
||||
Amount = item.Amount,
|
||||
Category = item.Category,
|
||||
StatusFlag = item.StatusFlag
|
||||
};
|
||||
amountText = item.Amount.ToString("0.00");
|
||||
showForm = true;
|
||||
infoMessage = null;
|
||||
errorMessage = null;
|
||||
}
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
errorMessage = null;
|
||||
infoMessage = null;
|
||||
|
||||
if (!decimal.TryParse(amountText, out var amount))
|
||||
{
|
||||
errorMessage = "Amount ist ungültig.";
|
||||
return;
|
||||
}
|
||||
|
||||
formModel.Amount = amount;
|
||||
|
||||
try
|
||||
{
|
||||
await Api.UpsertAsync(formModel);
|
||||
infoMessage = "MassData aktualisiert.";
|
||||
showForm = false;
|
||||
await LoadPage(pageIndex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"Fehler beim Speichern: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelEdit()
|
||||
{
|
||||
showForm = false;
|
||||
infoMessage = null;
|
||||
errorMessage = null;
|
||||
}
|
||||
|
||||
private void ShowDeleteNotReady()
|
||||
{
|
||||
infoMessage = "Löschen ist aktuell noch nicht verfügbar.";
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,11 @@
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
||||
</NavLink>
|
||||
</div>
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="massdata">
|
||||
<span class="bi bi-table" aria-hidden="true"></span> MassData
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
12
DbFirst.BlazorWasm/Models/MassDataReadDto.cs
Normal file
12
DbFirst.BlazorWasm/Models/MassDataReadDto.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace DbFirst.BlazorWasm.Models;
|
||||
|
||||
public class MassDataReadDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public string Category { get; set; } = string.Empty;
|
||||
public bool StatusFlag { get; set; }
|
||||
public DateTime AddedWhen { get; set; }
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
9
DbFirst.BlazorWasm/Models/MassDataWriteDto.cs
Normal file
9
DbFirst.BlazorWasm/Models/MassDataWriteDto.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace DbFirst.BlazorWasm.Models;
|
||||
|
||||
public class MassDataWriteDto
|
||||
{
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public string Category { get; set; } = string.Empty;
|
||||
public bool StatusFlag { get; set; }
|
||||
}
|
||||
7
DbFirst.BlazorWasm/Pages/Massdata.razor
Normal file
7
DbFirst.BlazorWasm/Pages/Massdata.razor
Normal file
@@ -0,0 +1,7 @@
|
||||
@page "/massdata"
|
||||
|
||||
<PageTitle>MassData</PageTitle>
|
||||
|
||||
<h1>MassData</h1>
|
||||
|
||||
<MassDataGrid />
|
||||
@@ -18,5 +18,6 @@ var apiBaseUrl = builder.Configuration["ApiBaseUrl"] ?? builder.HostEnvironment.
|
||||
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(apiBaseUrl) });
|
||||
builder.Services.AddScoped<CatalogApiClient>();
|
||||
builder.Services.AddScoped<DashboardApiClient>();
|
||||
builder.Services.AddScoped<MassDataApiClient>();
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
|
||||
35
DbFirst.BlazorWasm/Services/MassDataApiClient.cs
Normal file
35
DbFirst.BlazorWasm/Services/MassDataApiClient.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Net.Http.Json;
|
||||
using DbFirst.BlazorWasm.Models;
|
||||
|
||||
namespace DbFirst.BlazorWasm.Services;
|
||||
|
||||
public class MassDataApiClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Endpoint = "api/massdata";
|
||||
|
||||
public MassDataApiClient(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<int> GetCountAsync()
|
||||
{
|
||||
var result = await _httpClient.GetFromJsonAsync<int?>("api/massdata/count");
|
||||
return result ?? 0;
|
||||
}
|
||||
|
||||
public async Task<List<MassDataReadDto>> GetAllAsync(int skip, int take)
|
||||
{
|
||||
var result = await _httpClient.GetFromJsonAsync<List<MassDataReadDto>>($"{Endpoint}?skip={skip}&take={take}");
|
||||
return result ?? new List<MassDataReadDto>();
|
||||
}
|
||||
|
||||
public async Task<MassDataReadDto> UpsertAsync(MassDataWriteDto dto)
|
||||
{
|
||||
var response = await _httpClient.PostAsJsonAsync($"{Endpoint}/upsert", dto);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var payload = await response.Content.ReadFromJsonAsync<MassDataReadDto>();
|
||||
return payload ?? new MassDataReadDto();
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,12 @@
|
||||
<span class="oi oi-list-rich" aria-hidden="true"></span> Dashboards
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
<div class="nav-item px-3">
|
||||
<NavLink class="nav-link" href="massdata">
|
||||
<span class="bi bi-table" aria-hidden="true"></span> MassData
|
||||
</NavLink>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
196
DbFirst.BlazorWebApp/Components/MassDataGrid.razor
Normal file
196
DbFirst.BlazorWebApp/Components/MassDataGrid.razor
Normal file
@@ -0,0 +1,196 @@
|
||||
@inject MassDataApiClient Api
|
||||
|
||||
<style>
|
||||
.action-panel { margin-bottom: 16px; }
|
||||
.grid-section { margin-top: 12px; }
|
||||
.pager-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@if (!string.IsNullOrWhiteSpace(errorMessage))
|
||||
{
|
||||
<div class="alert alert-danger" role="alert">@errorMessage</div>
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(infoMessage))
|
||||
{
|
||||
<div class="alert alert-success" role="alert">@infoMessage</div>
|
||||
}
|
||||
|
||||
<div class="mb-3">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="@StartCreate">Neuen Eintrag anlegen</DxButton>
|
||||
</div>
|
||||
|
||||
@if (showForm)
|
||||
{
|
||||
<div class="action-panel">
|
||||
<EditForm Model="formModel" OnValidSubmit="HandleSubmit" Context="editCtx">
|
||||
<DxFormLayout ColCount="2">
|
||||
<DxFormLayoutItem Caption="CustomerName" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="formModel.CustomerName" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Amount" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="amountText" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Category" Context="itemCtx">
|
||||
<DxTextBox @bind-Text="formModel.Category" ReadOnly="true" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption="Status" Context="itemCtx">
|
||||
<DxCheckBox @bind-Checked="formModel.StatusFlag" ReadOnly="true" />
|
||||
</DxFormLayoutItem>
|
||||
<DxFormLayoutItem Caption=" " Context="itemCtx">
|
||||
<DxStack Orientation="Orientation.Horizontal" Spacing="8">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Success" ButtonType="ButtonType.Submit" SubmitFormOnClick="true" Context="btnCtx">Speichern</DxButton>
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Click="@CancelEdit" Context="btnCtx">Abbrechen</DxButton>
|
||||
</DxStack>
|
||||
</DxFormLayoutItem>
|
||||
</DxFormLayout>
|
||||
</EditForm>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (isLoading)
|
||||
{
|
||||
<p><em>Lade Daten...</em></p>
|
||||
}
|
||||
else if (items.Count == 0)
|
||||
{
|
||||
<p>Keine Einträge vorhanden.</p>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="grid-section">
|
||||
<DxGrid Data="@items" TItem="MassDataReadDto" KeyFieldName="@nameof(MassDataReadDto.Id)" ShowFilterRow="true" ShowGroupPanel="true" AllowColumnResize="true" PagerVisible="false" PageSize="100" CssClass="mb-3 massdata-grid">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Id)" Caption="Id" Width="90px" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.CustomerName)" Caption="CustomerName" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Amount)" Caption="Amount" DisplayFormat="c2" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.Category)" Caption="Category" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.StatusFlag)" Caption="Status" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.AddedWhen)" Caption="Added" />
|
||||
<DxGridDataColumn FieldName="@nameof(MassDataReadDto.ChangedWhen)" Caption="Changed" />
|
||||
<DxGridDataColumn Caption="" Width="220px" AllowSort="false">
|
||||
<CellDisplayTemplate Context="cell">
|
||||
@{ var item = (MassDataReadDto)cell.DataItem; }
|
||||
<div style="white-space: nowrap;">
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Size="ButtonSize.Small" Click="@(() => StartEdit(item))">Bearbeiten</DxButton>
|
||||
<DxButton RenderStyle="ButtonRenderStyle.Danger" Size="ButtonSize.Small" Click="@ShowDeleteNotReady">Löschen</DxButton>
|
||||
</div>
|
||||
</CellDisplayTemplate>
|
||||
</DxGridDataColumn>
|
||||
</Columns>
|
||||
</DxGrid>
|
||||
|
||||
<div class="pager-container">
|
||||
<DxPager PageCount="@pageCount" ActivePageIndex="@pageIndex" ActivePageIndexChanged="OnPageChanged" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private const int PageSize = 100;
|
||||
private List<MassDataReadDto> items = new();
|
||||
private MassDataWriteDto formModel = new();
|
||||
private string amountText = string.Empty;
|
||||
private bool isLoading;
|
||||
private bool showForm;
|
||||
private string? errorMessage;
|
||||
private string? infoMessage;
|
||||
private int pageIndex;
|
||||
private int pageCount = 1;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadPage(0);
|
||||
}
|
||||
|
||||
private async Task LoadPage(int page)
|
||||
{
|
||||
isLoading = true;
|
||||
errorMessage = null;
|
||||
try
|
||||
{
|
||||
var total = await Api.GetCountAsync();
|
||||
pageCount = Math.Max(1, (int)Math.Ceiling(total / (double)PageSize));
|
||||
pageIndex = Math.Clamp(page, 0, pageCount - 1);
|
||||
|
||||
var skip = pageIndex * PageSize;
|
||||
items = await Api.GetAllAsync(skip, PageSize);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"MassData konnten nicht geladen werden: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
isLoading = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnPageChanged(int index)
|
||||
{
|
||||
await LoadPage(index);
|
||||
}
|
||||
|
||||
private void StartCreate()
|
||||
{
|
||||
infoMessage = "Anlegen ist aktuell noch nicht verfügbar.";
|
||||
}
|
||||
|
||||
private void StartEdit(MassDataReadDto item)
|
||||
{
|
||||
formModel = new MassDataWriteDto
|
||||
{
|
||||
CustomerName = item.CustomerName,
|
||||
Amount = item.Amount,
|
||||
Category = item.Category,
|
||||
StatusFlag = item.StatusFlag
|
||||
};
|
||||
amountText = item.Amount.ToString("0.00");
|
||||
showForm = true;
|
||||
infoMessage = null;
|
||||
errorMessage = null;
|
||||
}
|
||||
|
||||
private async Task HandleSubmit()
|
||||
{
|
||||
errorMessage = null;
|
||||
infoMessage = null;
|
||||
|
||||
if (!decimal.TryParse(amountText, out var amount))
|
||||
{
|
||||
errorMessage = "Amount ist ungültig.";
|
||||
return;
|
||||
}
|
||||
|
||||
formModel.Amount = amount;
|
||||
|
||||
try
|
||||
{
|
||||
await Api.UpsertAsync(formModel);
|
||||
infoMessage = "MassData aktualisiert.";
|
||||
showForm = false;
|
||||
await LoadPage(pageIndex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorMessage = $"Fehler beim Speichern: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelEdit()
|
||||
{
|
||||
showForm = false;
|
||||
infoMessage = null;
|
||||
errorMessage = null;
|
||||
}
|
||||
|
||||
private void ShowDeleteNotReady()
|
||||
{
|
||||
infoMessage = "Löschen ist aktuell noch nicht verfügbar.";
|
||||
}
|
||||
}
|
||||
7
DbFirst.BlazorWebApp/Components/Pages/Massdata.razor
Normal file
7
DbFirst.BlazorWebApp/Components/Pages/Massdata.razor
Normal file
@@ -0,0 +1,7 @@
|
||||
@page "/massdata"
|
||||
|
||||
<PageTitle>MassData</PageTitle>
|
||||
|
||||
<h1>MassData</h1>
|
||||
|
||||
<MassDataGrid />
|
||||
12
DbFirst.BlazorWebApp/Models/MassDataReadDto.cs
Normal file
12
DbFirst.BlazorWebApp/Models/MassDataReadDto.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace DbFirst.BlazorWebApp.Models;
|
||||
|
||||
public class MassDataReadDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public string Category { get; set; } = string.Empty;
|
||||
public bool StatusFlag { get; set; }
|
||||
public DateTime AddedWhen { get; set; }
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
}
|
||||
9
DbFirst.BlazorWebApp/Models/MassDataWriteDto.cs
Normal file
9
DbFirst.BlazorWebApp/Models/MassDataWriteDto.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace DbFirst.BlazorWebApp.Models;
|
||||
|
||||
public class MassDataWriteDto
|
||||
{
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public decimal Amount { get; set; }
|
||||
public string Category { get; set; } = string.Empty;
|
||||
public bool StatusFlag { get; set; }
|
||||
}
|
||||
@@ -21,11 +21,16 @@ if (!string.IsNullOrWhiteSpace(apiBaseUrl))
|
||||
{
|
||||
client.BaseAddress = new Uri(apiBaseUrl);
|
||||
});
|
||||
builder.Services.AddHttpClient<MassDataApiClient>(client =>
|
||||
{
|
||||
client.BaseAddress = new Uri(apiBaseUrl);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddHttpClient<CatalogApiClient>();
|
||||
builder.Services.AddHttpClient<DashboardApiClient>();
|
||||
builder.Services.AddHttpClient<MassDataApiClient>();
|
||||
}
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
35
DbFirst.BlazorWebApp/Services/MassDataApiClient.cs
Normal file
35
DbFirst.BlazorWebApp/Services/MassDataApiClient.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Net.Http.Json;
|
||||
using DbFirst.BlazorWebApp.Models;
|
||||
|
||||
namespace DbFirst.BlazorWebApp.Services;
|
||||
|
||||
public class MassDataApiClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Endpoint = "api/massdata";
|
||||
|
||||
public MassDataApiClient(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<int> GetCountAsync()
|
||||
{
|
||||
var result = await _httpClient.GetFromJsonAsync<int?>("api/massdata/count");
|
||||
return result ?? 0;
|
||||
}
|
||||
|
||||
public async Task<List<MassDataReadDto>> GetAllAsync(int skip, int take)
|
||||
{
|
||||
var result = await _httpClient.GetFromJsonAsync<List<MassDataReadDto>>($"{Endpoint}?skip={skip}&take={take}");
|
||||
return result ?? new List<MassDataReadDto>();
|
||||
}
|
||||
|
||||
public async Task<MassDataReadDto> UpsertAsync(MassDataWriteDto dto)
|
||||
{
|
||||
var response = await _httpClient.PostAsJsonAsync($"{Endpoint}/upsert", dto);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var payload = await response.Content.ReadFromJsonAsync<MassDataReadDto>();
|
||||
return payload ?? new MassDataReadDto();
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@ public class MassDataRepository : IMassDataRepository
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<int> GetCountAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _db.Massdata.AsNoTracking().CountAsync(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<List<Massdata>> GetAllAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _db.Massdata.AsNoTracking().ToListAsync(cancellationToken);
|
||||
|
||||
Reference in New Issue
Block a user