Initial commit: Auto-Charger Logging Web-App
MQTT-Collector (Python/paho-mqtt) speichert abgeschlossene go-e Wallbox-Ladungen in SQLite; Next.js-Web-App zeigt sie als Tabelle mit Energie-Summen (Monat/Jahr/gesamt) im werte-next-Design. Zwei Docker-Container mit gemeinsamem DB-Volume. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { Charge } from "@/lib/db";
|
||||
|
||||
const WEEKDAYS = ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"];
|
||||
|
||||
function parts(iso: string) {
|
||||
// erwartet "YYYY-MM-DDTHH:MM:SS" (lokale Zeit vom Collector)
|
||||
const [date = "", time = ""] = iso.split("T");
|
||||
const [y, m, d] = date.split("-");
|
||||
return { y, m, d, hm: time.slice(0, 5) };
|
||||
}
|
||||
|
||||
function formatDate(iso: string): string {
|
||||
const { y, m, d } = parts(iso);
|
||||
return y && m && d ? `${d}.${m}.${y}` : iso;
|
||||
}
|
||||
|
||||
function weekday(iso: string): string {
|
||||
const { y, m, d } = parts(iso);
|
||||
if (!y || !m || !d) return "-";
|
||||
return WEEKDAYS[new Date(Number(y), Number(m) - 1, Number(d)).getDay()];
|
||||
}
|
||||
|
||||
function formatTime(iso: string): string {
|
||||
return parts(iso).hm || "-";
|
||||
}
|
||||
|
||||
function formatDuration(seconds: number): string {
|
||||
const h = Math.floor(seconds / 3600);
|
||||
const min = Math.floor((seconds % 3600) / 60);
|
||||
return `${h}:${String(min).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
export default function ChargesTable({ charges }: { charges: Charge[] }) {
|
||||
if (charges.length === 0) {
|
||||
return (
|
||||
<div className="text-center py-8 text-gray-500">
|
||||
Noch keine Ladungen erfasst
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-[#CCCCFF] border-b-2 border-gray-400">
|
||||
<th className="p-2 text-center">Datum</th>
|
||||
<th className="p-2 text-center">Tag</th>
|
||||
<th className="p-2 text-center">Start</th>
|
||||
<th className="p-2 text-center">Ende</th>
|
||||
<th className="p-2 text-center">
|
||||
Dauer<br />
|
||||
<span className="text-xs font-normal">h:mm</span>
|
||||
</th>
|
||||
<th className="p-2 text-center">
|
||||
Energie<br />
|
||||
<span className="text-xs font-normal">kWh</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{charges.map((c, index) => (
|
||||
<tr
|
||||
key={c.id}
|
||||
className={`border-b border-gray-300 hover:bg-gray-50 ${
|
||||
index % 2 === 0 ? "bg-white" : "bg-gray-50"
|
||||
}`}
|
||||
>
|
||||
<td className="p-2 text-center">{formatDate(c.start_time)}</td>
|
||||
<td className="p-2 text-center">{weekday(c.start_time)}</td>
|
||||
<td className="p-2 text-center">{formatTime(c.start_time)}</td>
|
||||
<td className="p-2 text-center">{formatTime(c.end_time)}</td>
|
||||
<td className="p-2 text-center">{formatDuration(c.duration_s)}</td>
|
||||
<td className="p-2 text-center">
|
||||
{(c.energy_wh / 1000).toLocaleString("de-DE", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user