diff --git a/Anlagentypen/Anlagentypen.xlsx b/Anlagentypen/Anlagentypen.xlsx index 823445d..35aaeb4 100644 Binary files a/Anlagentypen/Anlagentypen.xlsx and b/Anlagentypen/Anlagentypen.xlsx differ diff --git a/app.js b/app.js index 35dfddb..3562772 100644 --- a/app.js +++ b/app.js @@ -110,8 +110,7 @@ document.addEventListener('DOMContentLoaded', async () => { const btnDeleteWEA = document.getElementById('btnDeleteWEA'); const editNr = document.getElementById('edit-wea-nr'); - const editManufacturer = document.getElementById('edit-wea-manufacturer'); - const editType = document.getElementById('edit-wea-type'); + const editWeaSelector = document.getElementById('edit-wea-selector'); const editRd = document.getElementById('edit-wea-rd'); const editNh = document.getElementById('edit-wea-nh'); const editFr = document.getElementById('edit-wea-fr'); @@ -127,8 +126,7 @@ document.addEventListener('DOMContentLoaded', async () => { const inputRotor = document.getElementById('rotorDiameter'); const inputHub = document.getElementById('hubHeight'); const inputFoundation = document.getElementById('foundationRadius'); - const inputManufacturer = document.getElementById('turbineManufacturer'); - const inputType = document.getElementById('turbineType'); + const weaTypeSelector = document.getElementById('weaTypeSelector'); let placementMode = false; let measureMode = null; // 'dist' or 'area' @@ -291,8 +289,20 @@ document.addEventListener('DOMContentLoaded', async () => { } activeTurbine = turbine; editNr.value = turbine.nr; - editManufacturer.value = turbine.hersteller || 'Enercon'; - editType.value = turbine.type; + let matched = false; + for (const opt of editWeaSelector.options) { + if (opt.value) { + try { + const data = JSON.parse(opt.value); + if (data.hersteller === turbine.hersteller && data.anlagentyp === turbine.type && data.nabenhoehe === turbine.hh) { + editWeaSelector.value = opt.value; + matched = true; + break; + } + } catch(e) {} + } + } + if (!matched) editWeaSelector.value = ""; editRd.value = turbine.rd; editNh.value = turbine.hh; editFr.value = turbine.fr || 15; @@ -374,8 +384,15 @@ document.addEventListener('DOMContentLoaded', async () => { const rd = overrideData?.rd || Number.parseFloat(inputRotor?.value) || 160; const hh = overrideData?.hh || Number.parseFloat(inputHub?.value) || 165; const fr = overrideData?.fr || Number.parseFloat(inputFoundation?.value) || 15; - const type = overrideData?.type || inputType?.value || "Standard Typ"; - const hersteller = overrideData?.hersteller || inputManufacturer?.value || "Enercon"; + let type = overrideData?.type || "Standard Typ"; + let hersteller = overrideData?.hersteller || "Unbekannt"; + if (!overrideData && weaTypeSelector && weaTypeSelector.value) { + try { + const parsed = JSON.parse(weaTypeSelector.value); + type = parsed.anlagentyp; + hersteller = parsed.hersteller; + } catch(e) {} + } const weaNr = overrideData?.nr || loadedNr || (state.turbines.length + 1).toString(); const ksfAngle = overrideData?.ksfAngle || 0; const ksfMirrored = overrideData?.ksfMirrored || false; @@ -536,8 +553,15 @@ document.addEventListener('DOMContentLoaded', async () => { btnSaveEdit.onclick = () => { if (!activeTurbine) return; const newNr = editNr.value; - const newManufacturer = editManufacturer.value; - const newType = editType.value; + let newManufacturer = activeTurbine.hersteller; + let newType = activeTurbine.type; + if (editWeaSelector && editWeaSelector.value) { + try { + const parsed = JSON.parse(editWeaSelector.value); + newManufacturer = parsed.hersteller; + newType = parsed.anlagentyp; + } catch(e) {} + } const newRd = Number.parseFloat(editRd.value); const newNh = Number.parseFloat(editNh.value); const newFr = Number.parseFloat(editFr.value) || 15; @@ -2164,6 +2188,58 @@ document.addEventListener('DOMContentLoaded', async () => { } // Initialize allowed projects and project selector + window.availableWeaTypes = []; + + async function loadWeaTypes() { + try { + const res = await fetch('/api/wea-types'); + if (!res.ok) throw new Error('Network response was not ok'); + window.availableWeaTypes = await res.json(); + + // Build grouped options + const groups = {}; + window.availableWeaTypes.forEach(wea => { + if (!groups[wea.hersteller]) groups[wea.hersteller] = []; + groups[wea.hersteller].push(wea); + }); + + let html = ''; + for (const h in groups) { + html += ``; + groups[h].forEach(wea => { + const jsonStr = JSON.stringify(wea).replace(/"/g, '"'); + html += ``; + }); + html += ``; + } + + if (weaTypeSelector) { + weaTypeSelector.innerHTML = html; + weaTypeSelector.addEventListener('change', (e) => { + if (!e.target.value) return; + try { + const data = JSON.parse(e.target.value.replace(/"/g, '"')); + inputRotor.value = data.rotordurchmesser; + inputHub.value = data.nabenhoehe; + } catch(err) {} + }); + } + if (editWeaSelector) { + editWeaSelector.innerHTML = html; + editWeaSelector.addEventListener('change', (e) => { + if (!e.target.value) return; + try { + const data = JSON.parse(e.target.value.replace(/"/g, '"')); + editRd.value = data.rotordurchmesser; + editNh.value = data.nabenhoehe; + } catch(err) {} + }); + } + } catch (err) { + console.error('Fehler beim Laden der Anlagentypen:', err); + } + } + async function initializeProjects() { const statusEl = document.getElementById('statusInfo'); try { @@ -2258,6 +2334,7 @@ document.addEventListener('DOMContentLoaded', async () => { } // Start loading process + await loadWeaTypes(); initializeProjects(); // Project Persistence diff --git a/append_pdf.js b/append_pdf.js new file mode 100644 index 0000000..56ed14e --- /dev/null +++ b/append_pdf.js @@ -0,0 +1,97 @@ +const fs = require('fs'); +const js = ` + // --- PDF Export Logic --- + const btnExportPDF = document.getElementById('btnExportPDF'); + if (btnExportPDF) { + btnExportPDF.addEventListener('click', async () => { + const originalText = btnExportPDF.innerText; + btnExportPDF.innerText = 'Exportiere...'; + btnExportPDF.disabled = true; + + try { + if (typeof html2canvas === 'undefined' || typeof jspdf === 'undefined') { + throw new Error('PDF Bibliotheken (html2canvas, jspdf) sind noch nicht geladen.'); + } + + const mapContainer = document.getElementById('map'); + + // Add Overlay + const exportOverlay = document.createElement('div'); + exportOverlay.style.position = 'absolute'; + exportOverlay.style.bottom = '30px'; + exportOverlay.style.left = '30px'; + exportOverlay.style.zIndex = '9999'; + exportOverlay.style.background = 'rgba(255, 255, 255, 0.95)'; + exportOverlay.style.padding = '15px'; + exportOverlay.style.border = '2px solid #333'; + exportOverlay.style.borderRadius = '5px'; + exportOverlay.style.color = '#333'; + exportOverlay.style.fontFamily = 'Arial, sans-serif'; + exportOverlay.style.boxShadow = '0 0 10px rgba(0,0,0,0.3)'; + + const projName = document.getElementById('projectSelector')?.options[document.getElementById('projectSelector')?.selectedIndex]?.text || 'Unbekannt'; + + exportOverlay.innerHTML = \` +
ENWELO Standortplanung
+
Projekt: \${projName}
+
+
Rotorüberstreichfläche
+
Gebietsumring
+
Abstandslinien
+
WEA Standort
+
+ \`; + mapContainer.appendChild(exportOverlay); + + // Wait a tiny bit for DOM to render overlay + await new Promise(r => setTimeout(r, 100)); + + const canvas = await html2canvas(mapContainer, { + useCORS: true, + allowTaint: true, + ignoreElements: (element) => { + return element.classList.contains('leaflet-control-zoom'); + } + }); + + mapContainer.removeChild(exportOverlay); + + const imgData = canvas.toDataURL('image/png'); + const pdf = new jspdf.jsPDF({ + orientation: 'landscape', + unit: 'mm', + format: 'a3' + }); + + const pdfWidth = pdf.internal.pageSize.getWidth(); + const pdfHeight = pdf.internal.pageSize.getHeight(); + + const imgProps = pdf.getImageProperties(imgData); + const ratio = imgProps.width / imgProps.height; + + let renderWidth = pdfWidth; + let renderHeight = pdfWidth / ratio; + + if (renderHeight > pdfHeight) { + renderHeight = pdfHeight; + renderWidth = pdfHeight * ratio; + } + + // Center image in PDF + const xOffset = (pdfWidth - renderWidth) / 2; + const yOffset = (pdfHeight - renderHeight) / 2; + + pdf.addImage(imgData, 'PNG', xOffset, yOffset, renderWidth, renderHeight); + pdf.save('Karte_Enwelo.pdf'); + + } catch (err) { + console.error('Fehler beim PDF Export:', err); + alert('Fehler beim PDF Export: ' + err.message); + } finally { + btnExportPDF.innerText = originalText; + btnExportPDF.disabled = false; + } + }); + } +`; +fs.appendFileSync('app.js', js); diff --git a/db_add_column.js b/db_add_column.js new file mode 100644 index 0000000..ecef006 --- /dev/null +++ b/db_add_column.js @@ -0,0 +1,30 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + await pool.query('ALTER TABLE geodaten."potentialflächen_wind" ADD COLUMN IF NOT EXISTS projekt_id VARCHAR(255);'); + console.log('Column projekt_id added successfully.'); + // Set for samern-ohne as default since they want to see it! + // But wait, what if there's only one row? + const res = await pool.query('SELECT id FROM geodaten."potentialflächen_wind"'); + console.log('Found rows:', res.rowCount); + if (res.rowCount === 1) { + await pool.query("UPDATE geodaten.\"potentialflächen_wind\" SET projekt_id = 'projekt_bw_samern-ohne'"); + console.log('Updated the single row to projekt_bw_samern-ohne'); + } + } catch(e) { + console.error('Fehler:', e); + } finally { + await pool.end(); + } +} +run(); diff --git a/db_add_planungsstand.js b/db_add_planungsstand.js new file mode 100644 index 0000000..735d95d --- /dev/null +++ b/db_add_planungsstand.js @@ -0,0 +1,25 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + await pool.query('ALTER TABLE geodaten."potentialflächen_wind" ADD COLUMN IF NOT EXISTS planungsstand VARCHAR(255);'); + console.log('Column planungsstand added successfully.'); + + const res = await pool.query("UPDATE geodaten.\"potentialflächen_wind\" SET planungsstand = 'rechtsverbindlich'"); + console.log(`Updated ${res.rowCount} rows to rechtsverbindlich`); + } catch(e) { + console.error('Fehler:', e); + } finally { + await pool.end(); + } +} +run(); diff --git a/db_check_potential.js b/db_check_potential.js new file mode 100644 index 0000000..da4243f --- /dev/null +++ b/db_check_potential.js @@ -0,0 +1,31 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + const res = await pool.query("SELECT column_name, data_type FROM information_schema.columns WHERE table_schema = 'geodaten' AND table_name = 'potentialflächen_wind';"); + console.log('Columns:', res.rows); + + // Check if projekt_id exists in columns + const hasProjektId = res.rows.some(r => r.column_name === 'projekt_id'); + if (hasProjektId) { + const dataRes = await pool.query('SELECT DISTINCT projekt_id FROM geodaten."potentialflächen_wind";'); + console.log('Projects:', dataRes.rows); + } else { + console.log('No projekt_id column found.'); + } + } catch(e) { + console.error('Fehler:', e); + } finally { + await pool.end(); + } +} +run(); diff --git a/db_update_artennachweise.js b/db_update_artennachweise.js new file mode 100644 index 0000000..e23221e --- /dev/null +++ b/db_update_artennachweise.js @@ -0,0 +1,40 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + const client = await pool.connect(); + await client.query('BEGIN'); + + // Update artennachweise + let res = await client.query("UPDATE geodaten.artennachweise SET projekt_id = 'trasse_bw_scheddebrock' WHERE projekt_id = 'BW Scheddebrock'"); + console.log('Artennachweise (trasse_bw_scheddebrock):', res.rowCount); + + res = await client.query("UPDATE geodaten.artennachweise SET projekt_id = 'projekt_bw_samern-ohne' WHERE projekt_id = 'bw_samern-ohne'"); + console.log('Artennachweise (projekt_bw_samern-ohne):', res.rowCount); + + res = await client.query("UPDATE geodaten.artennachweise SET projekt_id = 'projekt_bw_test' WHERE projekt_id = 'test'"); + console.log('Artennachweise (projekt_bw_test):', res.rowCount); + + res = await client.query("UPDATE geodaten.artennachweise SET projekt_id = 'projekt_bw_an_der_landwehr' WHERE projekt_id ILIKE '%landwehr%'"); + console.log('Artennachweise (projekt_bw_an_der_landwehr):', res.rowCount); + + await client.query('COMMIT'); + console.log('--- ERFOLGREICH GESPEICHERT ---'); + client.release(); + } catch(e) { + await pool.query('ROLLBACK'); + console.error('Fehler:', e); + } finally { + await pool.end(); + } +} +run(); diff --git a/db_update_temp.js b/db_update_temp.js new file mode 100644 index 0000000..1079a9e --- /dev/null +++ b/db_update_temp.js @@ -0,0 +1,54 @@ +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + const client = await pool.connect(); + + await client.query('BEGIN'); + + // 1. Projekte + let res = await client.query("UPDATE geodaten.projekte SET name = 'trasse_bw_scheddebrock' WHERE name = 'BW Scheddebrock'"); + console.log('Projekte (trasse_bw_scheddebrock):', res.rowCount); + + res = await client.query("UPDATE geodaten.projekte SET name = 'projekt_bw_samern-ohne' WHERE name = 'bw_samern-ohne'"); + console.log('Projekte (projekt_bw_samern-ohne):', res.rowCount); + + res = await client.query("UPDATE geodaten.projekte SET name = 'projekt_bw_test' WHERE name = 'test'"); + console.log('Projekte (projekt_bw_test):', res.rowCount); + + res = await client.query("UPDATE geodaten.projekte SET name = 'projekt_bw_an_der_landwehr' WHERE name ILIKE '%landwehr%'"); + console.log('Projekte (projekt_bw_an_der_landwehr):', res.rowCount); + + // 2. WEA Standorte + res = await client.query("UPDATE geodaten.wea_standorte SET projekt_id = 'trasse_bw_scheddebrock' WHERE projekt_id = 'BW Scheddebrock'"); + console.log('WEA (trasse_bw_scheddebrock):', res.rowCount); + + res = await client.query("UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_samern-ohne' WHERE projekt_id = 'bw_samern-ohne'"); + console.log('WEA (projekt_bw_samern-ohne):', res.rowCount); + + res = await client.query("UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_test' WHERE projekt_id = 'test'"); + console.log('WEA (projekt_bw_test):', res.rowCount); + + res = await client.query("UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_an_der_landwehr' WHERE projekt_id ILIKE '%landwehr%'"); + console.log('WEA (projekt_bw_an_der_landwehr):', res.rowCount); + + await client.query('COMMIT'); + console.log('--- ERFOLGREICH GESPEICHERT ---'); + client.release(); + } catch(e) { + await pool.query('ROLLBACK'); + console.error('Fehler:', e); + } finally { + await pool.end(); + } +} +run(); diff --git a/enwelo_db.session.sql b/enwelo_db.session.sql index e69de29..e9267cb 100644 --- a/enwelo_db.session.sql +++ b/enwelo_db.session.sql @@ -0,0 +1,11 @@ +-- 1. Aktualisieren der Haupttabelle "projekte" +UPDATE geodaten.projekte SET name = 'trasse_bw_scheddebrock' WHERE name = 'BW Scheddebrock'; +UPDATE geodaten.projekte SET name = 'projekt_bw_samern-ohne' WHERE name = 'bw_samern-ohne'; +UPDATE geodaten.projekte SET name = 'projekt_bw_test' WHERE name = 'test'; +UPDATE geodaten.projekte SET name = 'projekt_bw_an_der_landwehr' WHERE name ILIKE '%landwehr%'; + +-- 2. Aktualisieren der Verknüpfungen in den Standorten (WEA) +UPDATE geodaten.wea_standorte SET projekt_id = 'trasse_bw_scheddebrock' WHERE projekt_id = 'BW Scheddebrock'; +UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_samern-ohne' WHERE projekt_id = 'bw_samern-ohne'; +UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_test' WHERE projekt_id = 'test'; +UPDATE geodaten.wea_standorte SET projekt_id = 'projekt_bw_an_der_landwehr' WHERE projekt_id ILIKE '%landwehr%'; diff --git a/import_umring.js b/import_umring.js new file mode 100644 index 0000000..22c0af0 --- /dev/null +++ b/import_umring.js @@ -0,0 +1,61 @@ +const shapefile = require('shapefile'); +const { Pool } = require('pg'); + +const pool = new Pool({ + user: 'enwelo_admin', + host: '87.106.21.21', + database: 'enwelo', + password: 'WX1t1cgP1qK09', + port: 5432, + ssl: false +}); + +async function run() { + try { + console.log("Reading shapefile..."); + const geojson = await shapefile.read("Shapefile/Windeignungsgebiet.shp", "Shapefile/Windeignungsgebiet.dbf"); + console.log(`Loaded ${geojson.features.length} features.`); + + if (geojson.features.length === 0) { + console.log("No features found!"); + return; + } + + const client = await pool.connect(); + try { + await client.query('BEGIN'); + + // wir wollen die Shapefile-Geometrie für samern-ohne in die DB pushen + const projektId = 'projekt_bw_samern-ohne'; + + // Zuerst bestehende löschen? + await client.query('DELETE FROM geodaten."potentialflächen_wind" WHERE projekt_id = $1', [projektId]); + + let count = 0; + for (const feature of geojson.features) { + const geomJson = JSON.stringify(feature.geometry); + + await client.query( + `INSERT INTO geodaten."potentialflächen_wind" (projekt_id, geom) + VALUES ($1, ST_SetSRID(ST_GeomFromGeoJSON($2), 25832))`, + [projektId, geomJson] + ); + count++; + } + + await client.query('COMMIT'); + console.log(`Erfolgreich ${count} Potentialflächen für ${projektId} importiert!`); + } catch (e) { + await client.query('ROLLBACK'); + throw e; + } finally { + client.release(); + } + } catch(e) { + console.error("Fehler:", e); + } finally { + await pool.end(); + } +} + +run(); diff --git a/import_wea.js b/import_wea.js new file mode 100644 index 0000000..c8af5dc --- /dev/null +++ b/import_wea.js @@ -0,0 +1,64 @@ +require('dotenv').config({ override: true }); +const { Pool } = require('pg'); +const xlsx = require('xlsx'); + +const pool = new Pool({ + host: process.env.DB_HOST, + port: process.env.DB_PORT, + database: process.env.DB_NAME, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD +}); + +async function importWea() { + const wb = xlsx.readFile('./Anlagentypen/Anlagentypen.xlsx'); + const sheet = wb.Sheets[wb.SheetNames[0]]; + const data = xlsx.utils.sheet_to_json(sheet); + + try { + console.log('Connecting to DB...'); + await pool.query('BEGIN'); + + console.log('Dropping and creating table geodaten.anlagendaten_wea...'); + await pool.query(` + DROP TABLE IF EXISTS geodaten.anlagendaten_wea; + CREATE TABLE geodaten.anlagendaten_wea ( + id SERIAL PRIMARY KEY, + hersteller VARCHAR(255), + anlagentyp VARCHAR(255), + nennleistung FLOAT, + nabenhoehe FLOAT, + rotordurchmesser FLOAT, + gesamthoehe FLOAT + ); + `); + + console.log(`Importing ${data.length} rows...`); + for (const row of data) { + // Keys from Excel + // "Hersteller", "Anlagentyp", "Nennleistung (MW)", "Nabenhöhe (m)", "Rotordurchmesser (m)", "Gesamthöhe (m)" + const hersteller = row['Hersteller'] || ''; + const anlagentyp = row['Anlagentyp'] || ''; + const nennleistung = parseFloat(row['Nennleistung (MW)'] || 0); + const nabenhoehe = parseFloat(row['Nabenhöhe (m)'] || 0); + const rotordurchmesser = parseFloat(row['Rotordurchmesser (m)'] || 0); + const gesamthoehe = parseFloat(row['Gesamthöhe (m)'] || 0); + + await pool.query(` + INSERT INTO geodaten.anlagendaten_wea + (hersteller, anlagentyp, nennleistung, nabenhoehe, rotordurchmesser, gesamthoehe) + VALUES ($1, $2, $3, $4, $5, $6) + `, [hersteller, anlagentyp, nennleistung, nabenhoehe, rotordurchmesser, gesamthoehe]); + } + + await pool.query('COMMIT'); + console.log('Import finished successfully.'); + } catch (err) { + await pool.query('ROLLBACK'); + console.error('Error importing:', err); + } finally { + await pool.end(); + } +} + +importWea(); diff --git a/index.html b/index.html index bdf7e09..0a84af1 100644 --- a/index.html +++ b/index.html @@ -74,28 +74,19 @@ WEA Konfiguration +
-
-
- - -
-
- - -
+
+ +
- - + +
- - + +
@@ -180,26 +171,19 @@
-
- - +
-
- - -
- +
- +
diff --git a/package-lock.json b/package-lock.json index d235529..9d7c2b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "dotenv": "^16.4.5", "express": "^4.19.2", "pg": "^8.11.5", - "shapefile": "^0.6.6" + "shapefile": "^0.6.6", + "xlsx": "^0.18.5" } }, "node_modules/accepts": { @@ -29,6 +30,15 @@ "node": ">= 0.6" } }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -103,6 +113,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -162,6 +194,18 @@ "url": "https://opencollective.com/express" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -358,6 +402,15 @@ "node": ">= 0.6" } }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -1001,6 +1054,18 @@ "node": ">= 10.x" } }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -1072,6 +1137,45 @@ "node": ">= 0.8" } }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 00c2005..2e8b6d2 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "dotenv": "^16.4.5", "express": "^4.19.2", "pg": "^8.11.5", - "shapefile": "^0.6.6" + "shapefile": "^0.6.6", + "xlsx": "^0.18.5" }, "scripts": { "start": "node server.js" diff --git a/read_excel.js b/read_excel.js new file mode 100644 index 0000000..b8ccce4 --- /dev/null +++ b/read_excel.js @@ -0,0 +1,7 @@ +const xlsx = require('xlsx'); +const wb = xlsx.readFile('./Anlagentypen/Anlagentypen.xlsx'); +const sheetName = wb.SheetNames[0]; +const sheet = wb.Sheets[sheetName]; +const data = xlsx.utils.sheet_to_json(sheet); +console.log('Columns:', Object.keys(data[0] || {})); +console.log('Sample Data:', data.slice(0, 3)); diff --git a/server.js b/server.js index 251e32c..0df1436 100644 --- a/server.js +++ b/server.js @@ -215,6 +215,20 @@ app.get('/api/logs', (req, res) => { res.type('text/plain').send(serverLogs.join('\n')); }); +// API to load available WEA types +app.get('/api/wea-types', async (req, res) => { + const client = await pool.connect(); + try { + const result = await client.query('SELECT * FROM geodaten.anlagendaten_wea ORDER BY hersteller, anlagentyp, nabenhoehe'); + res.status(200).json(result.rows); + } catch (e) { + log(`FEHLER beim Laden der Anlagentypen: ${e.message}`); + res.status(500).json({ error: e.message }); + } finally { + client.release(); + } +}); + // API to save turbines app.post('/api/wea', async (req, res) => { const { projekt_id, turbines } = req.body;