01a7ac8e0b
Web-App zur Erfassung der Arbeitszeit, Layout/Architektur an Projekt logbuch angelehnt, mit grüner Grundfarbe und SQLite3 statt MySQL. - Eingabemaske: Datum (mit Wochentag), Ort (Kunde FFM/Homeoffice/Andrena), Beginn/Ende, Reisezeit, Vertriebsunterstützung (default 2h), Kommentar (max 500) - Berechnung: Arbeitszeit = Ende-Beginn; Mehrarbeit = Arbeitszeit - 8h - Pause - Pause als globale Einstellung (Einstellungen-Tab) - Tabs Eingabe/Liste/Einstellungen, letzte 10 Einträge unter der Maske - Single-User-Login (Benutzer Birgit + Passwort fest in .env), JWT-Cookie via jose - better-sqlite3, Docker-Setup für docker.citysensor.de Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { getDb } from './db';
|
|
import type { ArbeitszeitEintrag, ArbeitszeitInput } from '@/types/arbeitszeit';
|
|
|
|
interface ListParams {
|
|
limit: number;
|
|
offset: number;
|
|
month?: string; // "YYYY-MM"
|
|
}
|
|
|
|
interface ListResult {
|
|
entries: ArbeitszeitEintrag[];
|
|
total: number;
|
|
}
|
|
|
|
/** Einträge absteigend nach Datum (neueste zuerst), optional nach Monat gefiltert. */
|
|
export function listArbeitszeit({ limit, offset, month }: ListParams): ListResult {
|
|
const db = getDb();
|
|
const where = month ? `WHERE substr(datum, 1, 7) = ?` : '';
|
|
const args = month ? [month] : [];
|
|
|
|
const total = (
|
|
db.prepare(`SELECT COUNT(*) AS c FROM arbeitszeit ${where}`).get(...args) as { c: number }
|
|
).c;
|
|
|
|
const entries = db
|
|
.prepare(
|
|
`SELECT * FROM arbeitszeit ${where}
|
|
ORDER BY datum DESC, beginn DESC, id DESC
|
|
LIMIT ? OFFSET ?`
|
|
)
|
|
.all(...args, limit, offset) as ArbeitszeitEintrag[];
|
|
|
|
return { entries, total };
|
|
}
|
|
|
|
export function getArbeitszeit(id: number): ArbeitszeitEintrag | undefined {
|
|
return getDb().prepare('SELECT * FROM arbeitszeit WHERE id = ?').get(id) as
|
|
| ArbeitszeitEintrag
|
|
| undefined;
|
|
}
|
|
|
|
export function createArbeitszeit(input: ArbeitszeitInput): ArbeitszeitEintrag {
|
|
const db = getDb();
|
|
const info = db
|
|
.prepare(
|
|
`INSERT INTO arbeitszeit (datum, ort, beginn, ende, reisezeit, vertriebsunterstuetzung, kommentar)
|
|
VALUES (@datum, @ort, @beginn, @ende, @reisezeit, @vertriebsunterstuetzung, @kommentar)`
|
|
)
|
|
.run(input);
|
|
return getArbeitszeit(Number(info.lastInsertRowid))!;
|
|
}
|
|
|
|
export function updateArbeitszeit(
|
|
id: number,
|
|
input: ArbeitszeitInput
|
|
): ArbeitszeitEintrag | undefined {
|
|
const db = getDb();
|
|
db.prepare(
|
|
`UPDATE arbeitszeit SET
|
|
datum = @datum, ort = @ort, beginn = @beginn, ende = @ende,
|
|
reisezeit = @reisezeit, vertriebsunterstuetzung = @vertriebsunterstuetzung,
|
|
kommentar = @kommentar
|
|
WHERE id = @id`
|
|
).run({ ...input, id });
|
|
return getArbeitszeit(id);
|
|
}
|
|
|
|
export function deleteArbeitszeit(id: number): boolean {
|
|
return getDb().prepare('DELETE FROM arbeitszeit WHERE id = ?').run(id).changes > 0;
|
|
}
|
|
|
|
// --- Einstellungen -------------------------------------------------------
|
|
|
|
export function getPause(): number {
|
|
const row = getDb().prepare(`SELECT value FROM settings WHERE key = 'pause'`).get() as
|
|
| { value: string }
|
|
| undefined;
|
|
const v = row ? parseFloat(row.value) : 0.5;
|
|
return isNaN(v) ? 0.5 : v;
|
|
}
|
|
|
|
export function setPause(value: number): void {
|
|
getDb()
|
|
.prepare(
|
|
`INSERT INTO settings (key, value) VALUES ('pause', @value)
|
|
ON CONFLICT(key) DO UPDATE SET value = @value`
|
|
)
|
|
.run({ value: String(value) });
|
|
}
|