Compare commits
5 Commits
feat/timer
...
cdf225bad1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf225bad1 | ||
|
|
59e051f162 | ||
|
|
1352dda20e | ||
|
|
33b5b03bf4 | ||
|
|
6b986db62e |
@@ -1,28 +0,0 @@
|
|||||||
using DbFirst.Application.Time.Commands;
|
|
||||||
using DbFirst.Domain.Entities;
|
|
||||||
using MediatR;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace DbFirst.API.Controllers;
|
|
||||||
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/[controller]")]
|
|
||||||
public class TimeController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly IMediator _mediator;
|
|
||||||
|
|
||||||
public TimeController(IMediator mediator)
|
|
||||||
{
|
|
||||||
_mediator = mediator;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpPost]
|
|
||||||
public async Task<ActionResult<TimeRecord>> InsertAndGetLast(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var result = await _mediator.Send(new InsertTimeCommand(), cancellationToken);
|
|
||||||
if (result == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,7 +54,6 @@ builder.Services.AddApplication();
|
|||||||
builder.Services.AddScoped<ICatalogRepository, CatalogRepository>();
|
builder.Services.AddScoped<ICatalogRepository, CatalogRepository>();
|
||||||
builder.Services.AddScoped<IMassDataRepository, MassDataRepository>();
|
builder.Services.AddScoped<IMassDataRepository, MassDataRepository>();
|
||||||
builder.Services.AddScoped<ILayoutRepository, LayoutRepository>();
|
builder.Services.AddScoped<ILayoutRepository, LayoutRepository>();
|
||||||
builder.Services.AddScoped<ITimeRepository, TimeRepository>();
|
|
||||||
|
|
||||||
builder.Services.AddDevExpressControls();
|
builder.Services.AddDevExpressControls();
|
||||||
builder.Services.AddSignalR();
|
builder.Services.AddSignalR();
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
using DbFirst.Domain.Entities;
|
|
||||||
|
|
||||||
namespace DbFirst.Application.Repositories;
|
|
||||||
|
|
||||||
public interface ITimeRepository
|
|
||||||
{
|
|
||||||
Task InsertAsync(CancellationToken cancellationToken = default);
|
|
||||||
Task<TimeRecord?> GetLastAsync(CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
using DbFirst.Domain.Entities;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace DbFirst.Application.Time.Commands;
|
|
||||||
|
|
||||||
public record InsertTimeCommand : IRequest<TimeRecord?>;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using DbFirst.Application.Repositories;
|
|
||||||
using DbFirst.Domain.Entities;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace DbFirst.Application.Time.Commands;
|
|
||||||
|
|
||||||
public class InsertTimeHandler : IRequestHandler<InsertTimeCommand, TimeRecord?>
|
|
||||||
{
|
|
||||||
private readonly ITimeRepository _repository;
|
|
||||||
|
|
||||||
public InsertTimeHandler(ITimeRepository repository)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeRecord?> Handle(InsertTimeCommand request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
await _repository.InsertAsync(cancellationToken);
|
|
||||||
return await _repository.GetLastAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,12 +31,6 @@
|
|||||||
<span class="bi bi-table-nav-menu" aria-hidden="true"></span> MassData
|
<span class="bi bi-table-nav-menu" aria-hidden="true"></span> MassData
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-item px-3">
|
|
||||||
<NavLink class="nav-link" href="clock">
|
|
||||||
<span class="bi bi-clock-nav-menu" aria-hidden="true"></span> Clock
|
|
||||||
</NavLink>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
@rendermode InteractiveServer
|
|
||||||
@page "/clock"
|
|
||||||
@inject TimeApiClient TimeApi
|
|
||||||
@implements IAsyncDisposable
|
|
||||||
|
|
||||||
<PageTitle>Clock</PageTitle>
|
|
||||||
|
|
||||||
<h3>DB Server Clock</h3>
|
|
||||||
|
|
||||||
<div class="clock-wrapper">
|
|
||||||
<div class="clock-display @(_error != null ? "clock-error" : "")">
|
|
||||||
@if (_dbTime.HasValue)
|
|
||||||
{
|
|
||||||
<span class="clock-time">@_dbTime.Value.ToString("HH:mm:ss")</span>
|
|
||||||
<span class="clock-date">@_dbTime.Value.ToString("dd.MM.yyyy")</span>
|
|
||||||
}
|
|
||||||
else if (_error != null)
|
|
||||||
{
|
|
||||||
<span class="clock-time">--:--:--</span>
|
|
||||||
<span class="clock-date text-danger">@_error</span>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<span class="clock-time">...</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.clock-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 40vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clock-display {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
background: var(--bs-body-bg, #1e1e2e);
|
|
||||||
border: 2px solid var(--bs-border-color, #444);
|
|
||||||
border-radius: 1rem;
|
|
||||||
padding: 2rem 4rem;
|
|
||||||
box-shadow: 0 4px 24px rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.clock-time {
|
|
||||||
font-size: 5rem;
|
|
||||||
font-weight: 700;
|
|
||||||
font-variant-numeric: tabular-nums;
|
|
||||||
letter-spacing: 0.1em;
|
|
||||||
color: var(--bs-primary, #0d6efd);
|
|
||||||
}
|
|
||||||
|
|
||||||
.clock-date {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clock-error .clock-time {
|
|
||||||
color: var(--bs-danger, #dc3545);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private DateTime? _dbTime;
|
|
||||||
private string? _error;
|
|
||||||
private Timer? _timer;
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
|
||||||
{
|
|
||||||
await TickAsync();
|
|
||||||
_timer = new Timer(async _ =>
|
|
||||||
{
|
|
||||||
await TickAsync();
|
|
||||||
await InvokeAsync(StateHasChanged);
|
|
||||||
}, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task TickAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_dbTime = await TimeApi.InsertAndGetLastAsync();
|
|
||||||
_error = null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_error = ex.Message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
if (_timer != null)
|
|
||||||
await _timer.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -31,10 +31,6 @@ if (!string.IsNullOrWhiteSpace(apiBaseUrl))
|
|||||||
{
|
{
|
||||||
client.BaseAddress = new Uri(apiBaseUrl);
|
client.BaseAddress = new Uri(apiBaseUrl);
|
||||||
});
|
});
|
||||||
builder.Services.AddHttpClient<TimeApiClient>(client =>
|
|
||||||
{
|
|
||||||
client.BaseAddress = new Uri(apiBaseUrl);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -42,7 +38,6 @@ else
|
|||||||
builder.Services.AddHttpClient<DashboardApiClient>();
|
builder.Services.AddHttpClient<DashboardApiClient>();
|
||||||
builder.Services.AddHttpClient<MassDataApiClient>();
|
builder.Services.AddHttpClient<MassDataApiClient>();
|
||||||
builder.Services.AddHttpClient<LayoutApiClient>();
|
builder.Services.AddHttpClient<LayoutApiClient>();
|
||||||
builder.Services.AddHttpClient<TimeApiClient>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
using System.Net.Http.Json;
|
|
||||||
|
|
||||||
namespace DbFirst.BlazorWebApp.Services;
|
|
||||||
|
|
||||||
public class TimeApiClient
|
|
||||||
{
|
|
||||||
private readonly HttpClient _httpClient;
|
|
||||||
private const string Endpoint = "api/time";
|
|
||||||
|
|
||||||
public TimeApiClient(HttpClient httpClient)
|
|
||||||
{
|
|
||||||
_httpClient = httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<DateTime?> InsertAndGetLastAsync()
|
|
||||||
{
|
|
||||||
var response = await _httpClient.PostAsync(Endpoint, null);
|
|
||||||
response.EnsureSuccessStatusCode();
|
|
||||||
var result = await response.Content.ReadFromJsonAsync<TimeResponse>();
|
|
||||||
return result?.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class TimeResponse
|
|
||||||
{
|
|
||||||
public DateTime? Now { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace DbFirst.Domain.Entities;
|
|
||||||
|
|
||||||
public class TimeRecord
|
|
||||||
{
|
|
||||||
public DateTime? Now { get; set; }
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,6 @@ public partial class ApplicationDbContext : DbContext
|
|||||||
|
|
||||||
public virtual DbSet<VwmyCatalog> VwmyCatalogs { get; set; }
|
public virtual DbSet<VwmyCatalog> VwmyCatalogs { get; set; }
|
||||||
public virtual DbSet<SmfLayout> SmfLayouts { get; set; }
|
public virtual DbSet<SmfLayout> SmfLayouts { get; set; }
|
||||||
public virtual DbSet<TimeRecord> Times { get; set; }
|
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@@ -84,16 +83,6 @@ public partial class ApplicationDbContext : DbContext
|
|||||||
.HasColumnName("CHANGED_WHEN");
|
.HasColumnName("CHANGED_WHEN");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity<TimeRecord>(entity =>
|
|
||||||
{
|
|
||||||
entity.HasNoKey();
|
|
||||||
entity.ToTable("TIME");
|
|
||||||
|
|
||||||
entity.Property(e => e.Now)
|
|
||||||
.HasColumnType("datetime")
|
|
||||||
.HasColumnName("NOW");
|
|
||||||
});
|
|
||||||
|
|
||||||
OnModelCreatingPartial(modelBuilder);
|
OnModelCreatingPartial(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
using DbFirst.Application.Repositories;
|
|
||||||
using DbFirst.Domain.Entities;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace DbFirst.Infrastructure.Repositories;
|
|
||||||
|
|
||||||
public class TimeRepository : ITimeRepository
|
|
||||||
{
|
|
||||||
private readonly ApplicationDbContext _db;
|
|
||||||
|
|
||||||
public TimeRepository(ApplicationDbContext db)
|
|
||||||
{
|
|
||||||
_db = db;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task InsertAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
await _db.Database.ExecuteSqlRawAsync("INSERT INTO [TIME] (NOW) VALUES (GETDATE())", cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<TimeRecord?> GetLastAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await _db.Times
|
|
||||||
.AsNoTracking()
|
|
||||||
.OrderByDescending(t => t.Now)
|
|
||||||
.FirstOrDefaultAsync(cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1157
docs/PROJEKTDOKUMENTATION.md
Normal file
1157
docs/PROJEKTDOKUMENTATION.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user