L13 Planung: Menüpunkt Planung mit Plantafel und Live-Lage
Plantafel: Standard heute + nächste 4 Werktage (Kolonnen als Zeilen, heutige Spalte mit Live-Status), Heute mit Kolonnen als parallelen Spalten (6–20 Uhr), Woche/nächste Woche, Auslastung, Konflikte/Hinweise, Verzugs- und Gefährdungs-Badges, Drag & Drop (@dnd-kit/core) mit Bestätigungs-Popover und Tastatur-Alternative, ungeplante Aufträge mit Vorschlägen, früher fertig mit Vorziehen, Kolonnenkapazität-Popup. Live-Lage: Leaflet/OSM-Karte mit einem Marker je Kolonne, Liste, Polling 30 s, Hinweis keine GPS-Ortung; CSP img-src für Kacheln. Dashboard-Kacheln Planung heute und Konflikte diese Woche, Einsatz-Vorschläge im Auftragsdetail, Navigation mit Unterpunkten, Smoke-Prüfungen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"dashboard": "Dashboard",
|
||||
"workOrders": "Aufträge",
|
||||
"planning": "Planung",
|
||||
"planningBoard": "Plantafel",
|
||||
"planningLive": "Live-Lage",
|
||||
"emergencyReview": "Notdienst-Prüfung",
|
||||
"imports": "Import",
|
||||
"customers": "Kunden",
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
{
|
||||
"crumb": "Planung",
|
||||
"weekday": { "0": "Mo", "1": "Di", "2": "Mi", "3": "Do", "4": "Fr", "5": "Sa", "6": "So" },
|
||||
"board": {
|
||||
"title": "Plantafel",
|
||||
"sub": "Aufträge je Team und Tag einplanen – Auslastung und Überschneidungen auf einen Blick.",
|
||||
"readOnly": "Nur Lesezugriff – Sie sehen Ihre eigenen Teams.",
|
||||
"viewLabel": "Ansicht",
|
||||
"view": { "today": "Heute", "days": "5 Tage", "week": "Woche", "nextWeek": "Nächste Woche" },
|
||||
"navLabel": "Zeitraum wechseln",
|
||||
"prevWeek": "Vorige Woche",
|
||||
"nextWeek": "Nächste Woche",
|
||||
"prevDay": "Voriger Tag",
|
||||
"nextDay": "Nächster Tag",
|
||||
"prevDays": "Vorige 5 Werktage",
|
||||
"nextDays": "Nächste 5 Werktage",
|
||||
"todayLabel": "Heute · {day}",
|
||||
"time": "Uhrzeit",
|
||||
"today": "Heute",
|
||||
"range": "{from} – {to}",
|
||||
"team": "Team",
|
||||
"noTeams": "Keine aktiven Teams in dieser Auswahl.",
|
||||
"showMembers": "Mitglieder von {team} anzeigen",
|
||||
"hideMembers": "Mitglieder von {team} ausblenden",
|
||||
"memberHint": "Einzeln zugewiesen",
|
||||
"load": "{planned} / {capacity} · {percent} %",
|
||||
"loadNoCapacity": "{planned} · keine Kapazität",
|
||||
"notWorkingDay": "Kein Arbeitstag",
|
||||
"allDay": "Ganztägig",
|
||||
"free": "frei",
|
||||
"narrowHint": "Die Plantafel ist für Bildschirme ab 1024 px ausgelegt. Hier sehen Sie eine einfache Liste.",
|
||||
"capacity": "Kapazität",
|
||||
"capacityOf": "Kapazität von {team} bearbeiten",
|
||||
"move": "Verschieben …",
|
||||
"schedule": "Einplanen …",
|
||||
"dragHint": "Karten mit der Maus auf einen Tag ziehen oder über „Einplanen …“ bzw. „Verschieben …“ per Tastatur einplanen.",
|
||||
"open": "Auftrag öffnen",
|
||||
"saved": "{number} eingeplant: {team}, {day}.",
|
||||
"savedWithConflicts": "{number} eingeplant: {team}, {day}. Achtung: {count} Konflikt(e) am Zieltag.",
|
||||
"priority": "Priorität: {priority}",
|
||||
"emergency": "Notdienst",
|
||||
"multiDay": "mehrtägig",
|
||||
"duration": "Dauer {duration}",
|
||||
"listDayEmpty": "Nichts geplant",
|
||||
"crewCapacity": "Kolonne · {capacity} je Arbeitstag · {count} Personen",
|
||||
"delayRisk": "Verzug droht · {percent} %",
|
||||
"delayOverrun": "Dauer überschritten · {percent} %",
|
||||
"atRisk": "gefährdet durch Verzug {number}"
|
||||
},
|
||||
"freed": {
|
||||
"title": "Früher fertig",
|
||||
"badge": "{team} · {minutes} früher fertig",
|
||||
"available": "{minutes} frei ab {time}",
|
||||
"pullForward": "Vorziehen",
|
||||
"kindPullForward": "Geplanter Auftrag von {team}",
|
||||
"kindNearby": "Ungeplant, {distance} entfernt",
|
||||
"noSuggestions": "Kein passender Auftrag für die freie Zeit.",
|
||||
"hint": "Nur Hinweis – nichts wird automatisch verschoben."
|
||||
},
|
||||
"conflicts": {
|
||||
"label": "Konflikt",
|
||||
"count": "{count, plural, =0 {Keine Konflikte} one {# Konflikt} other {# Konflikte}}",
|
||||
"overbooked": "Überbucht um {over}",
|
||||
"overlap": "Überschneidung: {a} und {b}",
|
||||
"assignee_double_booked": "{user} doppelt eingeplant: {a} und {b}",
|
||||
"outside_working_days": "Außerhalb der Arbeitstage",
|
||||
"crew_incomplete": "Kolonne unvollständig: {count} aktive Person(en)",
|
||||
"hintLabel": "Hinweis",
|
||||
"short": {
|
||||
"overbooked": "Überbucht",
|
||||
"overlap": "Überschneidung",
|
||||
"assignee_double_booked": "Doppelt eingeplant",
|
||||
"outside_working_days": "Kein Arbeitstag",
|
||||
"crew_incomplete": "Kolonne unvollständig"
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"title": "Filter",
|
||||
"team": "Team",
|
||||
"orderType": "Auftragsart",
|
||||
"priority": "Priorität",
|
||||
"any": "Alle",
|
||||
"apply": "Anwenden",
|
||||
"reset": "Zurücksetzen"
|
||||
},
|
||||
"unplanned": {
|
||||
"title": "Ungeplante Aufträge",
|
||||
"empty": "Keine ungeplanten Aufträge.",
|
||||
"noTeam": "ohne Team",
|
||||
"noDate": "ohne Termin",
|
||||
"noLocation": "ohne Ortsangabe",
|
||||
"suggestions": "Vorschläge"
|
||||
},
|
||||
"dialog": {
|
||||
"title": "Auftrag einplanen",
|
||||
"team": "Team",
|
||||
"date": "Datum",
|
||||
"time": "Beginn",
|
||||
"noTime": "Ohne Uhrzeit (ganztägig)",
|
||||
"duration": "Dauer in Minuten",
|
||||
"durationHint": "Vorbelegt aus Auftrag bzw. Auftragsart ({duration}).",
|
||||
"save": "Speichern",
|
||||
"saving": "Speichert …",
|
||||
"cancel": "Abbrechen",
|
||||
"close": "Schließen"
|
||||
},
|
||||
"errors": {
|
||||
"conflict": "Auftrag wurde zwischenzeitlich geändert. Die Ansicht wurde aktualisiert – bitte erneut einplanen.",
|
||||
"forbidden": "Dafür fehlt Ihnen die Berechtigung.",
|
||||
"not_found": "Auftrag nicht gefunden.",
|
||||
"invalid": "Bitte die Eingaben prüfen.",
|
||||
"planned_end_before_start": "Das Ende liegt vor dem Beginn.",
|
||||
"not_schedulable": "Dieser Auftrag läuft bereits und wird hier nicht verschoben.",
|
||||
"team_not_found": "Team nicht gefunden oder nicht aktiv.",
|
||||
"not_editable": "Dieser Auftrag kann nicht mehr geändert werden.",
|
||||
"network": "Keine Verbindung. Bitte erneut versuchen.",
|
||||
"generic": "Speichern war nicht möglich. Bitte erneut versuchen."
|
||||
},
|
||||
"recommend": {
|
||||
"title": "Vorschläge",
|
||||
"sub": "Nur Vorschläge nach Luftlinie und Terminlage – die Zuweisung entscheiden Sie.",
|
||||
"loading": "Vorschläge werden berechnet …",
|
||||
"reason": "{distance} von {number} · {team} hat am {day} noch {free} frei",
|
||||
"reasonTight": "{distance} von {number} · {team} am {day} knapp: {free} frei, {required} nötig",
|
||||
"card": "{day} · {team} · {distance} von {number} · {free} frei",
|
||||
"tight": "knapp",
|
||||
"take": "Übernehmen",
|
||||
"noCoordinates": "Adresse nicht verortet – die Verortung wurde angestoßen. Bitte später erneut öffnen.",
|
||||
"addressNotFound": "Adresse nicht verortet – die Adresse wurde nicht gefunden. Bitte am Objekt prüfen.",
|
||||
"notSchedulable": "Dieser Auftrag ist bereits in Ausführung.",
|
||||
"none": "Kein Team hat in den nächsten {days} Tagen einen Auftrag im Umkreis von {radius} km mit freier Kapazität.",
|
||||
"nearbyTitle": "In der Nähe, ebenfalls ungeplant",
|
||||
"nearbyQuestion": "Diese Aufträge liegen im Umkreis von {radius} km – zusammen einplanen?",
|
||||
"nearbyEmpty": "Keine weiteren ungeplanten Aufträge in der Nähe.",
|
||||
"planTogether": "Gemeinsam einplanen",
|
||||
"close": "Vorschläge schließen",
|
||||
"failed": "Vorschläge konnten nicht geladen werden.",
|
||||
"sectionTitle": "Einsatz-Vorschläge",
|
||||
"openBoard": "Zur Plantafel"
|
||||
},
|
||||
"live": {
|
||||
"title": "Live-Lage",
|
||||
"sub": "Wer ist gerade in welchem Einsatz?",
|
||||
"privacy": "Standort = Einsatzort des laufenden Auftrags, keine GPS-Ortung.",
|
||||
"status": { "en_route": "Unterwegs", "working": "In Arbeit", "paused": "Pause", "free": "Frei" },
|
||||
"freeHint": "kein laufender Einsatz",
|
||||
"since": "seit {time}",
|
||||
"updated": "Zuletzt aktualisiert: {time}",
|
||||
"refresh": "Aktualisieren",
|
||||
"refreshing": "Aktualisiert …",
|
||||
"updateFailed": "Aktualisierung fehlgeschlagen – der letzte Stand wird angezeigt.",
|
||||
"tabsLabel": "Darstellung",
|
||||
"tabs": { "map": "Karte", "list": "Liste" },
|
||||
"filterTeam": "Team",
|
||||
"filterStatus": "Status",
|
||||
"all": "Alle",
|
||||
"noLocation": "ohne Ortsangabe",
|
||||
"hiddenOrder": "Einsatz außerhalb Ihres Bereichs",
|
||||
"next": "Heute noch geplant",
|
||||
"nothingNext": "Heute nichts weiter geplant",
|
||||
"attentionTitle": "Heute ohne Beginn",
|
||||
"attentionEmpty": "Alle heutigen Aufträge sind begonnen oder später geplant.",
|
||||
"reason": { "not_accepted": "Nicht angenommen", "overdue": "Beginn überschritten" },
|
||||
"empty": "Keine Monteure in dieser Auswahl.",
|
||||
"markerCount": "{count} Personen an diesem Ort",
|
||||
"mapLabel": "Karte der laufenden Einsätze",
|
||||
"mapLoading": "Karte wird geladen …",
|
||||
"withoutLocation": "{count} laufende Einsätze ohne Ortsangabe (nur in der Liste)",
|
||||
"noTeam": "ohne Team",
|
||||
"crewsTitle": "Kolonnen",
|
||||
"soloTitle": "Ohne Team",
|
||||
"crewMembers": "Mitglieder",
|
||||
"memberAt": "bei {number}",
|
||||
"delayRisk": "Verzug droht · {percent} %",
|
||||
"delayOverrun": "Dauer überschritten · {percent} %",
|
||||
"worked": "{worked} von {planned} erfasst"
|
||||
},
|
||||
"capacity": {
|
||||
"title": "Teamkapazität",
|
||||
"sub": "Grundlage für Auslastung und Vorschläge",
|
||||
"minutes": "Arbeitstag der Kolonne in Minuten",
|
||||
"minutesHint": "Die Kolonne arbeitet gemeinsam: Kapazität je Arbeitstag, nicht je Person.",
|
||||
"days": "Arbeitstage",
|
||||
"save": "Speichern",
|
||||
"saving": "Speichert …",
|
||||
"errors": {
|
||||
"invalid": "Bitte die Eingaben prüfen.",
|
||||
"forbidden": "Dafür fehlt Ihnen die Berechtigung.",
|
||||
"not_found": "Team nicht gefunden.",
|
||||
"generic": "Speichern war nicht möglich."
|
||||
}
|
||||
},
|
||||
"dashboardTile": {
|
||||
"title": "Konflikte diese Woche",
|
||||
"hint": "Überbuchung, Überschneidung, Doppelbuchung",
|
||||
"todayTitle": "Planung heute",
|
||||
"todayHint": "Teams im Einsatz · {conflicts} Konflikt(e) · {unplanned} ungeplante Aufträge"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
{
|
||||
"dashboard": "Dashboard",
|
||||
"workOrders": "Work orders",
|
||||
"planning": "Planning",
|
||||
"planningBoard": "Planning board",
|
||||
"planningLive": "Live situation",
|
||||
"emergencyReview": "Emergency review",
|
||||
"imports": "Import",
|
||||
"customers": "Customers",
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
{
|
||||
"crumb": "Planning",
|
||||
"weekday": { "0": "Mon", "1": "Tue", "2": "Wed", "3": "Thu", "4": "Fri", "5": "Sat", "6": "Sun" },
|
||||
"board": {
|
||||
"title": "Planning board",
|
||||
"sub": "Schedule orders per team and day – utilization and overlaps at a glance.",
|
||||
"readOnly": "Read-only – you see your own teams.",
|
||||
"viewLabel": "View",
|
||||
"view": { "today": "Today", "days": "5 days", "week": "Week", "nextWeek": "Next week" },
|
||||
"navLabel": "Change period",
|
||||
"prevWeek": "Previous week",
|
||||
"nextWeek": "Next week",
|
||||
"prevDay": "Previous day",
|
||||
"nextDay": "Next day",
|
||||
"prevDays": "Previous 5 working days",
|
||||
"nextDays": "Next 5 working days",
|
||||
"todayLabel": "Today · {day}",
|
||||
"time": "Time",
|
||||
"today": "Today",
|
||||
"range": "{from} – {to}",
|
||||
"team": "Team",
|
||||
"noTeams": "No active teams in this selection.",
|
||||
"showMembers": "Show members of {team}",
|
||||
"hideMembers": "Hide members of {team}",
|
||||
"memberHint": "Individually assigned",
|
||||
"load": "{planned} / {capacity} · {percent} %",
|
||||
"loadNoCapacity": "{planned} · no capacity",
|
||||
"notWorkingDay": "Not a working day",
|
||||
"allDay": "All day",
|
||||
"free": "free",
|
||||
"narrowHint": "The planning board is designed for screens from 1024 px. Here you see a simple list.",
|
||||
"capacity": "Capacity",
|
||||
"capacityOf": "Edit capacity of {team}",
|
||||
"move": "Move …",
|
||||
"schedule": "Schedule …",
|
||||
"dragHint": "Drag cards onto a day with the mouse or use “Schedule …” / “Move …” with the keyboard.",
|
||||
"open": "Open order",
|
||||
"saved": "{number} scheduled: {team}, {day}.",
|
||||
"savedWithConflicts": "{number} scheduled: {team}, {day}. Attention: {count} conflict(s) on the target day.",
|
||||
"priority": "Priority: {priority}",
|
||||
"emergency": "Emergency",
|
||||
"multiDay": "multi-day",
|
||||
"duration": "Duration {duration}",
|
||||
"listDayEmpty": "Nothing planned",
|
||||
"crewCapacity": "Crew · {capacity} per working day · {count} people",
|
||||
"delayRisk": "Delay likely · {percent} %",
|
||||
"delayOverrun": "Duration exceeded · {percent} %",
|
||||
"atRisk": "at risk due to delay of {number}"
|
||||
},
|
||||
"freed": {
|
||||
"title": "Finished early",
|
||||
"badge": "{team} · {minutes} early",
|
||||
"available": "{minutes} free from {time}",
|
||||
"pullForward": "Pull forward",
|
||||
"kindPullForward": "Planned order of {team}",
|
||||
"kindNearby": "Unplanned, {distance} away",
|
||||
"noSuggestions": "No suitable order for the free time.",
|
||||
"hint": "Hint only – nothing is moved automatically."
|
||||
},
|
||||
"conflicts": {
|
||||
"label": "Conflict",
|
||||
"count": "{count, plural, =0 {No conflicts} one {# conflict} other {# conflicts}}",
|
||||
"overbooked": "Overbooked by {over}",
|
||||
"overlap": "Overlap: {a} and {b}",
|
||||
"assignee_double_booked": "{user} double-booked: {a} and {b}",
|
||||
"outside_working_days": "Outside working days",
|
||||
"crew_incomplete": "Crew incomplete: {count} active person(s)",
|
||||
"hintLabel": "Hint",
|
||||
"short": {
|
||||
"overbooked": "Overbooked",
|
||||
"overlap": "Overlap",
|
||||
"assignee_double_booked": "Double-booked",
|
||||
"outside_working_days": "Not a working day",
|
||||
"crew_incomplete": "Crew incomplete"
|
||||
}
|
||||
},
|
||||
"filters": {
|
||||
"title": "Filter",
|
||||
"team": "Team",
|
||||
"orderType": "Order type",
|
||||
"priority": "Priority",
|
||||
"any": "All",
|
||||
"apply": "Apply",
|
||||
"reset": "Reset"
|
||||
},
|
||||
"unplanned": {
|
||||
"title": "Unplanned orders",
|
||||
"empty": "No unplanned orders.",
|
||||
"noTeam": "no team",
|
||||
"noDate": "no date",
|
||||
"noLocation": "no location",
|
||||
"suggestions": "Suggestions"
|
||||
},
|
||||
"dialog": {
|
||||
"title": "Schedule order",
|
||||
"team": "Team",
|
||||
"date": "Date",
|
||||
"time": "Start",
|
||||
"noTime": "No time (all day)",
|
||||
"duration": "Duration in minutes",
|
||||
"durationHint": "Prefilled from the order or order type ({duration}).",
|
||||
"save": "Save",
|
||||
"saving": "Saving …",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close"
|
||||
},
|
||||
"errors": {
|
||||
"conflict": "The order was changed in the meantime. The view was refreshed – please schedule again.",
|
||||
"forbidden": "You are not allowed to do this.",
|
||||
"not_found": "Order not found.",
|
||||
"invalid": "Please check your input.",
|
||||
"planned_end_before_start": "The end is before the start.",
|
||||
"not_schedulable": "This order is already in progress and is not moved here.",
|
||||
"team_not_found": "Team not found or not active.",
|
||||
"not_editable": "This order can no longer be changed.",
|
||||
"network": "No connection. Please try again.",
|
||||
"generic": "Saving was not possible. Please try again."
|
||||
},
|
||||
"recommend": {
|
||||
"title": "Suggestions",
|
||||
"sub": "Suggestions only, by straight-line distance and schedule – you decide the assignment.",
|
||||
"loading": "Calculating suggestions …",
|
||||
"reason": "{distance} from {number} · {team} still has {free} free on {day}",
|
||||
"reasonTight": "{distance} from {number} · {team} on {day} tight: {free} free, {required} needed",
|
||||
"card": "{day} · {team} · {distance} from {number} · {free} free",
|
||||
"tight": "tight",
|
||||
"take": "Use",
|
||||
"noCoordinates": "Address not located – geocoding was requested. Please open again later.",
|
||||
"addressNotFound": "Address not located – the address was not found. Please check the site.",
|
||||
"notSchedulable": "This order is already in progress.",
|
||||
"none": "No team has an order within {radius} km with free capacity in the next {days} days.",
|
||||
"nearbyTitle": "Nearby, also unplanned",
|
||||
"nearbyQuestion": "These orders are within {radius} km – schedule them together?",
|
||||
"nearbyEmpty": "No other unplanned orders nearby.",
|
||||
"planTogether": "Schedule together",
|
||||
"close": "Close suggestions",
|
||||
"failed": "Suggestions could not be loaded.",
|
||||
"sectionTitle": "Assignment suggestions",
|
||||
"openBoard": "Open planning board"
|
||||
},
|
||||
"live": {
|
||||
"title": "Live situation",
|
||||
"sub": "Who is currently on which job?",
|
||||
"privacy": "Location = site of the running order, no GPS tracking.",
|
||||
"status": { "en_route": "En route", "working": "Working", "paused": "Break", "free": "Free" },
|
||||
"freeHint": "no running job",
|
||||
"since": "since {time}",
|
||||
"updated": "Last updated: {time}",
|
||||
"refresh": "Refresh",
|
||||
"refreshing": "Refreshing …",
|
||||
"updateFailed": "Update failed – showing the last state.",
|
||||
"tabsLabel": "Display",
|
||||
"tabs": { "map": "Map", "list": "List" },
|
||||
"filterTeam": "Team",
|
||||
"filterStatus": "Status",
|
||||
"all": "All",
|
||||
"noLocation": "no location",
|
||||
"hiddenOrder": "Job outside your area",
|
||||
"next": "Still planned today",
|
||||
"nothingNext": "Nothing else planned today",
|
||||
"attentionTitle": "Today without start",
|
||||
"attentionEmpty": "All of today's orders have started or are planned later.",
|
||||
"reason": { "not_accepted": "Not accepted", "overdue": "Start time passed" },
|
||||
"empty": "No technicians in this selection.",
|
||||
"markerCount": "{count} people at this location",
|
||||
"mapLabel": "Map of running jobs",
|
||||
"mapLoading": "Loading map …",
|
||||
"withoutLocation": "{count} running jobs without location (list only)",
|
||||
"noTeam": "no team",
|
||||
"crewsTitle": "Crews",
|
||||
"soloTitle": "Without team",
|
||||
"crewMembers": "Members",
|
||||
"memberAt": "at {number}",
|
||||
"delayRisk": "Delay likely · {percent} %",
|
||||
"delayOverrun": "Duration exceeded · {percent} %",
|
||||
"worked": "{worked} of {planned} recorded"
|
||||
},
|
||||
"capacity": {
|
||||
"title": "Team capacity",
|
||||
"sub": "Basis for utilization and suggestions",
|
||||
"minutes": "Crew working day in minutes",
|
||||
"minutesHint": "The crew works together: capacity per working day, not per person.",
|
||||
"days": "Working days",
|
||||
"save": "Save",
|
||||
"saving": "Saving …",
|
||||
"errors": {
|
||||
"invalid": "Please check your input.",
|
||||
"forbidden": "You are not allowed to do this.",
|
||||
"not_found": "Team not found.",
|
||||
"generic": "Saving was not possible."
|
||||
}
|
||||
},
|
||||
"dashboardTile": {
|
||||
"title": "Conflicts this week",
|
||||
"hint": "Overbooking, overlap, double booking",
|
||||
"todayTitle": "Planning today",
|
||||
"todayHint": "Teams on the job · {conflicts} conflict(s) · {unplanned} unplanned orders"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user