Files
secu-frontend/src/views/DocumentsView.vue
OpenClaw 3ca75cc4f2 feat: Add all module frontend views
Views added:
- ShiftsView (Schichtplanung)
- PatrolsView (Wächterkontrolle)
- IncidentsView (Vorfallberichte)
- VehiclesView (Fahrzeuge)
- DocumentsView (Dokumente)
- CustomersView (Kunden/CRM)
- BillingView (Abrechnung)
- ObjectsView (enhanced with contacts, instructions)

Updated:
- Router with all new routes
- Sidebar with complete navigation
2026-03-12 21:23:01 +00:00

138 lines
5.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { api } from '@/api'
const loading = ref(true)
const documents = ref<any[]>([])
const categories = ref<any[]>([])
const pendingDocs = ref<any[]>([])
const showModal = ref(false)
const form = ref({ title: '', description: '', category_id: '', file_url: '', is_mandatory: false })
onMounted(async () => { await loadData() })
async function loadData() {
loading.value = true
try {
const [docRes, catRes, pendRes] = await Promise.all([
api.get<any>('/documents'),
api.get<any>('/documents/categories'),
api.get<any>('/documents/pending/list')
])
documents.value = docRes.data.documents || []
categories.value = catRes.data.categories || []
pendingDocs.value = pendRes.data.documents || []
} catch (e) { console.error(e) }
loading.value = false
}
async function acknowledge(docId: string) {
try {
await api.post(`/documents/${docId}/acknowledge`, {})
await loadData()
} catch (e: any) { alert('Fehler: ' + e.message) }
}
async function createDocument() {
try {
await api.post('/documents', form.value)
showModal.value = false
form.value = { title: '', description: '', category_id: '', file_url: '', is_mandatory: false }
await loadData()
} catch (e: any) { alert('Fehler: ' + e.message) }
}
</script>
<template>
<div class="p-6">
<div class="flex justify-between items-center mb-6">
<div>
<h1 class="text-2xl font-bold">📁 Dokumente</h1>
<p class="text-gray-500">Unterlagen & Bestätigungen</p>
</div>
<button @click="showModal = true" class="btn btn-primary">+ Dokument</button>
</div>
<!-- Pending Documents Alert -->
<div v-if="pendingDocs.length > 0" class="bg-yellow-50 border-l-4 border-yellow-400 p-4 mb-6">
<div class="flex">
<span class="text-yellow-600 text-xl mr-3"></span>
<div>
<h3 class="font-semibold text-yellow-800">{{ pendingDocs.length }} Dokument(e) zu bestätigen</h3>
<div class="mt-2 space-y-2">
<div v-for="doc in pendingDocs" :key="doc.id" class="flex items-center justify-between bg-white p-2 rounded">
<span>{{ doc.category_icon }} {{ doc.title }}</span>
<button @click="acknowledge(doc.id)" class="text-sm text-blue-600 hover:underline">Bestätigen</button>
</div>
</div>
</div>
</div>
</div>
<div v-if="loading" class="text-center py-12">Laden...</div>
<div v-else-if="documents.length === 0" class="bg-gray-50 rounded-lg p-12 text-center text-gray-500">
<p class="text-4xl mb-4">📄</p>
<p>Keine Dokumente vorhanden</p>
</div>
<div v-else class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
<div v-for="doc in documents" :key="doc.id" class="bg-white rounded-lg shadow p-4 hover:shadow-md transition-shadow">
<div class="flex items-start space-x-3">
<span class="text-2xl">{{ doc.category_icon || '📄' }}</span>
<div class="flex-1 min-w-0">
<h3 class="font-semibold truncate">{{ doc.title }}</h3>
<p class="text-sm text-gray-500">{{ doc.category_name }}</p>
<p v-if="doc.description" class="text-sm text-gray-400 mt-1 line-clamp-2">{{ doc.description }}</p>
</div>
</div>
<div class="mt-3 flex items-center justify-between text-xs">
<span v-if="doc.is_mandatory" class="px-2 py-1 bg-red-100 text-red-700 rounded">Pflicht</span>
<span v-if="doc.acknowledged" class="text-green-600"> Bestätigt</span>
<span v-else-if="doc.is_mandatory" class="text-orange-600">Ausstehend</span>
</div>
<a v-if="doc.file_url" :href="doc.file_url" target="_blank"
class="mt-3 block text-center text-sm text-blue-600 hover:underline">
📥 Herunterladen
</a>
</div>
</div>
<!-- Modal -->
<div v-if="showModal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div class="bg-white rounded-lg shadow-xl w-full max-w-md p-6">
<h2 class="text-xl font-bold mb-4">Neues Dokument</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium mb-1">Titel *</label>
<input v-model="form.title" class="input" />
</div>
<div>
<label class="block text-sm font-medium mb-1">Kategorie</label>
<select v-model="form.category_id" class="input">
<option value="">-- Wählen --</option>
<option v-for="c in categories" :key="c.id" :value="c.id">{{ c.icon }} {{ c.name }}</option>
</select>
</div>
<div>
<label class="block text-sm font-medium mb-1">Datei-URL</label>
<input v-model="form.file_url" class="input" placeholder="https://..." />
</div>
<div>
<label class="block text-sm font-medium mb-1">Beschreibung</label>
<textarea v-model="form.description" rows="2" class="input"></textarea>
</div>
<label class="flex items-center">
<input v-model="form.is_mandatory" type="checkbox" class="mr-2" />
<span class="text-sm">Pflichtdokument (Bestätigung erforderlich)</span>
</label>
</div>
<div class="flex justify-end space-x-2 mt-6">
<button @click="showModal = false" class="btn">Abbrechen</button>
<button @click="createDocument" class="btn btn-primary">Erstellen</button>
</div>
</div>
</div>
</div>
</template>