diff --git a/TrafagSalesExporter/Components/App.razor b/TrafagSalesExporter/Components/App.razor index df9469f..64e19c7 100644 --- a/TrafagSalesExporter/Components/App.razor +++ b/TrafagSalesExporter/Components/App.razor @@ -6,7 +6,7 @@ Trafag Finanze/Sales Management Cockpit - + diff --git a/TrafagSalesExporter/Components/Pages/AdminSessions.razor b/TrafagSalesExporter/Components/Pages/AdminSessions.razor index 089057d..9c54585 100644 --- a/TrafagSalesExporter/Components/Pages/AdminSessions.razor +++ b/TrafagSalesExporter/Components/Pages/AdminSessions.razor @@ -3,6 +3,7 @@ @using TrafagSalesExporter.Services @inject IAccessSessionTracker SessionTracker @inject IAdminAccessService AdminAccess +@inject ILandingPageSettingsService LandingSettings @inject IUiTextService UiText @T("Aktive Logins", "Active logins") @@ -16,6 +17,19 @@ else { + +
+ @T("Startseite", "Landing page") + + @T("Optionale Animation unter dem Willkommens-Text.", "Optional animation below the welcome text.") + +
+ + +
+
@T("HR-/Finance-Cockpit Sessions", "HR/Finance cockpit sessions") @@ -77,6 +91,11 @@ else _sessions = []; } + private void SetWalkingFigure(bool value) + { + LandingSettings.SetShowWalkingLabFigure(value); + } + private static string FormatDate(DateTimeOffset value) => value.ToString("dd.MM.yyyy HH:mm:ss"); diff --git a/TrafagSalesExporter/Components/Pages/Dashboard.razor b/TrafagSalesExporter/Components/Pages/Dashboard.razor index e7fd4c7..9687920 100644 --- a/TrafagSalesExporter/Components/Pages/Dashboard.razor +++ b/TrafagSalesExporter/Components/Pages/Dashboard.razor @@ -1,6 +1,7 @@ @page "/" @using TrafagSalesExporter.Services @inject IUiTextService UiText +@inject ILandingPageSettingsService LandingSettings @T("Trafag Cockpit", "Trafag Cockpit") @@ -30,6 +31,21 @@
@T("Willkommen im Trafag Analyse Dashboard", "Welcome to the Trafag Analytical Dashboard")
+ @if (LandingSettings.ShowWalkingLabFigure) + { +
+
+ + + + + + + + +
+
+ }
@@ -63,6 +79,114 @@ 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-inner, .gauge-tick, diff --git a/TrafagSalesExporter/Components/Routes.razor b/TrafagSalesExporter/Components/Routes.razor index 4bec2d4..792e12e 100644 --- a/TrafagSalesExporter/Components/Routes.razor +++ b/TrafagSalesExporter/Components/Routes.razor @@ -50,7 +50,6 @@ "transformations" or "finance-rules" or "settings" or - "admin/sessions" or "logs" or "source-viewer"; } diff --git a/TrafagSalesExporter/Program.cs b/TrafagSalesExporter/Program.cs index 87e4bc0..c1595c5 100644 --- a/TrafagSalesExporter/Program.cs +++ b/TrafagSalesExporter/Program.cs @@ -49,6 +49,7 @@ builder.Services.Configure(builder.Configuration.GetSect builder.Services.Configure(builder.Configuration.GetSection(HrKpiAccessOptions.SectionName)); builder.Services.Configure(builder.Configuration.GetSection(FinanceCockpitAccessOptions.SectionName)); builder.Services.Configure(builder.Configuration.GetSection(AdminAccessOptions.SectionName)); +builder.Services.Configure(builder.Configuration.GetSection(LandingPageOptions.SectionName)); builder.Services.AddDbContextFactory(options => options.UseSqlite("Data Source=trafag_exporter.db;Default Timeout=60")); @@ -88,6 +89,7 @@ builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); // Datenquellen-Adapter (Strategy per ConnectionKind). builder.Services.AddSingleton(); diff --git a/TrafagSalesExporter/Security/LandingPageOptions.cs b/TrafagSalesExporter/Security/LandingPageOptions.cs new file mode 100644 index 0000000..05cd663 --- /dev/null +++ b/TrafagSalesExporter/Security/LandingPageOptions.cs @@ -0,0 +1,8 @@ +namespace TrafagSalesExporter.Security; + +public sealed class LandingPageOptions +{ + public const string SectionName = "LandingPage"; + + public bool ShowWalkingLabFigure { get; set; } +} diff --git a/TrafagSalesExporter/Services/LandingPageSettingsService.cs b/TrafagSalesExporter/Services/LandingPageSettingsService.cs new file mode 100644 index 0000000..3aa85ed --- /dev/null +++ b/TrafagSalesExporter/Services/LandingPageSettingsService.cs @@ -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 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)); + } + } +} diff --git a/TrafagSalesExporter/Services/UiTextService.cs b/TrafagSalesExporter/Services/UiTextService.cs index 50e06d8..9654b5f 100644 --- a/TrafagSalesExporter/Services/UiTextService.cs +++ b/TrafagSalesExporter/Services/UiTextService.cs @@ -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 wurde geändert."] = "La contraseña se ha cambiado.", ["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.", ["Bereich"] = "Área", ["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 wurde geändert."] = "La password è stata modificata.", ["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.", ["Bereich"] = "Area", ["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 wurde geändert."] = "पासवर्ड बदल दिया गया.", ["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."] = "ऐप के पिछले प्रारंभ के बाद से आंतरिक अनलॉक गिने जाते हैं.", ["Bereich"] = "क्षेत्र", ["IP-Adresse"] = "IP पता", diff --git a/TrafagSalesExporter/appsettings.json b/TrafagSalesExporter/appsettings.json index 81261ef..6a7ea3e 100644 --- a/TrafagSalesExporter/appsettings.json +++ b/TrafagSalesExporter/appsettings.json @@ -43,5 +43,8 @@ "Enabled": true, "Username": "admin", "PasswordHash": "F0101E12FBCCDD6D2645B214B8732F5AEDFFB2DABBE7EE98043E68DB3BD9ADA4" + }, + "LandingPage": { + "ShowWalkingLabFigure": false } } diff --git a/TrafagSalesExporter/docs/ADMIN_BEREICH_STARTSEITE_2026-05-21.md b/TrafagSalesExporter/docs/ADMIN_BEREICH_STARTSEITE_2026-05-21.md new file mode 100644 index 0000000..e83ec62 --- /dev/null +++ b/TrafagSalesExporter/docs/ADMIN_BEREICH_STARTSEITE_2026-05-21.md @@ -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. diff --git a/TrafagSalesExporter/lastchange.md b/TrafagSalesExporter/lastchange.md index 8a7f80d..2c617ff 100644 --- a/TrafagSalesExporter/lastchange.md +++ b/TrafagSalesExporter/lastchange.md @@ -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. - 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` diff --git a/TrafagSalesExporter/wwwroot/css/app.css b/TrafagSalesExporter/wwwroot/css/app.css index 2bf79fd..e3ae08b 100644 --- a/TrafagSalesExporter/wwwroot/css/app.css +++ b/TrafagSalesExporter/wwwroot/css/app.css @@ -1,5 +1,14 @@ -html, body { - font-family: 'Roboto', sans-serif; +html, +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 {