Added Frontend

This commit is contained in:
2026-01-06 12:09:31 +01:00
250 changed files with 29602 additions and 0 deletions

View File

@@ -0,0 +1,304 @@
<script setup>
import { v4 as uuidv4 } from 'uuid';
defineShortcuts({
'backspace': () => {
router.push("/projecttypes")
},
'arrowleft': () => {
if(openTab.value > 0){
openTab.value -= 1
}
},
'arrowright': () => {
if(openTab.value < 3) {
openTab.value += 1
}
},
})
const openTab = ref(0)
const route = useRoute()
const router = useRouter()
const toast = useToast()
const mode = ref(route.params.mode || "show")
const itemInfo = ref({
name: "",
initialPhases: [{ "key": "f31f6fcb-34d5-41a0-9b8f-6c85062f19be", "icon": "i-heroicons-clipboard-document", "label": "Erstkontakt", "active": true, "quickactions": [] }, { "key": "41995d1f-78fa-448b-b6ea-e206645ffb89", "icon": "i-heroicons-wrench-screwdriver", "label": "Umsetzung", "quickactions": [] }, { "key": "267e78ac-9eab-4736-b9c8-4b94c1724494", "icon": "i-heroicons-document-text", "label": "Rechnungsstellung", "quickactions": [] }, { "key": "038df888-53f2-4985-b08e-776ab82df5d3", "icon": "i-heroicons-check", "label": "Abgeschlossen", "quickactions": [] } ]
})
const oldItemInfo = ref({})
const openQuickActionModal = ref(false)
const selectedKeyForQuickAction = ref("")
const setKeys = () => {
itemInfo.value.initialPhases = itemInfo.value.initialPhases.map(i => {
return {
...i,
key: uuidv4(),
quickactions: i.quickactions || []
}
})
itemInfo.value.initialPhases[0].active = true
}
const setupPage = async() => {
if(mode.value === "show" ){
itemInfo.value = await useEntities("projecttypes").selectSingle(route.params.id,"*")
} else if (mode.value === "edit") {
itemInfo.value = await useEntities("projecttypes").selectSingle(route.params.id,"*")
}
if(mode.value === "create") {
let query = route.query
}
if(itemInfo.value) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value))
setKeys()
}
setupPage()
const addPhase = () => {
itemInfo.value.initialPhases.push({label: '', icon: ''}),
setKeys
}
</script>
<template>
<UDashboardNavbar :title="itemInfo ? itemInfo.name : (mode === 'create' ? 'Projekt erstellen' : 'Projekt bearbeiten')">
<template #left>
<UButton
icon="i-heroicons-chevron-left"
variant="outline"
@click="router.push(`/projecttypes`)"
>
Projekttypen
</UButton>
</template>
<template #center>
<h1
v-if="itemInfo"
class="text-xl font-medium"
>{{itemInfo.name ? `Projekttyp: ${itemInfo.name}` : (mode === 'create' ? 'Projekttyp erstellen' : 'Projekttyp bearbeiten')}}</h1>
</template>
<template #right>
<UButton
v-if="mode === 'edit'"
@click="useEntities('projecttypes').update(itemInfo.id, itemInfo)"
>
Speichern
</UButton>
<UButton
v-else-if="mode === 'create'"
@click="useEntities('projecttypes').create( itemInfo)"
>
Erstellen
</UButton>
<UButton
@click="router.push(itemInfo.id ? `/projecttypes/show/${itemInfo.id}` : `/projecttypes`)"
color="red"
class="ml-2"
v-if="mode === 'edit' || mode === 'create'"
>
Abbrechen
</UButton>
<UButton
v-if="mode === 'show'"
@click="router.push(`/projecttypes/edit/${itemInfo.id}`)"
>
Bearbeiten
</UButton>
</template>
</UDashboardNavbar>
<UDashboardPanelContent>
<UTabs
:items="[{label: 'Informationen'}]"
v-if="itemInfo.id && mode == 'show'"
v-model="openTab"
>
<template #item="{ item }">
<div v-if="item.label === 'Informationen'" class="flex flex-row">
<div class="w-1/2 mr-3">
<UCard class="mt-5">
{{itemInfo}}
</UCard>
</div>
<div class="w-1/2">
<UCard class="mt-5">
<HistoryDisplay
type="project"
v-if="itemInfo"
:element-id="itemInfo.id"
render-headline
/>
</UCard>
</div>
</div>
</template>
</UTabs>
<UForm v-else-if="mode === 'edit' || mode === 'create'">
<UAlert
color="rose"
variant="outline"
class="mb-5"
v-if="mode === 'edit'"
description="Achtung Änderungen an diesem Projekttypen betreffen nur Projekte die damit neu erstellt werden. Bestehende Projekte bleiben unverändert."
/>
<UFormGroup
label="Name:"
>
<UInput
v-model="itemInfo.name"
/>
</UFormGroup>
<UDivider class="mt-5">
Initiale Phasen
</UDivider>
<UButton
class="mt-3"
@click="addPhase"
>
+ Phase
</UButton>
<table class="mt-3">
<thead>
<tr>
<th></th>
<th class="text-left"><span class="ml-2">Name</span></th>
<th class="text-left"><span class="ml-2">Icon</span></th>
<th class="text-left"><span class="ml-2">Optional</span></th>
<th class="text-left"><span class="ml-2">Beschreibung</span></th>
<th class="text-left"><span class="ml-2">Schnellaktionen</span></th>
<th></th>
</tr>
</thead>
<draggable
v-model="itemInfo.initialPhases"
handle=".handle"
tag="tbody"
itemKey="pos"
@end="setKeys"
>
<template #item="{element: phase}">
<tr>
<td>
<UIcon
class="handle"
name="i-mdi-menu"
/>
</td>
<td>
<UInput
class="my-2 ml-2"
v-model="phase.label"
placeholder="Name"
/>
</td>
<td>
<UInput
class="my-2 ml-2"
v-model="phase.icon"
placeholder="Icon"
/>
</td>
<td>
<UCheckbox
class="my-2 ml-2"
v-model="phase.optional"
/>
</td>
<td>
<UInput
class="my-2 ml-2"
v-model="phase.description"
placeholder="Beschreibung"
/>
</td>
<td>
<UButton
class="my-2 ml-2"
variant="outline"
@click="openQuickActionModal = true,
selectedKeyForQuickAction = phase.key"
>+ Schnellaktion</UButton>
<UButton
@click="phase.quickactions = phase.quickactions.filter(i => i.label !== button.label)"
v-for="button in phase.quickactions"
class="ml-1"
>
{{ button.label }}
</UButton>
<UModal v-model="openQuickActionModal">
<UCard>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Schnellaktion hinzufügen
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="openQuickActionModal = false" />
</div>
<div class="flex flex-col">
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Angebot',link:'/createDocument/edit/?type=quotes'})">Angebot Erstellen</UButton>
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Auftrag',link:'/createDocument/edit/?type=confirmationOrders'})">Auftrag Erstellen</UButton>
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Lieferschein',link:'/createDocument/edit/?type=deliveryNotes'})">Lieferschein Erstellen</UButton>
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Rechnung',link:'/createDocument/edit/?type=invoices'})">Rechnung Erstellen</UButton>
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Aufgabe',link:'/tasks/create'})">Aufgabe Erstellen</UButton>
<UButton
class="my-1"
@click="itemInfo.initialPhases[itemInfo.initialPhases.findIndex(i=> i.key === selectedKeyForQuickAction)].quickactions.push({label:'+ Termin',link:'/events/edit'})">Termin Erstellen</UButton>
</div>
</UCard>
</UModal>
</td>
<td>
<UButton
class="my-2 ml-2"
variant="outline"
color="rose"
@click="itemInfo.initialPhases = itemInfo.initialPhases.filter(i => i !== phase)"
>X</UButton>
</td>
</tr>
</template>
</draggable>
</table>
</UForm>
</UDashboardPanelContent>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,107 @@
<script setup>
defineShortcuts({
'/': () => {
//console.log(searchinput)
//searchinput.value.focus()
document.getElementById("searchinput").focus()
},
'+': () => {
router.push("/projects/create")
},
'Enter': {
usingInput: true,
handler: () => {
router.push(`/projecttypes/show/${filteredRows.value[selectedItem.value].id}`)
}
},
'arrowdown': () => {
if (selectedItem.value < filteredRows.value.length - 1) {
selectedItem.value += 1
} else {
selectedItem.value = 0
}
},
'arrowup': () => {
if (selectedItem.value === 0) {
selectedItem.value = filteredRows.value.length - 1
} else {
selectedItem.value -= 1
}
}
})
const router = useRouter()
const tempStore = useTempStore()
const items = ref([])
const selectedItem = ref(0)
const setup = async () => {
items.value = await useEntities("projecttypes").select()
}
setup()
const templateColumns = [
{
key: "name",
label: "Name"
},
]
const selectedColumns = ref(templateColumns)
const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column)))
const searchString = ref(tempStore.searchStrings["projecttypes"] || '')
const filteredRows = computed(() => {
return useListFilter(searchString.value, items.value)
})
</script>
<template>
<UDashboardNavbar title="Projekttypen" :badge="filteredRows.length">
<template #right>
<UInput
id="searchinput"
v-model="searchString"
icon="i-heroicons-funnel"
autocomplete="off"
placeholder="Suche..."
class="hidden lg:block"
@keydown.esc="$event.target.blur()"
@change="tempStore.modifySearchString('projecttypes',searchString)"
>
<template #trailing>
<UKbd value="/"/>
</template>
</UInput>
<UButton @click="router.push(`/projecttypes/create`)">+ Projekttyp</UButton>
</template>
</UDashboardNavbar>
<UTable
:rows="filteredRows"
:columns="columns"
class="w-full"
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
@select="(i) => router.push(`/projecttypes/show/${i.id}`) "
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Projekttypen anzuzeigen' }"
>
<template #name-data="{row}">
<span class="text-primary-500 font-bold" v-if="row === filteredRows[selectedItem]">{{ row.name }}</span>
<span v-else>{{ row.name }}</span>
</template>
</UTable>
</template>
<style scoped>
</style>