From 2d3e0708302c3b831eafb93265e2cebc11c4ffd2 Mon Sep 17 00:00:00 2001 From: ISA Date: Fri, 11 Jul 2025 11:50:15 +0200 Subject: [PATCH] =?UTF-8?q?feat(api):=20Zeitraum=20und=20Eingang=20als=20P?= =?UTF-8?q?flichtparameter=20f=C3=BCr=20AnalogInputs-API=20eingef=C3=BChrt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API-Handler für /api/cpl/getAnalogInputsHistory überarbeitet - `zeitraum` (DIA0, DIA1, DIA2) und `eingang` (1–8) sind jetzt Pflichtfelder - Bei fehlenden oder ungültigen Parametern strukturierte Fehlerantwort mit Beispielen - Daten werden nun gezielt pro Eingang und Zeitraum geladen (z. B. AE3 + DIA1) - Bessere Fehlerbehandlung bei nicht vorhandenen Dateien --- .env.development | 2 +- .env.production | 2 +- CHANGELOG.md | 32 +++++++ package-lock.json | 4 +- package.json | 2 +- pages/api/cpl/getAnalogInputsHistory.ts | 92 +++++++++++++------ redux/slices/analogInputsChartSlice.ts | 40 ++++++++ redux/thunks/getAnalogInputsChartDataThunk.ts | 20 ++++ 8 files changed, 160 insertions(+), 34 deletions(-) create mode 100644 redux/slices/analogInputsChartSlice.ts create mode 100644 redux/thunks/getAnalogInputsChartDataThunk.ts diff --git a/.env.development b/.env.development index 482c21e..689bea5 100644 --- a/.env.development +++ b/.env.development @@ -6,6 +6,6 @@ NEXT_PUBLIC_USE_MOCK_BACKEND_LOOP_START=false NEXT_PUBLIC_EXPORT_STATIC=false NEXT_PUBLIC_USE_CGI=false # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.589 +NEXT_PUBLIC_APP_VERSION=1.6.593 NEXT_PUBLIC_CPL_MODE=json # json (Entwicklungsumgebung) oder jsSimulatedProd (CPL ->CGI-Interface-Simulator) oder production (CPL-> CGI-Interface Platzhalter) diff --git a/.env.production b/.env.production index b603bfe..e43dea8 100644 --- a/.env.production +++ b/.env.production @@ -5,5 +5,5 @@ NEXT_PUBLIC_CPL_API_PATH=/CPL NEXT_PUBLIC_EXPORT_STATIC=true NEXT_PUBLIC_USE_CGI=true # App-Versionsnummer -NEXT_PUBLIC_APP_VERSION=1.6.589 +NEXT_PUBLIC_APP_VERSION=1.6.593 NEXT_PUBLIC_CPL_MODE=production \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d00c22..6a6be4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +## [1.6.593] – 2025-07-11 + +- fix: Von/Bis-Datum beim Schließen des DetailModals zurücksetzen + +- Redux-State für vonDatum und bisDatum wird bei handleClose geleert +- verhindert unerwünschtes Vorfiltern bei erneutem Öffnen des Modals + +--- +## [1.6.592] – 2025-07-11 + +- fix: Von/Bis-Datum beim Schließen des DetailModals zurücksetzen + +- Redux-State für vonDatum und bisDatum wird bei handleClose geleert +- verhindert unerwünschtes Vorfiltern bei erneutem Öffnen des Modals + +--- +## [1.6.591] – 2025-07-11 + +- fix: Von/Bis-Datum beim Schließen des DetailModals zurücksetzen + +- Redux-State für vonDatum und bisDatum wird bei handleClose geleert +- verhindert unerwünschtes Vorfiltern bei erneutem Öffnen des Modals + +--- +## [1.6.590] – 2025-07-11 + +- fix: Von/Bis-Datum beim Schließen des DetailModals zurücksetzen + +- Redux-State für vonDatum und bisDatum wird bei handleClose geleert +- verhindert unerwünschtes Vorfiltern bei erneutem Öffnen des Modals + +--- ## [1.6.589] – 2025-07-11 - feat: Zeitspanne-Funktion mit Von/Bis und Button-Trigger im DetailModal eingebaut diff --git a/package-lock.json b/package-lock.json index 390da44..d127405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cpl-v4", - "version": "1.6.589", + "version": "1.6.593", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cpl-v4", - "version": "1.6.589", + "version": "1.6.593", "dependencies": { "@fontsource/roboto": "^5.1.0", "@headlessui/react": "^2.2.4", diff --git a/package.json b/package.json index b5b9d53..661ea24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cpl-v4", - "version": "1.6.589", + "version": "1.6.593", "private": true, "scripts": { "dev": "next dev", diff --git a/pages/api/cpl/getAnalogInputsHistory.ts b/pages/api/cpl/getAnalogInputsHistory.ts index ab1cf2b..bd75b7e 100644 --- a/pages/api/cpl/getAnalogInputsHistory.ts +++ b/pages/api/cpl/getAnalogInputsHistory.ts @@ -1,43 +1,77 @@ // /pages/api/cpl/getAnalogInputsHistory.ts - import path from "path"; import fs from "fs/promises"; import type { NextApiRequest, NextApiResponse } from "next"; +const erlaubteZeitraeume = ["DIA0", "DIA1", "DIA2"]; +const erlaubteEingaenge = [1, 2, 3, 4, 5, 6, 7, 8]; + export default async function handler( req: NextApiRequest, - res: NextApiResponse + res: NextApiResponse ) { + const { zeitraum, eingang } = req.query; + + const zeitraumKey = + typeof zeitraum === "string" && erlaubteZeitraeume.includes(zeitraum) + ? zeitraum + : null; + + const eingangId = + typeof eingang === "string" && !isNaN(Number(eingang)) + ? Number(eingang) + : null; + + // ❌ Fehlerhafte Anfrage + if (!zeitraumKey || !eingangId || !erlaubteEingaenge.includes(eingangId)) { + return res.status(400).json({ + error: "❌ Ungültige oder unvollständige Anfrage.", + erwartet: { + zeitraum: "Pflichtfeld. Erlaubt: DIA0 | DIA1 | DIA2", + eingang: "Pflichtfeld. Erlaubt: 1 bis 8 (entspricht AE1 bis AE8)", + }, + beispiele: [ + "/api/cpl/getAnalogInputsHistory?zeitraum=DIA1&eingang=3", + "/api/cpl/getAnalogInputsHistory?zeitraum=DIA2&eingang=7", + "http://localhost:3000/api/cpl/getAnalogInputsHistory?eingang=1&zeitraum=DIA0", + ], + hinweis: + "Die Antwort enthält ein Array mit Messwertobjekten für den gewählten Eingang und Zeitraum.", + }); + } + try { - const result: Record = {}; + const filePath = path.join( + process.cwd(), + "mocks", + "device-cgi-simulator", + "chartsData", + "analogInputs", + `${eingangId}`, + `${zeitraumKey}.json` + ); - for (let i = 1; i <= 8; i++) { - const filePath = path.join( - process.cwd(), - "mocks", - "device-cgi-simulator", - "chartsData", - "analogInputs", - `${i}`, - `DIA0.json` - ); - console.log(`Lade Mock-Daten für analogInput${i} von: ${filePath}`); + const fileContent = await fs.readFile(filePath, "utf-8"); + const daten = JSON.parse(fileContent); - try { - const fileContent = await fs.readFile(filePath, "utf-8"); - result[99 + i] = JSON.parse(fileContent); // z. B. 100 für AE1, 101 für AE2 - } catch (error) { - console.warn( - `Mock-Datei für analogInput${i} nicht gefunden oder fehlerhaft.`, - error - ); - result[99 + i] = []; - } - } - - res.status(200).json(result); + res.status(200).json({ + eingang: eingangId, + zeitraum: zeitraumKey, + beschreibung: + zeitraumKey === "DIA0" + ? "Alle Messwerte" + : zeitraumKey === "DIA1" + ? "Stündlich aggregierte Messwerte" + : "Täglich aggregierte Messwerte", + daten, + }); } catch (error) { - console.error("Fehler beim Laden der analogen Eingänge (Mock):", error); - res.status(500).json({ error: "Fehler beim Laden der Mock-Daten." }); + console.error( + `❌ Datei nicht gefunden für Eingang ${eingangId} und Zeitraum ${zeitraumKey}:`, + error + ); + res.status(404).json({ + error: `Keine Daten gefunden für Eingang ${eingangId} mit Zeitraum ${zeitraumKey}.`, + }); } } diff --git a/redux/slices/analogInputsChartSlice.ts b/redux/slices/analogInputsChartSlice.ts new file mode 100644 index 0000000..8270e5d --- /dev/null +++ b/redux/slices/analogInputsChartSlice.ts @@ -0,0 +1,40 @@ +import { createSlice, PayloadAction } from "@reduxjs/toolkit"; + +export type Zeitraum = "DIA0" | "DIA1" | "DIA2"; + +interface ChartState { + zeitraum: Zeitraum; + vonDatum: string; + bisDatum: string; + isLoading: boolean; +} + +const initialState: ChartState = { + zeitraum: "DIA0", + vonDatum: "", + bisDatum: "", + isLoading: false, +}; + +const analogInputsChartSlice = createSlice({ + name: "analogInputsChart", + initialState, + reducers: { + setZeitraum: (state, action: PayloadAction) => { + state.zeitraum = action.payload; + }, + setVonDatum: (state, action: PayloadAction) => { + state.vonDatum = action.payload; + }, + setBisDatum: (state, action: PayloadAction) => { + state.bisDatum = action.payload; + }, + setIsLoading: (state, action: PayloadAction) => { + state.isLoading = action.payload; + }, + }, +}); + +export const { setZeitraum, setVonDatum, setBisDatum, setIsLoading } = + analogInputsChartSlice.actions; +export default analogInputsChartSlice.reducer; diff --git a/redux/thunks/getAnalogInputsChartDataThunk.ts b/redux/thunks/getAnalogInputsChartDataThunk.ts new file mode 100644 index 0000000..8f9c115 --- /dev/null +++ b/redux/thunks/getAnalogInputsChartDataThunk.ts @@ -0,0 +1,20 @@ +import { createAsyncThunk } from "@reduxjs/toolkit"; +import { RootState } from "@/redux/store"; +import { Zeitraum } from "@/redux/slices/analogInputsChartSlice"; + +export const getAnalogInputsChartDataThunk = createAsyncThunk( + "analogInputsChart/fetchChartData", + async (_, { getState }) => { + const state = getState() as RootState; + const { zeitraum, vonDatum, bisDatum } = state.analogInputsChart; + const selectedInput = state.selectedAnalogInput; + + if (!selectedInput) return []; + + const res = await fetch( + `/api/cpl/getAnalogInputsHistory?inputId=${selectedInput.id}&zeitraum=${zeitraum}&von=${vonDatum}&bis=${bisDatum}` + ); + const data = await res.json(); + return data; + } +);