Compare commits
2 Commits
5682c076c1
...
2b1eefe229
| Author | SHA1 | Date |
|---|---|---|
|
|
2b1eefe229 | |
|
|
4107a62167 |
|
|
@ -0,0 +1,12 @@
|
||||||
|
node_modules/
|
||||||
|
.env
|
||||||
|
backend/node_modules/
|
||||||
|
backend/check_db.py
|
||||||
|
backend/check_db.js
|
||||||
|
backend/check_db2.js
|
||||||
|
backend/check_db_admin.js
|
||||||
|
backend/list_tables.js
|
||||||
|
backend/check_columns.js
|
||||||
|
backend/setup_db.py
|
||||||
|
.vscode/
|
||||||
|
*.log
|
||||||
38
app.js
38
app.js
|
|
@ -1414,9 +1414,45 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
a.download = `WindPlan_Projekt_${new Date().toLocaleDateString()}.json`;
|
a.download = `WindPlan_Projekt_${new Date().toLocaleDateString()}.json`;
|
||||||
a.click();
|
a.click();
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
document.getElementById('statusInfo').innerText = "Projekt exportiert.";
|
document.getElementById('statusInfo').innerText = "Projekt lokal exportiert.";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const btnSaveDB = document.getElementById('btnSaveDB');
|
||||||
|
if (btnSaveDB) {
|
||||||
|
btnSaveDB.addEventListener('click', async () => {
|
||||||
|
const statusEl = document.getElementById('statusInfo');
|
||||||
|
statusEl.innerText = "Speichere in Datenbank...";
|
||||||
|
|
||||||
|
const project_id = "BWSamern-Ohne"; // Could be dynamic from config
|
||||||
|
const turbineData = state.turbines.map(t => ({
|
||||||
|
nr: t.nr,
|
||||||
|
variant: t.variant,
|
||||||
|
type: t.type,
|
||||||
|
rd: t.rd,
|
||||||
|
hh: t.hh,
|
||||||
|
latlng: t.layers.marker.getLatLng()
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/wea', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ projekt_id, turbines: turbineData })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const result = await response.json();
|
||||||
|
statusEl.innerHTML = `<span style="color: #2ecc71;">${result.message}</span>`;
|
||||||
|
} else {
|
||||||
|
throw new Error("Fehler beim Speichern in DB");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
statusEl.innerHTML = `<span style="color: #ff4444;">Fehler beim DB-Sync: ${err.message}</span>`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
btnLoad.addEventListener('click', () => projectInput.click());
|
btnLoad.addEventListener('click', () => projectInput.click());
|
||||||
|
|
||||||
projectInput.addEventListener('change', (e) => {
|
projectInput.addEventListener('change', (e) => {
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,9 @@
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h2>Projektverwaltung</h2>
|
<h2>Projektverwaltung</h2>
|
||||||
<button class="btn-secondary" id="btnSaveProject">Projekt speichern</button>
|
<button class="btn-secondary" id="btnSaveProject">Projekt speichern (Lokal)</button>
|
||||||
<button class="btn-secondary" id="btnLoadProject">Projekt laden</button>
|
<button class="btn-primary" id="btnSaveDB">In Datenbank speichern</button>
|
||||||
|
<button class="btn-secondary" id="btnLoadProject">Projekt laden (Lokal)</button>
|
||||||
<input type="file" id="projectInput" style="display: none;" accept=".json">
|
<input type="file" id="projectInput" style="display: none;" accept=".json">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "bwsamern-ohne-planungstool",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "server.js",
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.20.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"pg": "^8.11.5"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "node server.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
require('dotenv').config();
|
||||||
|
const express = require('express');
|
||||||
|
const { Pool } = require('pg');
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const cors = require('cors');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
|
// Serve static files from the root directory
|
||||||
|
app.use(express.static(path.join(__dirname, './')));
|
||||||
|
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test DB Connection
|
||||||
|
pool.connect()
|
||||||
|
.then(() => console.log('Connected to PostgreSQL successfully'))
|
||||||
|
.catch(err => console.error('Connection error', err.stack));
|
||||||
|
|
||||||
|
// API to save turbines
|
||||||
|
app.post('/api/wea', async (req, res) => {
|
||||||
|
const { projekt_id, turbines } = req.body;
|
||||||
|
const client = await pool.connect();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await client.query('BEGIN');
|
||||||
|
|
||||||
|
// Delete existing turbines for this project before saving new state
|
||||||
|
await client.query('DELETE FROM geodaten.wea_standorte WHERE projekt_id = $1', [projekt_id]);
|
||||||
|
|
||||||
|
for(let t of turbines) {
|
||||||
|
await client.query(
|
||||||
|
`INSERT INTO geodaten.wea_standorte (
|
||||||
|
wea_nummer, hersteller, anlagentyp, nabenhoehe, rotordurchmesser, ksf_drehung, projekt_id, geom
|
||||||
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, ST_SetSRID(ST_MakePoint($8, $9), 4326))`,
|
||||||
|
[
|
||||||
|
t.nr,
|
||||||
|
t.hersteller || '',
|
||||||
|
t.type,
|
||||||
|
parseInt(t.hh),
|
||||||
|
parseInt(t.rd),
|
||||||
|
parseInt(t.ksfAngle || 0),
|
||||||
|
projekt_id,
|
||||||
|
t.latlng.lng,
|
||||||
|
t.latlng.lat
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.query('COMMIT');
|
||||||
|
res.status(200).json({ message: 'Windenergieanlagen erfolgreich in Datenbank gespeichert' });
|
||||||
|
} catch (e) {
|
||||||
|
await client.query('ROLLBACK');
|
||||||
|
console.error('Error saving turbines', e);
|
||||||
|
res.status(500).json({ error: e.message });
|
||||||
|
} finally {
|
||||||
|
client.release();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// API to load turbines
|
||||||
|
app.get('/api/wea/:projekt_id', async (req, res) => {
|
||||||
|
const { projekt_id } = req.params;
|
||||||
|
try {
|
||||||
|
const result = await pool.query(
|
||||||
|
`SELECT wea_nummer as nr, anlagentyp as type, nabenhoehe as hh, rotordurchmesser as rd, ksf_drehung as ksfAngle,
|
||||||
|
ST_X(geom) as lng, ST_Y(geom) as lat
|
||||||
|
FROM geodaten.wea_standorte WHERE projekt_id = $1`,
|
||||||
|
[projekt_id]
|
||||||
|
);
|
||||||
|
res.status(200).json(result.rows);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error loading turbines', e);
|
||||||
|
res.status(500).json({ error: e.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Catch-all route to serve index.html for any other request (optional, good for SPAs)
|
||||||
|
app.get('*', (req, res) => {
|
||||||
|
res.sendFile(path.join(__dirname, 'index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, '0.0.0.0', () => {
|
||||||
|
console.log(`Server running at http://0.0.0.0:${port}`);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue