Separate admin access from finance lock
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
<title>Trafag Finanze/Sales Management Cockpit</title>
|
<title>Trafag Finanze/Sales Management Cockpit</title>
|
||||||
<base href="@BaseHref" />
|
<base href="@BaseHref" />
|
||||||
<link href="css/app.css" rel="stylesheet" />
|
<link href="css/app.css" rel="stylesheet" />
|
||||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800&display=swap" rel="stylesheet" />
|
||||||
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
<link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
|
||||||
<HeadOutlet @rendermode="@Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer" />
|
<HeadOutlet @rendermode="@Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer" />
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
@using TrafagSalesExporter.Services
|
@using TrafagSalesExporter.Services
|
||||||
@inject IAccessSessionTracker SessionTracker
|
@inject IAccessSessionTracker SessionTracker
|
||||||
@inject IAdminAccessService AdminAccess
|
@inject IAdminAccessService AdminAccess
|
||||||
|
@inject ILandingPageSettingsService LandingSettings
|
||||||
@inject IUiTextService UiText
|
@inject IUiTextService UiText
|
||||||
|
|
||||||
<PageTitle>@T("Aktive Logins", "Active logins")</PageTitle>
|
<PageTitle>@T("Aktive Logins", "Active logins")</PageTitle>
|
||||||
@@ -16,6 +17,19 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudPaper Class="pa-4 mb-4" Elevation="1">
|
<MudPaper Class="pa-4 mb-4" Elevation="1">
|
||||||
|
<MudStack Row AlignItems="AlignItems.Center" Class="mb-4">
|
||||||
|
<div>
|
||||||
|
<MudText Typo="Typo.h6">@T("Startseite", "Landing page")</MudText>
|
||||||
|
<MudText Typo="Typo.caption">
|
||||||
|
@T("Optionale Animation unter dem Willkommens-Text.", "Optional animation below the welcome text.")
|
||||||
|
</MudText>
|
||||||
|
</div>
|
||||||
|
<MudSpacer />
|
||||||
|
<MudSwitch T="bool" Value="LandingSettings.ShowWalkingLabFigure" ValueChanged="SetWalkingFigure"
|
||||||
|
Color="Color.Primary"
|
||||||
|
Label="@T("Strichmännchen anzeigen", "Show stick figure")" />
|
||||||
|
</MudStack>
|
||||||
|
<MudDivider Class="mb-4" />
|
||||||
<MudStack Row AlignItems="AlignItems.Center" Class="mb-3">
|
<MudStack Row AlignItems="AlignItems.Center" Class="mb-3">
|
||||||
<div>
|
<div>
|
||||||
<MudText Typo="Typo.h6">@T("HR-/Finance-Cockpit Sessions", "HR/Finance cockpit sessions")</MudText>
|
<MudText Typo="Typo.h6">@T("HR-/Finance-Cockpit Sessions", "HR/Finance cockpit sessions")</MudText>
|
||||||
@@ -77,6 +91,11 @@ else
|
|||||||
_sessions = [];
|
_sessions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetWalkingFigure(bool value)
|
||||||
|
{
|
||||||
|
LandingSettings.SetShowWalkingLabFigure(value);
|
||||||
|
}
|
||||||
|
|
||||||
private static string FormatDate(DateTimeOffset value)
|
private static string FormatDate(DateTimeOffset value)
|
||||||
=> value.ToString("dd.MM.yyyy HH:mm:ss");
|
=> value.ToString("dd.MM.yyyy HH:mm:ss");
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@using TrafagSalesExporter.Services
|
@using TrafagSalesExporter.Services
|
||||||
@inject IUiTextService UiText
|
@inject IUiTextService UiText
|
||||||
|
@inject ILandingPageSettingsService LandingSettings
|
||||||
|
|
||||||
<PageTitle>@T("Trafag Cockpit", "Trafag Cockpit")</PageTitle>
|
<PageTitle>@T("Trafag Cockpit", "Trafag Cockpit")</PageTitle>
|
||||||
|
|
||||||
@@ -30,6 +31,21 @@
|
|||||||
<circle cx="300" cy="260" r="28" fill="#050505" />
|
<circle cx="300" cy="260" r="28" fill="#050505" />
|
||||||
</svg>
|
</svg>
|
||||||
<div class="home-welcome">@T("Willkommen im Trafag Analyse Dashboard", "Welcome to the Trafag Analytical Dashboard")</div>
|
<div class="home-welcome">@T("Willkommen im Trafag Analyse Dashboard", "Welcome to the Trafag Analytical Dashboard")</div>
|
||||||
|
@if (LandingSettings.ShowWalkingLabFigure)
|
||||||
|
{
|
||||||
|
<div class="walking-stage" aria-label="Walking lab figure">
|
||||||
|
<div class="walking-person">
|
||||||
|
<span class="head"></span>
|
||||||
|
<span class="body"></span>
|
||||||
|
<span class="coat coat-left"></span>
|
||||||
|
<span class="coat coat-right"></span>
|
||||||
|
<span class="arm arm-left"></span>
|
||||||
|
<span class="arm arm-right"></span>
|
||||||
|
<span class="leg leg-left"></span>
|
||||||
|
<span class="leg leg-right"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -63,6 +79,114 @@
|
|||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.walking-stage {
|
||||||
|
width: min(360px, 70vw);
|
||||||
|
height: 96px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
border-bottom: 2px solid #050505;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 4px;
|
||||||
|
width: 48px;
|
||||||
|
height: 82px;
|
||||||
|
animation: lab-walk-path 7s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person span {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
background: #050505;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .head {
|
||||||
|
left: 15px;
|
||||||
|
top: 0;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border: 3px solid #050505;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .body {
|
||||||
|
left: 22px;
|
||||||
|
top: 22px;
|
||||||
|
width: 4px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .coat {
|
||||||
|
top: 25px;
|
||||||
|
width: 17px;
|
||||||
|
height: 36px;
|
||||||
|
border: 3px solid #050505;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .coat-left {
|
||||||
|
left: 8px;
|
||||||
|
transform: skewY(10deg);
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .coat-right {
|
||||||
|
left: 23px;
|
||||||
|
transform: skewY(-10deg);
|
||||||
|
border-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .arm,
|
||||||
|
.walking-person .leg {
|
||||||
|
width: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transform-origin: 50% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .arm {
|
||||||
|
top: 28px;
|
||||||
|
height: 28px;
|
||||||
|
animation: limb-swing 0.72s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .arm-left {
|
||||||
|
left: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .arm-right {
|
||||||
|
left: 31px;
|
||||||
|
animation-direction: alternate-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .leg {
|
||||||
|
top: 56px;
|
||||||
|
height: 28px;
|
||||||
|
animation: limb-swing 0.72s ease-in-out infinite alternate-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .leg-left {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.walking-person .leg-right {
|
||||||
|
left: 27px;
|
||||||
|
animation-direction: alternate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@keyframes lab-walk-path {
|
||||||
|
0% { transform: translateX(-54px); }
|
||||||
|
100% { transform: translateX(calc(min(360px, 70vw) + 54px)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@@keyframes limb-swing {
|
||||||
|
0% { transform: rotate(-24deg); }
|
||||||
|
100% { transform: rotate(24deg); }
|
||||||
|
}
|
||||||
|
|
||||||
.gauge-outer,
|
.gauge-outer,
|
||||||
.gauge-inner,
|
.gauge-inner,
|
||||||
.gauge-tick,
|
.gauge-tick,
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
"transformations" or
|
"transformations" or
|
||||||
"finance-rules" or
|
"finance-rules" or
|
||||||
"settings" or
|
"settings" or
|
||||||
"admin/sessions" or
|
|
||||||
"logs" or
|
"logs" or
|
||||||
"source-viewer";
|
"source-viewer";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ builder.Services.Configure<HrKpiDataSourceOptions>(builder.Configuration.GetSect
|
|||||||
builder.Services.Configure<HrKpiAccessOptions>(builder.Configuration.GetSection(HrKpiAccessOptions.SectionName));
|
builder.Services.Configure<HrKpiAccessOptions>(builder.Configuration.GetSection(HrKpiAccessOptions.SectionName));
|
||||||
builder.Services.Configure<FinanceCockpitAccessOptions>(builder.Configuration.GetSection(FinanceCockpitAccessOptions.SectionName));
|
builder.Services.Configure<FinanceCockpitAccessOptions>(builder.Configuration.GetSection(FinanceCockpitAccessOptions.SectionName));
|
||||||
builder.Services.Configure<AdminAccessOptions>(builder.Configuration.GetSection(AdminAccessOptions.SectionName));
|
builder.Services.Configure<AdminAccessOptions>(builder.Configuration.GetSection(AdminAccessOptions.SectionName));
|
||||||
|
builder.Services.Configure<LandingPageOptions>(builder.Configuration.GetSection(LandingPageOptions.SectionName));
|
||||||
|
|
||||||
builder.Services.AddDbContextFactory<AppDbContext>(options =>
|
builder.Services.AddDbContextFactory<AppDbContext>(options =>
|
||||||
options.UseSqlite("Data Source=trafag_exporter.db;Default Timeout=60"));
|
options.UseSqlite("Data Source=trafag_exporter.db;Default Timeout=60"));
|
||||||
@@ -88,6 +89,7 @@ builder.Services.AddSingleton<IDatabaseSeedService, DatabaseSeedService>();
|
|||||||
builder.Services.AddSingleton<IDatabaseInitializationService, DatabaseInitializationService>();
|
builder.Services.AddSingleton<IDatabaseInitializationService, DatabaseInitializationService>();
|
||||||
builder.Services.AddSingleton<IUiTextService, UiTextService>();
|
builder.Services.AddSingleton<IUiTextService, UiTextService>();
|
||||||
builder.Services.AddSingleton<IAccessSessionTracker, AccessSessionTracker>();
|
builder.Services.AddSingleton<IAccessSessionTracker, AccessSessionTracker>();
|
||||||
|
builder.Services.AddSingleton<ILandingPageSettingsService, LandingPageSettingsService>();
|
||||||
|
|
||||||
// Datenquellen-Adapter (Strategy per ConnectionKind).
|
// Datenquellen-Adapter (Strategy per ConnectionKind).
|
||||||
builder.Services.AddSingleton<IDataSourceAdapter, HanaDataSourceAdapter>();
|
builder.Services.AddSingleton<IDataSourceAdapter, HanaDataSourceAdapter>();
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace TrafagSalesExporter.Security;
|
||||||
|
|
||||||
|
public sealed class LandingPageOptions
|
||||||
|
{
|
||||||
|
public const string SectionName = "LandingPage";
|
||||||
|
|
||||||
|
public bool ShowWalkingLabFigure { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using TrafagSalesExporter.Security;
|
||||||
|
|
||||||
|
namespace TrafagSalesExporter.Services;
|
||||||
|
|
||||||
|
public interface ILandingPageSettingsService
|
||||||
|
{
|
||||||
|
bool ShowWalkingLabFigure { get; }
|
||||||
|
void SetShowWalkingLabFigure(bool value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class LandingPageSettingsService : ILandingPageSettingsService
|
||||||
|
{
|
||||||
|
private static readonly object FileLock = new();
|
||||||
|
private readonly LandingPageOptions _options;
|
||||||
|
private readonly IHostEnvironment _environment;
|
||||||
|
|
||||||
|
public LandingPageSettingsService(IOptions<LandingPageOptions> options, IHostEnvironment environment)
|
||||||
|
{
|
||||||
|
_options = options.Value;
|
||||||
|
_environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowWalkingLabFigure => _options.ShowWalkingLabFigure;
|
||||||
|
|
||||||
|
public void SetShowWalkingLabFigure(bool value)
|
||||||
|
{
|
||||||
|
_options.ShowWalkingLabFigure = value;
|
||||||
|
SaveSetting(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveSetting(bool value)
|
||||||
|
{
|
||||||
|
var path = Path.Combine(_environment.ContentRootPath, "appsettings.json");
|
||||||
|
|
||||||
|
lock (FileLock)
|
||||||
|
{
|
||||||
|
var json = File.Exists(path)
|
||||||
|
? File.ReadAllText(path, Encoding.UTF8)
|
||||||
|
: "{}";
|
||||||
|
|
||||||
|
var root = JsonNode.Parse(json)?.AsObject() ?? new JsonObject();
|
||||||
|
var section = root[LandingPageOptions.SectionName] as JsonObject;
|
||||||
|
if (section is null)
|
||||||
|
{
|
||||||
|
section = new JsonObject();
|
||||||
|
root[LandingPageOptions.SectionName] = section;
|
||||||
|
}
|
||||||
|
|
||||||
|
section[nameof(LandingPageOptions.ShowWalkingLabFigure)] = value;
|
||||||
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
||||||
|
File.WriteAllText(path, root.ToJsonString(options), new UTF8Encoding(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,6 +69,9 @@ public sealed class UiTextService : IUiTextService
|
|||||||
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "No se pudo cambiar la contraseña. Compruebe el nombre o la contraseña actual.",
|
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "No se pudo cambiar la contraseña. Compruebe el nombre o la contraseña actual.",
|
||||||
["Passwort wurde geändert."] = "La contraseña se ha cambiado.",
|
["Passwort wurde geändert."] = "La contraseña se ha cambiado.",
|
||||||
["HR-/Finance-Cockpit Sessions"] = "Sesiones de cockpit HR/Finance",
|
["HR-/Finance-Cockpit Sessions"] = "Sesiones de cockpit HR/Finance",
|
||||||
|
["Startseite"] = "Página de inicio",
|
||||||
|
["Optionale Animation unter dem Willkommens-Text."] = "Animación opcional debajo del texto de bienvenida.",
|
||||||
|
["Strichmännchen anzeigen"] = "Mostrar figura de líneas",
|
||||||
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "Se cuentan los desbloqueos internos de la app desde el último inicio.",
|
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "Se cuentan los desbloqueos internos de la app desde el último inicio.",
|
||||||
["Bereich"] = "Área",
|
["Bereich"] = "Área",
|
||||||
["IP-Adresse"] = "Dirección IP",
|
["IP-Adresse"] = "Dirección IP",
|
||||||
@@ -299,6 +302,9 @@ public sealed class UiTextService : IUiTextService
|
|||||||
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "Impossibile modificare la password. Controllare nome o password attuale.",
|
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "Impossibile modificare la password. Controllare nome o password attuale.",
|
||||||
["Passwort wurde geändert."] = "La password è stata modificata.",
|
["Passwort wurde geändert."] = "La password è stata modificata.",
|
||||||
["HR-/Finance-Cockpit Sessions"] = "Sessioni cockpit HR/Finance",
|
["HR-/Finance-Cockpit Sessions"] = "Sessioni cockpit HR/Finance",
|
||||||
|
["Startseite"] = "Pagina iniziale",
|
||||||
|
["Optionale Animation unter dem Willkommens-Text."] = "Animazione opzionale sotto il testo di benvenuto.",
|
||||||
|
["Strichmännchen anzeigen"] = "Mostra omino",
|
||||||
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "Vengono contati gli sblocchi interni dell'app dall'ultimo avvio.",
|
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "Vengono contati gli sblocchi interni dell'app dall'ultimo avvio.",
|
||||||
["Bereich"] = "Area",
|
["Bereich"] = "Area",
|
||||||
["IP-Adresse"] = "Indirizzo IP",
|
["IP-Adresse"] = "Indirizzo IP",
|
||||||
@@ -529,6 +535,9 @@ public sealed class UiTextService : IUiTextService
|
|||||||
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "पासवर्ड बदला नहीं जा सका. नाम या वर्तमान पासवर्ड जांचें.",
|
["Passwort konnte nicht geändert werden. Name oder aktuelles Passwort prüfen."] = "पासवर्ड बदला नहीं जा सका. नाम या वर्तमान पासवर्ड जांचें.",
|
||||||
["Passwort wurde geändert."] = "पासवर्ड बदल दिया गया.",
|
["Passwort wurde geändert."] = "पासवर्ड बदल दिया गया.",
|
||||||
["HR-/Finance-Cockpit Sessions"] = "HR/Finance cockpit sessions",
|
["HR-/Finance-Cockpit Sessions"] = "HR/Finance cockpit sessions",
|
||||||
|
["Startseite"] = "होम पेज",
|
||||||
|
["Optionale Animation unter dem Willkommens-Text."] = "स्वागत पाठ के नीचे वैकल्पिक animation.",
|
||||||
|
["Strichmännchen anzeigen"] = "स्टिक फिगर दिखाएं",
|
||||||
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "ऐप के पिछले प्रारंभ के बाद से आंतरिक अनलॉक गिने जाते हैं.",
|
["Gezählt werden App-interne Entsperrungen seit dem letzten App-Start."] = "ऐप के पिछले प्रारंभ के बाद से आंतरिक अनलॉक गिने जाते हैं.",
|
||||||
["Bereich"] = "क्षेत्र",
|
["Bereich"] = "क्षेत्र",
|
||||||
["IP-Adresse"] = "IP पता",
|
["IP-Adresse"] = "IP पता",
|
||||||
|
|||||||
@@ -43,5 +43,8 @@
|
|||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"Username": "admin",
|
"Username": "admin",
|
||||||
"PasswordHash": "F0101E12FBCCDD6D2645B214B8732F5AEDFFB2DABBE7EE98043E68DB3BD9ADA4"
|
"PasswordHash": "F0101E12FBCCDD6D2645B214B8732F5AEDFFB2DABBE7EE98043E68DB3BD9ADA4"
|
||||||
|
},
|
||||||
|
"LandingPage": {
|
||||||
|
"ShowWalkingLabFigure": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# Admin Bereich und Startseite, Stand 2026-05-21
|
||||||
|
|
||||||
|
## Admin Bereich
|
||||||
|
|
||||||
|
Der Menüpunkt `Admin Bereich` ist ein eigener Hauptmenüpunkt und liegt nicht unter `Finance`.
|
||||||
|
|
||||||
|
Wichtig:
|
||||||
|
|
||||||
|
- Der Admin Bereich darf nicht durch den Finance-Cockpit-Login blockiert werden.
|
||||||
|
- Route: `/admin/sessions`
|
||||||
|
- Schutz: eigener App-interner Admin-Login über `AdminAccess`
|
||||||
|
- Initialer Benutzer: `admin`
|
||||||
|
- Initiales Passwort: `TrafagAdmin2026!`
|
||||||
|
- Das Admin-Passwort ist unabhängig vom Finance-Cockpit-Passwort.
|
||||||
|
- Das Passwort kann direkt im Admin-Loginbereich geändert werden.
|
||||||
|
|
||||||
|
Technische Dateien:
|
||||||
|
|
||||||
|
- `Components/Pages/AdminSessions.razor`
|
||||||
|
- `Components/AdminAccessPanel.razor`
|
||||||
|
- `Services/AdminAccessService.cs`
|
||||||
|
- `Security/AdminAccessOptions.cs`
|
||||||
|
- `appsettings.json`
|
||||||
|
|
||||||
|
Korrektur 2026-05-21:
|
||||||
|
|
||||||
|
- `/admin/sessions` wurde aus der globalen Finance-Sperrliste in `Components/Routes.razor` entfernt.
|
||||||
|
- Dadurch erscheint im Admin Bereich nicht mehr zuerst der Text `Finance Cockpit ist geschützt. Bitte separat anmelden.`
|
||||||
|
- Der Admin Bereich bleibt trotzdem geschützt, aber mit dem separaten Admin-Passwort.
|
||||||
|
|
||||||
|
## Aktive Logins
|
||||||
|
|
||||||
|
Der Admin Bereich zeigt aktive HR-/Finance-App-Entsperrungen seit dem letzten App-Start.
|
||||||
|
|
||||||
|
Einschränkung:
|
||||||
|
|
||||||
|
- HR und Finance verwenden aktuell gemeinsame App-Logins.
|
||||||
|
- Die Anzeige zeigt deshalb den verwendeten Login-Namen, IP-Adresse und Session-Zeitpunkte.
|
||||||
|
- Sie beweist nicht zwingend die echte Windows-Person hinter dem Zugriff.
|
||||||
|
|
||||||
|
## Startseite
|
||||||
|
|
||||||
|
Die Startseite `/` ist bewusst neutral und verlangt keinen Finance-Login.
|
||||||
|
|
||||||
|
Aktueller Aufbau:
|
||||||
|
|
||||||
|
- weißer Hintergrund
|
||||||
|
- schwarzer animierter Manometer
|
||||||
|
- Trafag-Schriftzug im Manometer
|
||||||
|
- Willkommenstext in der gewählten Sprache
|
||||||
|
- optionales animiertes Strichmännchen mit Kittel unter dem Willkommenstext
|
||||||
|
|
||||||
|
Die Corporate-Schrift wurde an die Trafag-Webseite angenähert:
|
||||||
|
|
||||||
|
- Google Font `Open Sans`
|
||||||
|
- Fallbacks: `Helvetica Neue`, `Helvetica`, `Arial`, `sans-serif`
|
||||||
|
|
||||||
|
Technische Dateien:
|
||||||
|
|
||||||
|
- `Components/App.razor`
|
||||||
|
- `wwwroot/css/app.css`
|
||||||
|
- `Components/Pages/Dashboard.razor`
|
||||||
|
- `Services/UiTextService.cs`
|
||||||
|
|
||||||
|
## Schalter für Strichmännchen
|
||||||
|
|
||||||
|
Das Strichmännchen ist standardmäßig deaktiviert.
|
||||||
|
|
||||||
|
Aktivierung:
|
||||||
|
|
||||||
|
1. `Admin Bereich` öffnen.
|
||||||
|
2. Mit Admin-Passwort anmelden.
|
||||||
|
3. Schalter `Strichmännchen anzeigen` aktivieren.
|
||||||
|
|
||||||
|
Speicherung:
|
||||||
|
|
||||||
|
- Einstellung: `LandingPage.ShowWalkingLabFigure`
|
||||||
|
- Datei: `appsettings.json`
|
||||||
|
- Service: `LandingPageSettingsService`
|
||||||
|
|
||||||
|
Technische Dateien:
|
||||||
|
|
||||||
|
- `Security/LandingPageOptions.cs`
|
||||||
|
- `Services/LandingPageSettingsService.cs`
|
||||||
|
- `Program.cs`
|
||||||
|
- `Components/Pages/AdminSessions.razor`
|
||||||
|
|
||||||
|
## Lokaler Übergangsserver
|
||||||
|
|
||||||
|
Für Tests auf dem eigenen PC wurde Port `5000` vorbereitet.
|
||||||
|
|
||||||
|
Firewall-Regel:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Name: Local Dev Web Port 5000
|
||||||
|
Richtung: Eingehend
|
||||||
|
Protokoll: TCP
|
||||||
|
Lokaler Port: 5000
|
||||||
|
Profile: Domäne, Privat, Öffentlich
|
||||||
|
Aktion: Zulassen
|
||||||
|
```
|
||||||
|
|
||||||
|
Startprofil:
|
||||||
|
|
||||||
|
- `Properties/launchSettings.json`
|
||||||
|
- enthält `http://0.0.0.0:5000`
|
||||||
|
|
||||||
|
Aufruf für andere Benutzer im Netzwerk/VPN:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://172.16.9.185:5000/
|
||||||
|
```
|
||||||
|
|
||||||
|
Hinweise:
|
||||||
|
|
||||||
|
- Die IP kann sich nach Neustart oder Netzwerkwechsel ändern.
|
||||||
|
- Die Firewall-Regel bleibt nach Neustart aktiv.
|
||||||
|
- Die Anwendung muss trotzdem auf dem PC laufen.
|
||||||
|
- Lokal ist das ohne Zertifikat `http`, nicht `https`.
|
||||||
|
|
||||||
|
## Serverproblem
|
||||||
|
|
||||||
|
Die Veröffentlichung auf den Server wurde technisch ausgeführt, aber HTTPS-Aufrufe werden vor der App durch IIS/TLS blockiert.
|
||||||
|
|
||||||
|
Beobachtung:
|
||||||
|
|
||||||
|
- IIS fordert ein Client-Zertifikat an.
|
||||||
|
- Der Fehler passiert vor der Blazor-App.
|
||||||
|
- Kopieren ins Root-Verzeichnis löst das nicht.
|
||||||
|
|
||||||
|
Marco/IT muss auf dem IIS für die Site bzw. Anwendung prüfen:
|
||||||
|
|
||||||
|
- SSL Settings
|
||||||
|
- Client certificates: `Ignore` oder höchstens `Accept`
|
||||||
|
- nicht `Require`
|
||||||
|
|
||||||
|
Erst danach ist sinnvoll zu prüfen, ob die veröffentlichte App normal erreichbar ist.
|
||||||
@@ -2182,3 +2182,37 @@ Hinweis:
|
|||||||
|
|
||||||
- Der direkte Vergleich gegen die lokale SQLite-Datei `trafag_exporter.db` war nicht aussagekraeftig, weil diese lokale DB keine passenden `CentralSalesRecords` fuer diesen Stand enthaelt.
|
- Der direkte Vergleich gegen die lokale SQLite-Datei `trafag_exporter.db` war nicht aussagekraeftig, weil diese lokale DB keine passenden `CentralSalesRecords` fuer diesen Stand enthaelt.
|
||||||
- Die Excel-interne Summenpruefung und der Vergleich gegen `output\Sales_All_2026-05-20.xlsx` waren konsistent.
|
- Die Excel-interne Summenpruefung und der Vergleich gegen `output\Sales_All_2026-05-20.xlsx` waren konsistent.
|
||||||
|
|
||||||
|
## Admin Bereich und Startseite aktualisiert 2026-05-21
|
||||||
|
|
||||||
|
Admin Bereich:
|
||||||
|
|
||||||
|
- `/admin/sessions` ist nicht mehr durch den Finance-Cockpit-Login vorgeschaltet.
|
||||||
|
- Der Admin Bereich nutzt weiterhin ein eigenes Admin-Passwort über `AdminAccess`.
|
||||||
|
- Initialer Benutzer: `admin`
|
||||||
|
- Initiales Passwort: `TrafagAdmin2026!`
|
||||||
|
- Das Admin-Passwort ist unabhängig vom Finance-Cockpit-Passwort.
|
||||||
|
- Dokumentation ergänzt: `docs/ADMIN_BEREICH_STARTSEITE_2026-05-21.md`
|
||||||
|
|
||||||
|
Startseite:
|
||||||
|
|
||||||
|
- Corporate-Schrift auf `Open Sans` mit Trafag-nahen Fallbacks angepasst.
|
||||||
|
- Manometer-Startgrafik bleibt auf weißem Hintergrund, schwarz gezeichnet und mit Trafag-Schriftzug.
|
||||||
|
- Willkommenstext ist sprachabhängig.
|
||||||
|
- Optionales Strichmännchen mit Kittel unter dem Willkommenstext ergänzt.
|
||||||
|
- Das Strichmännchen ist standardmäßig deaktiviert.
|
||||||
|
- Aktivierung über `Admin Bereich` -> `Strichmännchen anzeigen`.
|
||||||
|
- Einstellung wird in `appsettings.json` unter `LandingPage.ShowWalkingLabFigure` gespeichert.
|
||||||
|
|
||||||
|
Technische Dateien:
|
||||||
|
|
||||||
|
- `Components/Routes.razor`
|
||||||
|
- `Components/App.razor`
|
||||||
|
- `wwwroot/css/app.css`
|
||||||
|
- `Components/Pages/Dashboard.razor`
|
||||||
|
- `Components/Pages/AdminSessions.razor`
|
||||||
|
- `Program.cs`
|
||||||
|
- `Security/LandingPageOptions.cs`
|
||||||
|
- `Services/LandingPageSettingsService.cs`
|
||||||
|
- `Services/UiTextService.cs`
|
||||||
|
- `appsettings.json`
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
html, body {
|
html,
|
||||||
font-family: 'Roboto', sans-serif;
|
body,
|
||||||
|
.mud-typography,
|
||||||
|
.mud-button-root,
|
||||||
|
.mud-input,
|
||||||
|
.mud-table,
|
||||||
|
.mud-nav-link,
|
||||||
|
.mud-chip,
|
||||||
|
.mud-list-item,
|
||||||
|
.mud-menu-item {
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-title {
|
.app-title {
|
||||||
|
|||||||
Reference in New Issue
Block a user