Add Help & Documentation system under Settings

This commit is contained in:
2026-03-12 17:33:42 +00:00
parent 88fce35e84
commit 96c3fdd836
3472 changed files with 1368684 additions and 10 deletions

View File

@@ -33,7 +33,10 @@ const navigation = computed(() => {
items.push({ name: 'Module', href: '/modules', icon: '⚙️' })
}
items.push({ name: 'Einstellungen', href: '/settings', icon: '🔧' })
items.push(
{ name: 'Einstellungen', href: '/settings', icon: '🔧' },
{ name: 'Hilfe', href: '/help', icon: '📚' }
)
return items
})

View File

@@ -73,6 +73,11 @@ const router = createRouter({
path: 'partnerships',
name: 'partnerships',
component: () => import('@/views/PartnershipsView.vue')
},
{
path: 'help',
name: 'help',
component: () => import('@/views/HelpView.vue')
}
]
}

702
src/views/HelpView.vue Normal file
View File

@@ -0,0 +1,702 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
const searchQuery = ref('')
const activeCategory = ref<string | null>(null)
const activeArticle = ref<string | null>(null)
interface Article {
id: string
title: string
icon: string
content: string
}
interface Category {
id: string
name: string
icon: string
description: string
articles: Article[]
}
const categories: Category[] = [
{
id: 'getting-started',
name: 'Erste Schritte',
icon: '🚀',
description: 'Grundlagen und Einrichtung',
articles: [
{
id: 'overview',
title: 'Übersicht',
icon: '📋',
content: `
## Was ist SeCu?
SeCu ist eine modulare Mitarbeiterverwaltung speziell für Sicherheitsunternehmen. Die Software hilft Ihnen bei:
- **Mitarbeiterverwaltung** Alle Mitarbeiter zentral verwalten
- **Auftragsverwaltung** Aufträge erstellen und zuweisen
- **Stundenzettel** Arbeitszeiten erfassen und genehmigen
- **Verfügbarkeiten** Wer ist wann einsetzbar?
- **Partnerschaften** Zusammenarbeit mit Subunternehmern
### Rollen im System
**Chef** Vollzugriff auf alle Funktionen, kann Disponenten und Mitarbeiter anlegen
**Disponent** Kann Mitarbeiter anlegen, Aufträge erstellen, Stundenzettel einsehen
**Mitarbeiter** Kann eigene Aufträge sehen, Verfügbarkeit melden, Stundenzettel hochladen
`
},
{
id: 'first-login',
title: 'Erster Login',
icon: '🔐',
content: `
## Erster Login
Nach der Registrierung Ihrer Organisation erhalten Sie Zugangsdaten per E-Mail.
### Anmeldung
1. Öffnen Sie die SeCu-Webseite
2. Geben Sie Ihre E-Mail-Adresse ein
3. Geben Sie Ihr Passwort ein
4. Klicken Sie auf "Anmelden"
### Passwort ändern
Wir empfehlen, Ihr Passwort nach dem ersten Login zu ändern:
1. Gehen Sie zu **Einstellungen**
2. Scrollen Sie zu "Passwort ändern"
3. Geben Sie Ihr aktuelles Passwort ein
4. Geben Sie ein neues Passwort ein (mind. 8 Zeichen)
5. Bestätigen Sie das neue Passwort
6. Klicken Sie auf "Passwort ändern"
`
}
]
},
{
id: 'users',
name: 'Benutzerverwaltung',
icon: '👥',
description: 'Mitarbeiter und Disponenten verwalten',
articles: [
{
id: 'create-user',
title: 'Benutzer anlegen',
icon: '',
content: `
## Neuen Benutzer anlegen
**Berechtigung:** Chef oder Disponent
### Schritt für Schritt
1. Navigieren Sie zu **Benutzer** im Menü
2. Klicken Sie auf **"+ Neuer Benutzer"**
3. Füllen Sie das Formular aus:
- **Vorname** und **Nachname**
- **E-Mail-Adresse** (wird für Login verwendet)
- **Passwort** (mind. 8 Zeichen)
- **Rolle** auswählen (Disponent oder Mitarbeiter)
4. Klicken Sie auf **"Erstellen"**
### Rollen-Unterschiede
- **Disponent**: Kann selbst Mitarbeiter anlegen und Aufträge verwalten
- **Mitarbeiter**: Kann nur eigene Daten sehen und bearbeiten
> **Hinweis:** Als Disponent können Sie nur Mitarbeiter anlegen, keine weiteren Disponenten.
`
},
{
id: 'edit-user',
title: 'Benutzer bearbeiten',
icon: '✏️',
content: `
## Benutzer bearbeiten
### Benutzerdaten ändern
1. Gehen Sie zu **Benutzer**
2. Klicken Sie auf den Namen des Benutzers
3. Ändern Sie die gewünschten Felder
4. Klicken Sie auf **"Speichern"**
### Benutzer deaktivieren
Statt einen Benutzer zu löschen, können Sie ihn deaktivieren:
1. Öffnen Sie das Benutzerprofil
2. Setzen Sie den Status auf **"Inaktiv"**
3. Der Benutzer kann sich nicht mehr anmelden
> **Tipp:** Deaktivierte Benutzer bleiben in der Historie erhalten.
`
}
]
},
{
id: 'orders',
name: 'Auftragsverwaltung',
icon: '📋',
description: 'Aufträge erstellen und verwalten',
articles: [
{
id: 'create-order',
title: 'Auftrag erstellen',
icon: '',
content: `
## Neuen Auftrag erstellen
**Berechtigung:** Chef oder Disponent
### Auftrag anlegen
1. Navigieren Sie zu **Aufträge**
2. Klicken Sie auf **"+ Neuer Auftrag"**
3. Füllen Sie die Pflichtfelder aus:
- **Titel** Kurze Beschreibung des Auftrags
- **Kunde** Name des Auftraggebers
- **Standort** Einsatzort
- **Datum/Zeit** Wann findet der Einsatz statt?
4. Optional: Beschreibung hinzufügen
5. Klicken Sie auf **"Erstellen"**
### Mitarbeiter zuweisen
Nach dem Erstellen können Sie Mitarbeiter zuweisen:
1. Öffnen Sie den Auftrag
2. Klicken Sie auf **"Mitarbeiter zuweisen"**
3. Wählen Sie verfügbare Mitarbeiter aus
4. Bestätigen Sie die Zuweisung
`
},
{
id: 'order-status',
title: 'Auftragsstatus',
icon: '🔄',
content: `
## Auftragsstatus verstehen
Jeder Auftrag durchläuft verschiedene Status:
🟡 **Offen** Auftrag erstellt, noch nicht begonnen
🔵 **In Bearbeitung** Auftrag läuft aktuell
🟢 **Abgeschlossen** Auftrag erfolgreich beendet
🔴 **Storniert** Auftrag wurde abgebrochen
### Status ändern
1. Öffnen Sie den Auftrag
2. Klicken Sie auf den aktuellen Status
3. Wählen Sie den neuen Status
4. Optional: Kommentar hinzufügen
`
}
]
},
{
id: 'timesheets',
name: 'Stundenzettel',
icon: '⏱️',
description: 'Arbeitszeiten erfassen und verwalten',
articles: [
{
id: 'submit-timesheet',
title: 'Stundenzettel einreichen',
icon: '📤',
content: `
## Stundenzettel einreichen
**Für Mitarbeiter**
### Arbeitszeit erfassen
1. Gehen Sie zu **Stundenzettel**
2. Klicken Sie auf **"+ Neue Erfassung"**
3. Wählen Sie den **Auftrag** aus
4. Geben Sie ein:
- **Startzeit** und **Endzeit**
- **Pausenzeit** (falls vorhanden)
5. Optional: Foto des Stundenzettels hochladen
6. Klicken Sie auf **"Einreichen"**
### Foto hochladen
Sie können ein Foto Ihres handschriftlichen Stundenzettels anhängen:
1. Klicken Sie auf **"Foto hinzufügen"**
2. Wählen Sie das Foto aus oder machen Sie ein neues
3. Das Foto wird automatisch hochgeladen
> **Tipp:** Stellen Sie sicher, dass das Foto gut lesbar ist.
`
},
{
id: 'approve-timesheet',
title: 'Stundenzettel genehmigen',
icon: '✅',
content: `
## Stundenzettel genehmigen
**Für Disponenten und Chefs**
### Übersicht
Offene Stundenzettel werden im Dashboard angezeigt. Sie können diese genehmigen oder ablehnen.
### Genehmigungsprozess
1. Gehen Sie zu **Stundenzettel**
2. Filtern Sie nach **"Ausstehend"**
3. Prüfen Sie die Einträge:
- Stimmen die Zeiten mit dem Auftrag überein?
- Ist das hochgeladene Foto lesbar?
4. Klicken Sie auf **✓ Genehmigen** oder **✗ Ablehnen**
5. Bei Ablehnung: Grund angeben
### Massenbearbeitung
Sie können mehrere Stundenzettel gleichzeitig bearbeiten:
1. Aktivieren Sie die Checkboxen
2. Klicken Sie auf **"Ausgewählte genehmigen"**
`
}
]
},
{
id: 'availability',
name: 'Verfügbarkeiten',
icon: '📅',
description: 'Einsatzbereitschaft verwalten',
articles: [
{
id: 'set-availability',
title: 'Verfügbarkeit melden',
icon: '🗓️',
content: `
## Verfügbarkeit melden
**Für Mitarbeiter**
### Warum Verfügbarkeit melden?
Damit Disponenten wissen, wann Sie einsetzbar sind, sollten Sie Ihre Verfügbarkeit regelmäßig aktualisieren.
### Verfügbarkeit eintragen
1. Gehen Sie zu **Verfügbarkeit**
2. Klicken Sie auf einen Tag im Kalender
3. Wählen Sie:
- ✅ **Verfügbar** Sie können eingesetzt werden
- ❌ **Nicht verfügbar** Sie sind verhindert
- 🕐 **Teilweise** Nur zu bestimmten Zeiten
4. Bei "Teilweise": Zeitfenster angeben
5. Speichern Sie die Eingabe
### Regelmäßige Muster
Sie können wiederkehrende Verfügbarkeiten einrichten:
1. Klicken Sie auf **"Muster erstellen"**
2. Wählen Sie die Wochentage
3. Geben Sie die Zeiten ein
4. Das Muster wird automatisch angewendet
`
},
{
id: 'view-availability',
title: 'Verfügbarkeiten einsehen',
icon: '👁️',
content: `
## Verfügbarkeiten einsehen
**Für Disponenten und Chefs**
### Team-Übersicht
1. Gehen Sie zu **Verfügbarkeit**
2. Wählen Sie **"Team-Ansicht"**
3. Sie sehen alle Mitarbeiter im Kalender
### Nach Datum filtern
- Klicken Sie auf ein Datum, um zu sehen, wer verfügbar ist
- Grün = verfügbar, Rot = nicht verfügbar, Gelb = teilweise
### Für Auftrag nutzen
Beim Erstellen eines Auftrags werden automatisch nur verfügbare Mitarbeiter vorgeschlagen.
`
}
]
},
{
id: 'partnerships',
name: 'Partnerschaften',
icon: '🤝',
description: 'Zusammenarbeit mit Subunternehmern',
articles: [
{
id: 'partnership-overview',
title: 'Übersicht',
icon: '📋',
content: `
## Partnerschaften in SeCu
Das Partnerschaftsmodul ermöglicht die Zusammenarbeit mit anderen Sicherheitsunternehmen.
### Anwendungsfälle
- **Subunternehmer einsetzen** Personal bei Partnerfirmen anfordern
- **Personal verleihen** Eigene Mitarbeiter an Partner ausleihen
- **Abrechnung** Stundenzettel und Rechnungen austauschen
### Beziehungsarten
**Auftraggeber** Sie beauftragen den Partner (Subunternehmer)
**Subunternehmer** Sie werden vom Partner beauftragt
**Bilateral** Beide Seiten können Aufträge teilen
### Voraussetzungen
- Beide Unternehmen müssen in SeCu registriert sein
- Partnerschaftsmodul muss aktiviert sein
`
},
{
id: 'create-partnership',
title: 'Partnerschaft anfragen',
icon: '',
content: `
## Partnerschaft anfragen
**Berechtigung:** Chef
### Neue Partnerschaft
1. Gehen Sie zu **Partnerschaften**
2. Klicken Sie auf **"+ Neue Partnerschaft"**
3. Suchen Sie das Partnerunternehmen
4. Wählen Sie die **Beziehungsart**:
- Auftraggeber (Sie beauftragen)
- Subunternehmer (Sie werden beauftragt)
- Bilateral (beidseitig)
5. Klicken Sie auf **"Anfrage senden"**
### Anfrage annehmen
Wenn Sie eine Anfrage erhalten:
1. Sie sehen eine Benachrichtigung
2. Prüfen Sie die Details
3. Klicken Sie auf **"Annehmen"** oder **"Ablehnen"**
> **Hinweis:** Nach Annahme können beide Seiten Aufträge teilen.
`
},
{
id: 'share-orders',
title: 'Aufträge teilen',
icon: '📤',
content: `
## Aufträge mit Partnern teilen
### Auftrag an Subunternehmer
1. Erstellen oder öffnen Sie einen Auftrag
2. Klicken Sie auf **"Mit Partner teilen"**
3. Wählen Sie den **Partner** aus
4. Geben Sie Details an:
- Benötigte Mitarbeiteranzahl
- Stundensatz (falls vereinbart)
5. Partner erhält Benachrichtigung
### Geteilte Aufträge verwalten
Geteilte Aufträge werden mit einem 🤝 Symbol markiert.
- **Blau**: Von Ihnen geteilt
- **Orange**: An Sie geteilt
### Stundenzettel vom Partner
Wenn der Partner Stundenzettel einreicht:
1. Sie erhalten eine Benachrichtigung
2. Prüfen Sie die Zeiten
3. Genehmigen oder lehnen Sie ab
4. Genehmigte Zeiten fließen in die Abrechnung
`
}
]
},
{
id: 'modules',
name: 'Module',
icon: '🧩',
description: 'Funktionen aktivieren/deaktivieren',
articles: [
{
id: 'module-overview',
title: 'Module verwalten',
icon: '⚙️',
content: `
## Module in SeCu
SeCu ist modular aufgebaut. Sie können Funktionen nach Bedarf aktivieren oder deaktivieren.
### Verfügbare Module
**Stundenzettel** Arbeitszeiterfassung
**Verfügbarkeit** Einsatzplanung
**Dokumente** Dateiverwaltung
**Partnerschaften** Subunternehmer-Management
**Abrechnung** Rechnungserstellung
### Modul aktivieren
1. Gehen Sie zu **Module** (nur für Chefs)
2. Finden Sie das gewünschte Modul
3. Klicken Sie auf den Schalter
4. Das Modul ist sofort verfügbar
### Modul deaktivieren
> **Achtung:** Beim Deaktivieren werden keine Daten gelöscht, aber die Funktionen sind nicht mehr zugänglich.
1. Klicken Sie auf den Schalter des aktiven Moduls
2. Bestätigen Sie die Deaktivierung
`
}
]
},
{
id: 'faq',
name: 'Häufige Fragen',
icon: '❓',
description: 'Antworten auf häufige Fragen',
articles: [
{
id: 'faq-general',
title: 'Allgemeine Fragen',
icon: '💬',
content: `
## Häufige Fragen
### Ich habe mein Passwort vergessen
1. Klicken Sie auf der Login-Seite auf **"Passwort vergessen"**
2. Geben Sie Ihre E-Mail-Adresse ein
3. Sie erhalten einen Link zum Zurücksetzen
---
### Kann ich mehrere Organisationen haben?
Nein, jeder Benutzer gehört zu genau einer Organisation. Für die Zusammenarbeit nutzen Sie das Partnerschaftsmodul.
---
### Werden meine Daten gesichert?
Ja, es werden regelmäßig automatische Backups erstellt. Bei Datenverlust kontaktieren Sie den Support.
---
### Wie kann ich Support kontaktieren?
- **E-Mail:** support@kronos-soulution.de
- **Telefon:** Siehe Ihre Vertragsdaten
---
### Gibt es eine Mobile App?
SeCu ist als Web-App optimiert und funktioniert auf allen Geräten. Eine native App ist in Planung.
`
}
]
}
]
// Simple markdown renderer
function renderMarkdown(text: string): string {
return text
// Headers
.replace(/^### (.+)$/gm, '<h3 class="text-lg font-semibold mt-6 mb-2 text-gray-900 dark:text-white">$1</h3>')
.replace(/^## (.+)$/gm, '<h2 class="text-xl font-bold mt-8 mb-4 text-gray-900 dark:text-white">$1</h2>')
// Bold
.replace(/\*\*(.+?)\*\*/g, '<strong class="font-semibold">$1</strong>')
// Italic
.replace(/\*(.+?)\*/g, '<em>$1</em>')
// Code
.replace(/`(.+?)`/g, '<code class="bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded text-sm">$1</code>')
// Blockquote
.replace(/^> (.+)$/gm, '<blockquote class="border-l-4 border-blue-500 pl-4 italic text-gray-600 dark:text-gray-400 my-4 bg-blue-50 dark:bg-blue-900/20 py-2 pr-4 rounded-r">$1</blockquote>')
// Horizontal rule
.replace(/^---$/gm, '<hr class="my-6 border-gray-200 dark:border-gray-700">')
// Lists
.replace(/^(\d+)\. (.+)$/gm, '<li class="ml-6 list-decimal my-1 text-gray-700 dark:text-gray-300">$2</li>')
.replace(/^- (.+)$/gm, '<li class="ml-6 list-disc my-1 text-gray-700 dark:text-gray-300">$1</li>')
// Wrap consecutive list items
.replace(/(<li class="ml-6 list-decimal[^>]*>.*<\/li>\n?)+/g, (match) => `<ol class="my-4">${match}</ol>`)
.replace(/(<li class="ml-6 list-disc[^>]*>.*<\/li>\n?)+/g, (match) => `<ul class="my-4">${match}</ul>`)
// Paragraphs (lines that don't start with HTML tags)
.split('\n\n')
.map(p => {
p = p.trim()
if (!p) return ''
if (p.startsWith('<')) return p
return `<p class="my-3 text-gray-700 dark:text-gray-300">${p}</p>`
})
.join('\n')
}
const filteredCategories = computed(() => {
if (!searchQuery.value) return categories
const query = searchQuery.value.toLowerCase()
return categories.map(cat => ({
...cat,
articles: cat.articles.filter(art =>
art.title.toLowerCase().includes(query) ||
art.content.toLowerCase().includes(query)
)
})).filter(cat => cat.articles.length > 0)
})
function selectCategory(catId: string) {
activeCategory.value = catId
activeArticle.value = null
}
function selectArticle(catId: string, artId: string) {
activeCategory.value = catId
activeArticle.value = artId
}
function goBack() {
if (activeArticle.value) {
activeArticle.value = null
} else {
activeCategory.value = null
}
}
const currentCategory = computed(() =>
categories.find(c => c.id === activeCategory.value)
)
const currentArticle = computed(() =>
currentCategory.value?.articles.find(a => a.id === activeArticle.value)
)
</script>
<template>
<div class="space-y-6">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<button
v-if="activeCategory"
@click="goBack"
class="p-2 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors text-xl"
>
</button>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
📚 Hilfe & Dokumentation
</h1>
</div>
</div>
<!-- Search -->
<div class="relative">
<input
v-model="searchQuery"
type="text"
placeholder="🔍 Suche in der Dokumentation..."
class="input pl-4 pr-10 w-full"
/>
<span
v-if="searchQuery"
@click="searchQuery = ''"
class="absolute right-3 top-1/2 -translate-y-1/2 cursor-pointer text-gray-400 hover:text-gray-600 text-lg"
>
</span>
</div>
<!-- Category Grid -->
<div v-if="!activeCategory" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="category in filteredCategories"
:key="category.id"
@click="selectCategory(category.id)"
class="card cursor-pointer hover:shadow-lg transition-all hover:scale-[1.02] border-2 border-transparent hover:border-blue-500"
>
<div class="text-3xl mb-3">{{ category.icon }}</div>
<h3 class="text-lg font-semibold mb-1 text-gray-900 dark:text-white">{{ category.name }}</h3>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ category.description }}</p>
<p class="text-xs text-gray-400 mt-2">{{ category.articles.length }} Artikel</p>
</div>
</div>
<!-- Article List -->
<div v-else-if="!activeArticle" class="space-y-4">
<div class="card bg-gray-50 dark:bg-gray-800">
<div class="flex items-center gap-3">
<span class="text-3xl">{{ currentCategory?.icon }}</span>
<div>
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">{{ currentCategory?.name }}</h2>
<p class="text-sm text-gray-500 dark:text-gray-400">{{ currentCategory?.description }}</p>
</div>
</div>
</div>
<div class="grid gap-3">
<div
v-for="article in currentCategory?.articles"
:key="article.id"
@click="selectArticle(currentCategory!.id, article.id)"
class="card cursor-pointer hover:shadow-md transition-all flex items-center gap-3 hover:bg-gray-50 dark:hover:bg-gray-700"
>
<span class="text-2xl">{{ article.icon }}</span>
<span class="font-medium text-gray-900 dark:text-white">{{ article.title }}</span>
<span class="ml-auto text-gray-400"></span>
</div>
</div>
</div>
<!-- Article Content -->
<div v-else class="card">
<div class="flex items-center gap-3 mb-6 pb-4 border-b dark:border-gray-700">
<span class="text-3xl">{{ currentArticle?.icon }}</span>
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">{{ currentArticle?.title }}</h2>
</div>
<div
class="prose dark:prose-invert max-w-none"
v-html="renderMarkdown(currentArticle?.content || '')"
></div>
</div>
</div>
</template>