feat(maintenance): MAINT-Epic (Wartungspläne/-aufträge, Werkstatt) + Akte-Redesign
Neues Wartungskonzept: Wartungsplan+Position+Intervall (zeit/km/ Betriebsstunden, kombinierbar - fällig sobald ein Kriterium erreicht ist), Wartungsauftrag mit intern/externer Werkstatt, Status offen/ in_arbeit/erledigt, Kosten, Historie, Dokument-Anhang. Ad-hoc-Aufträge ohne Plan möglich (z.B. kleinere Reparatur). Admin-Tab "Wartungspläne". Objektakte-Redesign (Epic 21, Nutzer-Feedback "wirkt nicht modern"): CSS-Grid statt Karten-Stapel, einspaltig mobil, zweispaltig ab 900px; Fahrzeug-Objekte zeigen Wartung/Fahrzeugdaten prominent, Geräte/ Rucksäcke die Beladung. Dabei gefundene Lücke: Beladung (Soll/Ist je Position) fehlte in der Akte komplett, nur über eine laufende Kontrolle sichtbar - jetzt eigene Karte. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
@@ -5,6 +5,7 @@ import { apiRequest } from "../api/client";
|
||||
import { useAuth } from "../auth/AuthContext";
|
||||
import type { Akte } from "../api/types";
|
||||
import { DokumentePanel } from "../components/DokumentePanel";
|
||||
import { WartungSection } from "../components/WartungSection";
|
||||
import { ReadinessBadge } from "../components/status/ReadinessBadge";
|
||||
import { GRUND_TEXT } from "../components/status/gruendeText";
|
||||
import { EREIGNIS_LABEL } from "../components/status/ereignisText";
|
||||
@@ -15,8 +16,6 @@ const MANGEL_PRIORITAET_LABEL: Record<string, string> = {
|
||||
hoch: "Hoch",
|
||||
};
|
||||
|
||||
// FILE-006: EIN Screen für alle Teilbereiche einer Ressource statt mehrerer
|
||||
// Einzelseiten - konsumiert den FILE-001-Aggregations-Endpunkt.
|
||||
export function AktePage() {
|
||||
const { objektId } = useParams<{ objektId: string }>();
|
||||
const { istVerantwortlich } = useAuth();
|
||||
@@ -52,10 +51,11 @@ export function AktePage() {
|
||||
if (!akte) return null;
|
||||
|
||||
const { objekt } = akte;
|
||||
const istFahrzeug = akte.fahrzeugdetails !== null;
|
||||
|
||||
return (
|
||||
<main className="page">
|
||||
<div className="row-between" style={{ alignItems: "flex-start" }}>
|
||||
<main className={`page-wide akte-grid${istFahrzeug ? " ist-fahrzeug" : ""}`}>
|
||||
<div className="akte-kopf row-between" style={{ alignItems: "flex-start" }}>
|
||||
<div>
|
||||
<h1 style={{ marginBottom: "0.15rem" }}>{objekt.name}</h1>
|
||||
<div className="text-muted">
|
||||
@@ -65,7 +65,7 @@ export function AktePage() {
|
||||
<ReadinessBadge status={akte.einsatzbereitschaft_status} />
|
||||
</div>
|
||||
{akte.einsatzbereitschaft_gruende.length > 0 && (
|
||||
<ul className="card-list" style={{ marginTop: "0.5rem" }}>
|
||||
<ul className="akte-kopf card-list" style={{ marginTop: "0.5rem" }}>
|
||||
{akte.einsatzbereitschaft_gruende.map((g) => (
|
||||
<li key={g} className="text-muted" style={{ fontSize: "0.9rem" }}>
|
||||
• {GRUND_TEXT[g] ?? g}
|
||||
@@ -74,9 +74,7 @@ export function AktePage() {
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{/* nach dem QR-Scan (MOBILE-002) landet man hier - die
|
||||
Kernaktionen sollen direkt sichtbar sein, nicht erst am Seitenende. */}
|
||||
<div className="row" style={{ flexWrap: "wrap", marginTop: "1rem" }}>
|
||||
<div className="akte-aktionen row" style={{ flexWrap: "wrap" }}>
|
||||
<Link to={`/objekte/${objekt.id}/kontrolle`} className="btn btn-primary">
|
||||
Kontrolle starten
|
||||
</Link>
|
||||
@@ -85,7 +83,7 @@ export function AktePage() {
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-stamm card">
|
||||
<h3 style={{ marginTop: 0 }}>Stammdaten</h3>
|
||||
<div className="stack">
|
||||
<div>Standort: {akte.standort_name}</div>
|
||||
@@ -108,7 +106,40 @@ export function AktePage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-beladung card">
|
||||
<h3 style={{ marginTop: 0 }}>Beladung</h3>
|
||||
{akte.beladung.length === 0 && <p className="text-muted">Keine Positionen zugeordnet.</p>}
|
||||
{akte.beladung.length > 0 && (
|
||||
<div style={{ overflowX: "auto" }}>
|
||||
<table className="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Material</th>
|
||||
<th>Fach</th>
|
||||
<th>Soll</th>
|
||||
<th>Ist</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{akte.beladung.map((b) => (
|
||||
<tr key={b.objektposition_id}>
|
||||
<td>{b.material_name}</td>
|
||||
<td>{b.fach ?? "–"}</td>
|
||||
<td>
|
||||
{b.sollmenge} {b.einheit}
|
||||
</td>
|
||||
<td className={Number(b.istmenge) < Number(b.sollmenge) ? "text-danger" : undefined}>
|
||||
{b.istmenge} {b.einheit}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="akte-verantwortlich card">
|
||||
<h3 style={{ marginTop: 0 }}>Verantwortlichkeit</h3>
|
||||
{akte.zustaendige_benutzer.length === 0 && akte.kontrollverantwortung.length === 0 && (
|
||||
<p className="text-muted">Keine Zuordnung hinterlegt.</p>
|
||||
@@ -124,7 +155,7 @@ export function AktePage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-pruefungen card">
|
||||
<h3 style={{ marginTop: 0 }}>Prüfungen (Geräte)</h3>
|
||||
{akte.geraete.length === 0 && <p className="text-muted">Keine Geräte-Instanzen erfasst.</p>}
|
||||
{akte.geraete.length > 0 && (
|
||||
@@ -149,7 +180,11 @@ export function AktePage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-wartung">
|
||||
<WartungSection objektId={objekt.id} onFehler={setFehler} />
|
||||
</div>
|
||||
|
||||
<div className="akte-maengel card">
|
||||
<h3 style={{ marginTop: 0 }}>Mängel</h3>
|
||||
{akte.maengel.length === 0 && <p className="text-muted">Keine Mängel gemeldet.</p>}
|
||||
{akte.maengel.length > 0 && (
|
||||
@@ -163,12 +198,12 @@ export function AktePage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-dokumente card">
|
||||
<h3 style={{ marginTop: 0 }}>Dokumente</h3>
|
||||
<DokumentePanel entitaetTyp="objekt" entitaetId={String(objekt.id)} onFehler={setFehler} />
|
||||
</div>
|
||||
|
||||
<div className="card" style={{ marginTop: "1rem" }}>
|
||||
<div className="akte-historie card">
|
||||
<h3 style={{ marginTop: 0 }}>Historie</h3>
|
||||
{akte.historie.length === 0 && <p className="text-muted">Noch keine Änderungen protokolliert.</p>}
|
||||
{akte.historie.length > 0 && (
|
||||
|
||||
Reference in New Issue
Block a user