chore: km_berechnen Tool (BEO-Entfernungen/Fahrkosten-Recherche) hinzugefügt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-10 15:45:37 +02:00
parent 982ada5172
commit 48aaf82899
6 changed files with 523 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
// Erzeugt eine PDF-Tabelle aller BEOs mit Wohnort und Straßenentfernung (km)
// zur Sternwarte Welzheim — zum Versand an die BEOs zur Verifizierung.
//
// Daten kommen über den PHP-Proxy (cmd GET_BEOS). Das HTML wird mit Headless-
// Chrome nach PDF gerendert.
// node --env-file=.env erzeuge-pdf.mjs
//
// Ergebnis: beo-entfernungen.html und beo-entfernungen.pdf
import { writeFile } from 'node:fs/promises';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const execFileP = promisify(execFile);
const __dirname = dirname(fileURLToPath(import.meta.url));
const HTML_FILE = join(__dirname, 'beo-entfernungen.html');
const PDF_FILE = join(__dirname, 'beo-entfernungen.pdf');
const PHP_DB_URL = process.env.PHP_DB_URL || 'http://localhost:8080/DB4js_all.php';
const CHROME = process.env.CHROME_PATH ||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
async function callProxy(cmd, params = {}) {
const headers = { 'Content-Type': 'application/json' };
if (process.env.API_USER && process.env.API_PASS) {
const token = Buffer.from(`${process.env.API_USER}:${process.env.API_PASS}`).toString('base64');
headers.Authorization = `Basic ${token}`;
}
const res = await fetch(PHP_DB_URL, {
method: 'POST', headers, body: JSON.stringify({ cmd, ...params }),
});
const json = await res.json();
if (json && !Array.isArray(json) && json.error) throw new Error(`DB4js ${cmd}: ${json.error}`);
return json;
}
const esc = (s) => String(s ?? '').replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]));
function fullName(r) {
return [r.vorname, r.name].map((x) => (x || '').trim()).filter(Boolean).join(' ');
}
function buildHtml(rows) {
const stand = new Date().toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' });
const body = rows.map((r, i) => `
<tr>
<td class="nr">${i + 1}</td>
<td>${esc(fullName(r))}</td>
<td>${esc(r.ort)}</td>
<td class="km">${r.km == null || r.km === '' ? '—' : esc(r.km)}</td>
</tr>`).join('');
return `<!doctype html>
<html lang="de"><head><meta charset="utf-8"><title>BEO-Entfernungen</title>
<style>
@page { size: A4; margin: 18mm 16mm; }
* { box-sizing: border-box; }
body { font-family: -apple-system, "Helvetica Neue", Arial, sans-serif; color: #1a1a1a; font-size: 11pt; }
h1 { font-size: 17pt; margin: 0 0 2mm; }
.sub { color: #555; font-size: 10pt; margin: 0 0 5mm; }
.intro { font-size: 10pt; line-height: 1.45; margin: 0 0 6mm; }
table { width: 100%; border-collapse: collapse; }
thead th { text-align: left; font-size: 9.5pt; text-transform: uppercase; letter-spacing: .04em;
color: #444; border-bottom: 1.5pt solid #333; padding: 2mm 2mm; }
tbody td { padding: 1.8mm 2mm; border-bottom: 0.4pt solid #ccc; vertical-align: bottom; }
tbody tr:nth-child(even) { background: #f6f6f6; }
.nr { color: #999; width: 8mm; text-align: right; }
.km { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; width: 22mm; }
th.km { text-align: right; }
.foot { margin-top: 7mm; font-size: 8.5pt; color: #777; }
</style></head>
<body>
<h1>Entfernungen der BEOs zur Sternwarte Welzheim</h1>
<p class="sub">Einfache Straßenentfernung in Kilometern &middot; Stand: ${stand}</p>
<p class="intro">
Die folgende Tabelle listet die einfache Straßenentfernung (Auto) von deinem
Wohnort zur Sternwarte Welzheim. Die Werte wurden automatisch über
OpenStreetMap / OSRM ermittelt. <strong>Bitte prüfe deinen Wert und melde
ihn in jedem Fall zurück</strong> auch wenn er stimmt.
</p>
<table>
<thead><tr>
<th class="nr">#</th><th>Name</th><th>Wohnort</th><th class="km">km</th>
</tr></thead>
<tbody>${body}
</tbody>
</table>
<p class="foot">${rows.length} Beobachter &middot; Sternwarte Welzheim &middot; automatisch erzeugt</p>
</body></html>`;
}
async function main() {
const rows = await callProxy('GET_BEOS', { what: 'id,vorname,name,ort,km' });
rows.sort((a, b) => (a.name || '').localeCompare(b.name || '', 'de'));
const html = buildHtml(rows);
await writeFile(HTML_FILE, html, 'utf8');
await execFileP(CHROME, [
'--headless=new',
'--disable-gpu',
'--no-pdf-header-footer',
`--print-to-pdf=${PDF_FILE}`,
HTML_FILE,
]);
console.log(`PDF erzeugt: ${PDF_FILE} (${rows.length} BEOs)`);
}
main().catch((err) => { console.error('Fehler:', err.message); process.exit(1); });