Browse Source

Umfrage Prototyp unter /

Leonard Schulz 1 năm trước cách đây
mục cha
commit
fcb03ffde3

+ 43 - 0
src/main/java/com/tsystems/inwo/vgl/web/HhmEinkommenController.java

@@ -8,7 +8,10 @@ import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.http.ResponseEntity;
+import org.springframework.core.io.ClassPathResource;
 import java.util.*;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
 
 @Controller
 @RequestMapping("/hhm-einkommen")
@@ -30,6 +33,39 @@ public class HhmEinkommenController {
         this.dataExtractor = dataExtractor;
     }
 
+    @GetMapping
+    public String vergleichGet(
+            @RequestParam(required = false, defaultValue = "false") boolean loadExample,
+            @RequestParam(required = false, defaultValue = "realistic") String exampleType,
+            @RequestParam(required = false, defaultValue = "true") boolean validate,
+            @RequestParam(required = false) String kunde,
+            @RequestHeader(value = "X-Kunde", required = false) String kundeHeader,
+            Model model) {
+
+        if (loadExample) {
+            try {
+                String altFile = exampleType.equals("many") ? 
+                    "static/example-alt.json" : 
+                    "static/example-realistic-alt.json";
+                String neuFile = exampleType.equals("many") ? 
+                    "static/example-neu.json" : 
+                    "static/example-realistic-neu.json";
+
+                String leftJson = loadJsonFromClasspath(altFile);
+                String rightJson = loadJsonFromClasspath(neuFile);
+
+                return vergleich(leftJson, rightJson, validate, "haushalt-einkommen", 
+                               null, null, null, null, kunde, kundeHeader, model);
+            } catch (Exception e) {
+                model.addAttribute("processingErrors", List.of("Fehler beim Laden der Beispieldaten: " + e.getMessage()));
+                return "fehler";
+            }
+        }
+
+        // Wenn keine Beispieldaten geladen werden sollen, redirect zu Test-Seite
+        return "redirect:/test";
+    }
+
     @PostMapping
     public String vergleich(
             @RequestParam String leftJson,
@@ -278,6 +314,13 @@ public class HhmEinkommenController {
         return kunde != null ? kunde : kundeHeader;
     }
     
+    private String loadJsonFromClasspath(String path) throws IOException {
+        ClassPathResource resource = new ClassPathResource(path);
+        try (InputStream inputStream = resource.getInputStream()) {
+            return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+        }
+    }
+    
     private PersonComparisonContext createPersonComparisonContext(JsonNode rightZeitraum, JsonNode leftZeitraum, String personId) {
         // Personen-Tabelle (UNION via person.id)
         Map<String, Pair<JsonNode, JsonNode>> personenPairs = comparisonService.unionByKey(

+ 43 - 0
src/main/java/com/tsystems/inwo/vgl/web/MieteController.java

@@ -8,7 +8,10 @@ import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.http.ResponseEntity;
+import org.springframework.core.io.ClassPathResource;
 import java.util.*;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
 
 @Controller
 @RequestMapping("/miete")
@@ -30,6 +33,39 @@ public class MieteController {
         this.dataExtractor = dataExtractor;
     }
 
+    @GetMapping
+    public String vergleichGet(
+            @RequestParam(required = false, defaultValue = "false") boolean loadExample,
+            @RequestParam(required = false, defaultValue = "realistic") String exampleType,
+            @RequestParam(required = false, defaultValue = "true") boolean validate,
+            @RequestParam(required = false) String kunde,
+            @RequestHeader(value = "X-Kunde", required = false) String kundeHeader,
+            Model model) {
+
+        if (loadExample) {
+            try {
+                String altFile = exampleType.equals("many") ? 
+                    "static/example-miete-alt.json" : 
+                    "static/example-miete-realistic-alt.json";
+                String neuFile = exampleType.equals("many") ? 
+                    "static/example-miete-neu.json" : 
+                    "static/example-miete-realistic-neu.json";
+
+                String leftJson = loadJsonFromClasspath(altFile);
+                String rightJson = loadJsonFromClasspath(neuFile);
+
+                return vergleich(leftJson, rightJson, validate, "miete", 
+                               null, null, null, kunde, kundeHeader, model);
+            } catch (Exception e) {
+                model.addAttribute("processingErrors", List.of("Fehler beim Laden der Beispieldaten: " + e.getMessage()));
+                return "fehler";
+            }
+        }
+
+        // Wenn keine Beispieldaten geladen werden sollen, redirect zu Test-Seite
+        return "redirect:/test";
+    }
+
     @PostMapping
     public String vergleich(
             @RequestParam String leftJson,
@@ -243,6 +279,13 @@ public class MieteController {
         return kunde != null ? kunde : kundeHeader;
     }
 
+    private String loadJsonFromClasspath(String path) throws IOException {
+        ClassPathResource resource = new ClassPathResource(path);
+        try (InputStream inputStream = resource.getInputStream()) {
+            return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+        }
+    }
+
     // ===== Response Classes =====
     
     public record VorgangChangeResponse(

+ 16 - 0
src/main/java/com/tsystems/inwo/vgl/web/PrototypeController.java

@@ -0,0 +1,16 @@
+package com.tsystems.inwo.vgl.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class PrototypeController {
+
+    @GetMapping("/")
+    public String prototype(Model model) {
+        model.addAttribute("activeKunde", "Berlin");
+        model.addAttribute("pageTitle", "DIWO");
+        return "prototype";
+    }
+}

+ 1 - 0
src/main/resources/static/example-miete-realistic-alt.json

@@ -0,0 +1 @@
+{"stammakte":{"aktenzeichen":"01/01/119979","antragstellername":"Müller","antragstellerGeburtsdatum":"2000-01-01","anschrift":{"strasse":"Unter den Linden","hausnummer":"1","zusatz":"","plz":"10117","ort":"Berlin"},"vorgaenge":[{"stammvorgang":{"id":"1","vorgangstyp":"Erstantrag","vorgangsstatus":"unvollständig"},"zeitraeume":[{"id":"1","beginn":"2025-07-01","ende":"2026-06-30","miete":{"id":"1","miete":1600,"heizungP":null,"warmwasserP":null,"moeblierungP":null,"gewerbeZuschlagP":null,"sonstWogFaehigText":"","sonstZuschlagBeschr":"","energieP":null,"stellplatzP":null,"untermieter":[{"miId":"127560","lfdnr":1,"name":"Mieter","vorname":"Test","flaeche":10,"miete":200,"heizungP":null,"warmwasser":10,"warmwasserP":null,"moeblierungP":null,"sonst":10}],"mitbewohner":[]},"ausstattung":{"id":"1","flaeche":70,"heizung":"Zentralheizung","bad":"Mit Bad oder Duschraum","sozBauJn":false,"mietverhaeltnis":"Hauptm.und Nutzungsber.","eigentum":"","nameEig":"XYZ Vermietung GmbH","adresseEig":"","telefonEig":"12345","wofgJn":false,"foerderungJn":false}}]},{"stammvorgang":{"id":"2","vorgangstyp":"Weiterleistungsantrag","vorgangsstatus":"Antrag gelöscht"},"zeitraeume":[{"id":"1","beginn":"2026-07-01","ende":"2027-06-30","miete":{"id":"1","miete":1600,"heizungP":null,"warmwasserP":null,"moeblierungP":null,"gewerbeZuschlagP":null,"sonstWogFaehigText":"","sonstZuschlagBeschr":"","energie":100,"energieP":null,"stellplatz":125,"stellplatzP":null,"untermieter":[],"mitbewohner":[]},"ausstattung":{"id":"1","flaeche":70,"heizung":"Zentralheizung","bad":"Mit Bad oder Duschraum","sozBauJn":false,"mietverhaeltnis":"Hauptm.und Nutzungsber.","eigentum":"","nameEig":"XYZ Vermietung GmbH","adresseEig":"","telefonEig":"12345","wofgJn":false,"foerderungJn":false}}]}]}}

+ 1 - 0
src/main/resources/static/example-miete-realistic-neu.json

@@ -0,0 +1 @@
+{"stammakte":{"aktenzeichen":"01/01/119979","antragstellername":"Müller","antragstellerGeburtsdatum":"2000-01-01","anschrift":{"strasse":"Unter den Linden","hausnummer":"1","zusatz":"","plz":"10117","ort":"Berlin"},"vorgaenge":[{"stammvorgang":{"id":"3","vorgangstyp":"Weiterleistungsantrag","vorgangsstatus":"unvollständig"},"zeitraeume":[{"id":"1","beginn":"2026-07-01","ende":"2027-06-30","miete":{"id":"1","miete":1600,"sonstZuschlag":100,"beitragDritter":100,"heizung":200,"heizungP":null,"warmwasserP":null,"moeblierungP":null,"gewerbeZuschlagP":null,"gewerbeFlaeche":20,"sonstWogFaehigBetrag":100,"sonstWogFaehigText":"Gartenleistungen","sonstZuschlagBeschr":"Hausmeister","energie":100,"energieP":null,"stellplatz":160,"stellplatzP":null,"untermieter":[],"mitbewohner":[]},"ausstattung":{"id":"1","flaeche":70,"heizung":"Zentralheizung","bad":"Mit Bad oder Duschraum","sozBauJn":false,"mietverhaeltnis":"Hauptm.und Nutzungsber.","eigentum":"","fertigDat":"2000-01-01","nameEig":"XYZ Vermietung GmbH","adresseEig":"Neue Adresse ","telefonEig":"12345","wofgJn":false,"foerderungJn":false}}]}]}}

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
src/main/resources/static/example-realistic-alt.json


+ 1 - 0
src/main/resources/static/example-realistic-neu.json

@@ -0,0 +1 @@
+{"stammakte":{"aktenzeichen":"01/01/119979","antragstellername":"Müller","antragstellerGeburtsdatum":"2000-01-01","anschrift":{"strasse":"Unter den Linden","hausnummer":"1","zusatz":"","plz":"10117","ort":"Berlin"},"vorgaenge":[{"stammvorgang":{"id":"3","vorgangstyp":"Weiterleistungsantrag","vorgangsstatus":"unvollständig"},"zeitraeume":[{"id":"1","beginn":"2026-07-01","ende":"2027-06-30","personen":[{"person":{"id":"133768","nachname":"Müller","vorname":"Tobias","anrede":"Herr","geburtsdatum":"2000-01-01","geschlecht":"Männlich","telefon":"01234 567890","email":"tobias.mueller@mail.de","blockname":false,"verwandtschaftsverhaeltnis":"Ehe-/Lebenspartner*in","sozialstellung":"Angestellte/Angestellter","familienstand":"verheiratet"},"einkommen":[{"id":"1","art":"Eink. aus nichtselbst. Tätigkeit","artZusatz":"12dsds","faktor":12,"betrag":800},{"id":"2","art":"Eink. aus nichtselbst. Tätigkeit","faktor":12,"betrag":600}],"freibetraege":[{"id":"1","art":"Abzug für Krankenversicherung","typ":"P"},{"id":"2","art":"Abzug für Rentenversicherung","typ":"P"},{"id":"3","art":"Pauschaler Abzug für Steuern 10%","typ":"P"},{"id":"4","art":"Unterhalt (§ 18 Satz 1 Nr. 1 WoGG)","typ":"F","faktor":12,"betrag":100}],"kinderbetreuung":[{"id":"1","kindRef":"133771","betrag":100}]},{"person":{"id":"133770","nachname":"Müller","vorname":"Annemarie","anrede":"Frau","geburtsdatum":"1991-08-08","geschlecht":"Weiblich","blockname":false,"verwandtschaftsverhaeltnis":"Ehe-/Lebenspartner*in","sozialstellung":"Angestellte/Angestellter","familienstand":"verheiratet"}},{"person":{"id":"133771","nachname":"Müller","vorname":"Sofie","anrede":"Frau","geburtsdatum":"2025-01-16","geschlecht":"Weiblich","blockname":false,"verwandtschaftsverhaeltnis":"Kind","sozialstellung":"Sonst. nicht erwerbstätige Person","familienstand":"ledig"}}]}]}]}}

BIN
src/main/resources/static/images/hhm-einkommen-diwo.jpg


BIN
src/main/resources/static/images/miete-diwo.jpg


+ 341 - 0
src/main/resources/templates/prototype.html

@@ -0,0 +1,341 @@
+<!DOCTYPE html>
+<html lang="de" xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8"/>
+    <title>Vergleich – Prototyp</title>
+    <link rel="stylesheet" href="/css/global.css"/>
+    <link rel="stylesheet" href="/css/header.css"/>
+    <link rel="stylesheet" href="/css/footer.css"/>
+    <style>
+        .light-header {
+            background-color: #f8f9fa;
+            border-bottom: 1px solid #dee2e6;
+            padding: 1rem 2rem;
+            margin-bottom: 1rem;
+        }
+        
+        .header-row-1 {
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+        }
+        
+        .kunde-logo-container {
+            height: 40px;
+        }
+        
+        .kunde-logo-image {
+            height: 40px;
+            width: auto;
+        }
+        
+        .page-title {
+            font-size: 1.5rem;
+            font-weight: 600;
+            color: #333;
+            margin: 0;
+        }
+        
+        .container {
+            display: flex;
+            min-height: calc(100vh - 300px);
+            gap: 1rem;
+            padding: 0 2rem;
+        }
+        
+        .sidebar {
+            width: 300px;
+            background-color: #f8f9fa;
+            padding: 1.5rem;
+            border-radius: 8px;
+            height: fit-content;
+            position: sticky;
+            top: 1rem;
+            display: flex;
+            flex-direction: column;
+        }
+        
+        .main-content {
+            flex: 1;
+            min-width: 0;
+        }
+        
+        .navigation {
+            margin-bottom: auto;
+        }
+        
+        .navigation h3 {
+            margin: 0 0 1rem 0;
+            color: #333;
+            font-size: 1.1rem;
+        }
+        
+        .nav-links {
+            display: flex;
+            flex-direction: column;
+            gap: 0.5rem;
+            list-style: none;
+            margin: 0;
+            padding: 0;
+        }
+        
+        .nav-links a {
+            text-decoration: none;
+            color: #007bff;
+            padding: 0.8rem 1rem;
+            border-radius: 5px;
+            transition: all 0.3s;
+            border: 2px solid transparent;
+            display: block;
+        }
+        
+        .nav-links a:hover {
+            background-color: #e9ecef;
+            transform: translateX(5px);
+        }
+        
+        .nav-links a.active {
+            background-color: #007bff;
+            color: white;
+            border-color: #0056b3;
+            box-shadow: 0 2px 4px rgba(0,123,255,0.3);
+        }
+        
+        .controls {
+            border-top: 1px solid #dee2e6;
+            padding-top: 1rem;
+            margin-top: 1rem;
+        }
+        
+        .controls h3 {
+            margin: 0 0 0.8rem 0;
+            color: #333;
+            font-size: 1rem;
+        }
+        
+        .controls label {
+            display: block;
+            margin-bottom: 0.4rem;
+            font-weight: 500;
+            color: #555;
+            font-size: 0.9rem;
+        }
+        
+        .controls select {
+            width: 100%;
+            padding: 0.5rem;
+            border: 1px solid #ccc;
+            border-radius: 4px;
+            margin-bottom: 0.8rem;
+            font-size: 0.85rem;
+        }
+        
+        .controls select:focus {
+            outline: none;
+            border-color: #007bff;
+            box-shadow: 0 0 0 2px rgba(0,123,255,0.25);
+        }
+        
+        .screenshot-container {
+            position: relative;
+            border: 2px solid #dee2e6;
+            border-radius: 8px;
+            overflow: hidden;
+            background-color: #fff;
+            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
+        }
+        
+        .screenshot {
+            width: 100%;
+            height: auto;
+            display: block;
+            position: relative;
+        }
+        
+        .screenshot img {
+            width: 100%;
+            height: auto;
+            display: block;
+        }
+        
+        .watermark {
+            position: absolute;
+            bottom: 50px;
+            right: 20px;
+            background-color: rgba(255, 255, 255, 0.9);
+            color: #ff0000;
+            padding: 0.5rem 1rem;
+            border-radius: 20px;
+            font-size: 0.9rem;
+            font-weight: 500;
+            border: 1px solid rgba(0, 0, 0, 0.1);
+            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+            z-index: 5;
+        }
+        
+        .compare-button {
+            position: absolute;
+            top: 100px;
+            right: 200px;
+            background-color: #28a745;
+            color: white;
+            border: none;
+            padding: 0.8rem 1.5rem;
+            border-radius: 5px;
+            cursor: pointer;
+            font-size: 1rem;
+            font-weight: 600;
+            z-index: 10;
+            box-shadow: 0 3px 6px rgba(0,0,0,0.2);
+            transition: all 0.3s;
+        }
+        
+        .compare-button:hover {
+            background-color: #218838;
+            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
+        }
+    </style>
+</head>
+<body>
+    <!-- Light Header -->
+    <header class="light-header">
+        <div class="header-row-1">
+            <div class="kunde-logo">
+                <div th:if="${activeKunde != null and !#strings.isEmpty(activeKunde)}" class="kunde-logo-container">
+                    <img th:src="@{'/images/' + ${#strings.toLowerCase(activeKunde)} + '.jpg'}" 
+                         th:alt="${activeKunde != null and !#strings.isEmpty(activeKunde) ? activeKunde + ' Logo' : 'Kunden-Logo'}" 
+                         class="kunde-logo-image"
+                         th:onerror="'this.style.display=\\'none\\''"/>
+                </div>
+            </div>
+            <div class="page-title" role="heading" aria-level="2" th:text="${pageTitle ?: 'Vergleich'}">Prototyp</div>
+        </div>
+    </header>
+    
+    <div class="container">
+        <aside class="sidebar">
+            <nav class="navigation">
+                <h3>Navigation</h3>
+                <ul class="nav-links">
+                    <li><a href="#" id="nav-hhm" class="nav-link active" onclick="switchView('hhm')">Haushaltsmitglieder/Einkommen</a></li>
+                    <li><a href="#" id="nav-miete" class="nav-link" onclick="switchView('miete')">Miete</a></li>
+                </ul>
+            </nav>
+            
+            <div class="controls">
+                <h3>Einstellungen</h3>
+                <label for="exampleTypeSelect">Beispieltyp:</label>
+                <select id="exampleTypeSelect" onchange="updateExampleType()">
+                    <option value="realistic">Realistische Änderungen</option>
+                    <option value="many">Viele Änderungen</option>
+                </select>
+            </div>
+        </aside>
+        
+        <main class="main-content">
+            <div class="screenshot-container">
+                <div class="watermark">Bildschirmfoto</div>
+                <button class="compare-button" onclick="openCompareView()">Vergleichsansicht</button>
+                <div class="screenshot" id="screenshot">
+                    <img src="/images/hhm-einkommen-diwo.jpg" alt="Screenshot Haushaltsmitglieder/Einkommen" id="screenshotImage">
+                </div>
+            </div>
+        </main>
+    </div>
+
+    <script>
+        let currentView = 'hhm';
+        let currentExampleType = 'realistic';
+        let compareWindow = null;
+        
+        function switchView(view) {
+            currentView = view;
+            
+            // Navigation updaten
+            document.querySelectorAll('.nav-link').forEach(link => {
+                link.classList.remove('active');
+            });
+            document.getElementById('nav-' + view).classList.add('active');
+            
+            // Screenshot updaten
+            updateScreenshot();
+            
+            // Wenn Vergleichsfenster offen ist, auch dort wechseln
+            if (compareWindow && !compareWindow.closed) {
+                updateCompareWindow();
+            }
+        }
+        
+        function updateExampleType() {
+            currentExampleType = document.getElementById('exampleTypeSelect').value;
+            
+            // Wenn Vergleichsfenster offen ist, auch dort updaten
+            if (compareWindow && !compareWindow.closed) {
+                updateCompareWindow();
+            }
+        }
+        
+        function updateScreenshot() {
+            const screenshotImage = document.getElementById('screenshotImage');
+            
+            if (currentView === 'hhm') {
+                screenshotImage.src = '/images/hhm-einkommen-diwo.jpg';
+                screenshotImage.alt = 'Screenshot Haushaltsmitglieder/Einkommen';
+            } else {
+                screenshotImage.src = '/images/miete-diwo.jpg';
+                screenshotImage.alt = 'Screenshot Miete';
+            }
+        }
+        
+        function openCompareView() {
+            if (compareWindow && !compareWindow.closed) {
+                compareWindow.focus();
+                return;
+            }
+            
+            const url = getCompareUrl();
+            compareWindow = window.open(url, 'compareView', 'width=1400,height=900,scrollbars=yes,resizable=yes');
+            
+            if (compareWindow) {
+                compareWindow.focus();
+            }
+        }
+        
+        function updateCompareWindow() {
+            if (compareWindow && !compareWindow.closed) {
+                const url = getCompareUrl();
+                compareWindow.location.href = url;
+            }
+        }
+        
+        function getCompareUrl() {
+            const baseUrl = currentView === 'hhm' ? '/hhm-einkommen' : '/miete';
+            
+            // URL mit vorgeladenen JSON-Daten erstellen
+            const params = new URLSearchParams();
+            params.append('loadExample', 'true');
+            params.append('exampleType', currentExampleType);
+            params.append('validate', 'true');
+            params.append('kunde', 'Berlin');
+            
+            return `${baseUrl}?${params.toString()}`;
+        }
+        
+        // Initial setup
+        window.addEventListener('load', function() {
+            updateScreenshot();
+        });
+        
+        // Überprüfen, ob Popup-Fenster noch offen ist
+        setInterval(function() {
+            if (compareWindow && compareWindow.closed) {
+                compareWindow = null;
+            }
+        }, 1000);
+    </script>
+
+    <!-- Footer-Fragment einbinden -->
+    <div th:replace="~{fragments/footer :: footer}"></div>
+
+</body>
+</html>

+ 22 - 4
src/main/resources/templates/test.html

@@ -11,6 +11,12 @@
         <option value="miete">Miete</option>
       </select>
     </label>
+    <label>Beispieltyp: 
+      <select id="exampleTypeSelect">
+        <option value="realistic">Realistische Änderungen</option>
+        <option value="many">Viele Änderungen</option>
+      </select>
+    </label>
     <button type="button" onclick="loadExamples()">📄 Beispiel-JSONs laden</button>
     <button type="button" onclick="clearTextareas()">🗑️ Leeren</button>
   </div>
@@ -53,16 +59,28 @@
     async function loadExamples() {
       try {
         const schemaSelect = document.getElementById('schemaSelect');
+        const exampleTypeSelect = document.getElementById('exampleTypeSelect');
         const selectedSchema = schemaSelect.value;
+        const selectedType = exampleTypeSelect.value;
         
         let altFile, neuFile;
         
         if (selectedSchema === 'miete') {
-          altFile = '/example-miete-alt.json';
-          neuFile = '/example-miete-neu.json';
+          if (selectedType === 'many') {
+            altFile = '/example-miete-alt.json';
+            neuFile = '/example-miete-neu.json';
+          } else {
+            altFile = '/example-miete-realistic-alt.json';
+            neuFile = '/example-miete-realistic-neu.json';
+          }
         } else {
-          altFile = '/example-alt.json';
-          neuFile = '/example-neu.json';
+          if (selectedType === 'many') {
+            altFile = '/example-alt.json';
+            neuFile = '/example-neu.json';
+          } else {
+            altFile = '/example-realistic-alt.json';
+            neuFile = '/example-realistic-neu.json';
+          }
         }
         
         // Lade Alt-Beispiel

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác