Introduced New Projecttypes and Phase Display
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import HistoryDisplay from "~/components/HistoryDisplay.vue";
|
|
||||||
import DocumentUpload from "~/components/DocumentUpload.vue";
|
|
||||||
import DocumentList from "~/components/DocumentList.vue";
|
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
middleware: "auth"
|
middleware: "auth"
|
||||||
@@ -97,17 +95,18 @@ const itemInfo = ref({
|
|||||||
const oldItemInfo = ref({})
|
const oldItemInfo = ref({})
|
||||||
const tags = dataStore.getDocumentTags
|
const tags = dataStore.getDocumentTags
|
||||||
const phasesTemplates = ref([])
|
const phasesTemplates = ref([])
|
||||||
const phasesTemplateSelected = ref(null)
|
|
||||||
|
|
||||||
const plants = ref([])
|
const plants = ref([])
|
||||||
const contracts = ref([])
|
const contracts = ref([])
|
||||||
|
const projecttypes = ref([])
|
||||||
|
const disableCustomerSelection =ref(false)
|
||||||
|
|
||||||
|
|
||||||
//Functions
|
//Functions
|
||||||
const setupPage = async() => {
|
const setupPage = async() => {
|
||||||
plants.value = await useSupabaseSelect("plants")
|
plants.value = await useSupabaseSelect("plants")
|
||||||
contracts.value = await useSupabaseSelect("contracts")
|
contracts.value = await useSupabaseSelect("contracts")
|
||||||
|
projecttypes.value = await useSupabaseSelect("projecttypes", "*", "id")
|
||||||
|
|
||||||
if(mode.value === "show" ){
|
if(mode.value === "show" ){
|
||||||
itemInfo.value = await useSupabaseSelectSingle("projects",route.params.id,"*, customer(*), plant(*)")
|
itemInfo.value = await useSupabaseSelectSingle("projects",route.params.id,"*, customer(*), plant(*)")
|
||||||
@@ -127,12 +126,10 @@ const setupPage = async() => {
|
|||||||
}
|
}
|
||||||
if(itemInfo.value) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value))
|
if(itemInfo.value) oldItemInfo.value = JSON.parse(JSON.stringify(itemInfo.value))
|
||||||
|
|
||||||
phasesTemplates.value = await useSupabaseSelect("phasesTemplates","*","created_at")
|
if(!oldItemInfo.value.projecttype) {
|
||||||
if(phasesTemplates.value.length > 0) {
|
itemInfo.value.projecttype = projecttypes.value[0].id
|
||||||
phasesTemplateSelected.value = phasesTemplates.value[0].id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupPage()
|
setupPage()
|
||||||
@@ -155,53 +152,65 @@ const projectHours = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*const phasesTemplate = ref([{
|
|
||||||
label: 'Erstkontakt',
|
|
||||||
icon: 'i-heroicons-clipboard-document',
|
|
||||||
active: true
|
|
||||||
}, {
|
|
||||||
label: 'Überprüfung Vor Ort',
|
|
||||||
icon: 'i-heroicons-magnifying-glass'
|
|
||||||
}, {
|
|
||||||
label: 'Angebotserstellung',
|
|
||||||
icon: 'i-heroicons-document-text'
|
|
||||||
}, {
|
|
||||||
label: 'Auftragsvergabe',
|
|
||||||
icon: 'i-heroicons-document-check'
|
|
||||||
}, {
|
|
||||||
label: 'Umsetzung',
|
|
||||||
icon: 'i-heroicons-wrench-screwdriver'
|
|
||||||
},{
|
|
||||||
label: 'Rechnungsstellung',
|
|
||||||
icon: 'i-heroicons-document-text'
|
|
||||||
}, {
|
|
||||||
label: 'Abgeschlossen',
|
|
||||||
icon: 'i-heroicons-check'
|
|
||||||
}])*/
|
|
||||||
const changeActivePhase = async (phase) => {
|
|
||||||
itemInfo.value = await useSupabaseSelectSingle("projects",route.params.id,'*')
|
|
||||||
|
|
||||||
itemInfo.value.phases = itemInfo.value.phases.map(p => {
|
const createProject = async () => {
|
||||||
if(p.active) delete p.active
|
let initialPhases = projecttypes.value.find(i => i.id === itemInfo.value.projecttype).initialPhases
|
||||||
|
await dataStore.createNewItem('projects',{...itemInfo.value, phases: initialPhases })
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeActivePhase = async (key) => {
|
||||||
|
console.log(key)
|
||||||
|
let item = await useSupabaseSelectSingle("projects",itemInfo.value.id,'*')
|
||||||
|
|
||||||
|
item.phases = item.phases.map(p => {
|
||||||
|
if(p.active) p.active = false
|
||||||
|
|
||||||
|
if(p.key === key) {
|
||||||
|
p.active = true
|
||||||
|
p.activated_at = dayjs().format()
|
||||||
|
p.activated_by = dataStore.activeProfile.id
|
||||||
|
}
|
||||||
|
|
||||||
if(p.label === phase.label) p.active = true
|
|
||||||
|
|
||||||
return p
|
return p
|
||||||
})
|
})
|
||||||
|
|
||||||
await savePhases()
|
console.log(item.phases)
|
||||||
|
|
||||||
|
await dataStore.updateItem("projects", item)
|
||||||
setupPage()
|
setupPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
const savePhases = () => {
|
|
||||||
dataStore.updateItem("projects", itemInfo.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadPhases = async () => {
|
const renderedPhases = computed(() => {
|
||||||
itemInfo.value.phases = dataStore.phasesTemplates.find(i => i.id === phasesTemplateSelected.value).initialPhases
|
|
||||||
await dataStore.updateItem("projects", {...itemInfo.value, customer: itemInfo.value.customer ? itemInfo.value.customer.id : null, plant: itemInfo.value.plant ? itemInfo.value.plant.id : null})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(itemInfo.value.phases) {
|
||||||
|
return itemInfo.value.phases.map((phase,index,array) => {
|
||||||
|
|
||||||
|
let isAvailable = false
|
||||||
|
|
||||||
|
if(phase.active) {
|
||||||
|
isAvailable = true
|
||||||
|
} else if(index > 0 && array[index-1].active ){
|
||||||
|
isAvailable = true
|
||||||
|
} else if(index > 1 && array[index-1].optional && array[index-2].active){
|
||||||
|
isAvailable = true
|
||||||
|
} else if(array.findIndex(i => i.active) > index) {
|
||||||
|
isAvailable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
...phase,
|
||||||
|
label: phase.optional ? `${phase.label}(optional)`: phase.label,
|
||||||
|
disabled: !isAvailable,
|
||||||
|
defaultOpen: phase.active ? true : false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -231,7 +240,7 @@ const loadPhases = async () => {
|
|||||||
</UButton>
|
</UButton>
|
||||||
<UButton
|
<UButton
|
||||||
v-else-if="mode === 'create'"
|
v-else-if="mode === 'create'"
|
||||||
@click="dataStore.createNewItem('projects',itemInfo)"
|
@click="createProject"
|
||||||
>
|
>
|
||||||
Erstellen
|
Erstellen
|
||||||
</UButton>
|
</UButton>
|
||||||
@@ -294,37 +303,15 @@ const loadPhases = async () => {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="item.key === 'phases'" class="space-y-3">
|
<div v-if="item.key === 'phases'" class="space-y-3">
|
||||||
<UCard class="mt-5">
|
<UCard class="mt-5">
|
||||||
<UFormGroup
|
|
||||||
label="Vorlage laden"
|
|
||||||
v-if="itemInfo.phases.length === 0"
|
|
||||||
>
|
|
||||||
<InputGroup>
|
|
||||||
<USelectMenu
|
|
||||||
:options="phasesTemplates"
|
|
||||||
option-attribute="name"
|
|
||||||
value-attribute="id"
|
|
||||||
v-model="phasesTemplateSelected"
|
|
||||||
class="flex-auto"
|
|
||||||
>
|
|
||||||
|
|
||||||
</USelectMenu>
|
|
||||||
<UButton
|
|
||||||
@click="loadPhases"
|
|
||||||
>
|
|
||||||
Vorlage laden
|
|
||||||
</UButton>
|
|
||||||
</InputGroup>
|
|
||||||
|
|
||||||
</UFormGroup>
|
|
||||||
|
|
||||||
<UAccordion
|
<UAccordion
|
||||||
:items="itemInfo.phases"
|
:items="renderedPhases"
|
||||||
>
|
>
|
||||||
<template #default="{item,index,open}">
|
<template #default="{item,index,open}">
|
||||||
<UButton
|
<UButton
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
:color="item.active ? 'primary' : 'white'"
|
:color="item.active ? 'primary' : 'white'"
|
||||||
class="mb-1"
|
class="mb-1"
|
||||||
|
:disabled="true"
|
||||||
>
|
>
|
||||||
<template #leading>
|
<template #leading>
|
||||||
<div class="w-6 h-6 flex items-center justify-center -my-1">
|
<div class="w-6 h-6 flex items-center justify-center -my-1">
|
||||||
@@ -344,15 +331,35 @@ const loadPhases = async () => {
|
|||||||
|
|
||||||
</UButton>
|
</UButton>
|
||||||
</template>
|
</template>
|
||||||
<template #item="{item}">
|
<template #item="{item, index}">
|
||||||
<InputGroup>
|
<UCard class="mx-5">
|
||||||
<UButton
|
<template #header>
|
||||||
v-if="!item.active"
|
<span class="text-black">{{item.label}}</span>
|
||||||
@click="changeActivePhase(item)"
|
</template>
|
||||||
>
|
<InputGroup>
|
||||||
Phase aktivieren
|
<UButton
|
||||||
</UButton>
|
v-if="!item.activated_at && index !== 0 "
|
||||||
</InputGroup>
|
@click="changeActivePhase(item.key)"
|
||||||
|
>
|
||||||
|
Phase aktivieren
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-if="item.active"
|
||||||
|
v-for="button in item.quickactions"
|
||||||
|
@click="router.push(`${button.link}&customer=${itemInfo.customer.id}&project=${itemInfo.id}`)"
|
||||||
|
>
|
||||||
|
{{button.label}}
|
||||||
|
</UButton>
|
||||||
|
</InputGroup>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<p v-if="item.activated_at" class="text-black">Aktiviert am: {{dayjs(item.activated_at).format("DD.MM.YY HH:mm")}} Uhr</p>
|
||||||
|
<p v-if="item.activated_by" class="text-black">Aktiviert durch: {{dataStore.getProfileById(item.activated_by).fullName}}</p>
|
||||||
|
<p v-if="item.description" class="text-black">Beschreibung: {{item.description}}</p>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
</UAccordion>
|
</UAccordion>
|
||||||
</UCard>
|
</UCard>
|
||||||
@@ -490,23 +497,7 @@ const loadPhases = async () => {
|
|||||||
</UCard>
|
</UCard>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="item.key === 'material'" class="space-y-3">
|
<div v-else-if="item.key === 'material'" class="space-y-3">
|
||||||
<UCard class="mt-5">
|
|
||||||
Auf das Projekt gebuchte Artikel:
|
|
||||||
|
|
||||||
<!-- <UTable
|
|
||||||
:rows="dataStore.getStocksByProjectId(itemInfo.id)"
|
|
||||||
:columns="[{key:'productId',label:'Artikel'},{key:'stock',label:'Anzahl'}]"
|
|
||||||
@select="(i) => router.push(`/products/show/${i.productId}`)"
|
|
||||||
>
|
|
||||||
<template #productId-data="{row}">
|
|
||||||
{{dataStore.getProductById(row.productId).name}}
|
|
||||||
</template>
|
|
||||||
<template #stock-data="{row}">
|
|
||||||
{{dataStore.getProductById(row.productId)}}
|
|
||||||
{{row.stock}} {{dataStore.units.find(i => i.id === dataStore.getProductById(row.productId).unit).short}}
|
|
||||||
</template>
|
|
||||||
</UTable>-->
|
|
||||||
</UCard>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
@@ -532,6 +523,43 @@ const loadPhases = async () => {
|
|||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Objekt:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.plant"
|
||||||
|
:options="itemInfo.customer ? plants.filter(i => i.customer === itemInfo.customer) : plants"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable
|
||||||
|
:search-attributes="['name']"
|
||||||
|
@change="itemInfo.customer = plants.find(i => i.id === itemInfo.plant).customer,
|
||||||
|
disableCustomerSelection = true"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{plants.find(i => i.id === itemInfo.plant) ? plants.find(i => i.id === itemInfo.plant).name : "Objekt auswählen"}}
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
<UFormGroup
|
||||||
|
label="Vertrag:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.contract"
|
||||||
|
:options="itemInfo.customer ? contracts.filter(i => i.customer === itemInfo.customer) : contracts"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable
|
||||||
|
:search-attributes="['name']"
|
||||||
|
@change="itemInfo.customer = contracts.find(i => i.id === itemInfo.contract).customer,
|
||||||
|
disableCustomerSelection = true"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
{{contracts.find(i => i.id === itemInfo.contract) ? contracts.find(i => i.id === itemInfo.contract).name : "Vertrag auswählen"}}
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="Kundennummer:"
|
label="Kundennummer:"
|
||||||
>
|
>
|
||||||
@@ -542,6 +570,7 @@ const loadPhases = async () => {
|
|||||||
value-attribute="id"
|
value-attribute="id"
|
||||||
searchable
|
searchable
|
||||||
:search-attributes="['name']"
|
:search-attributes="['name']"
|
||||||
|
:disabled="disableCustomerSelection"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
{{dataStore.getCustomerById(itemInfo.customer) ? dataStore.getCustomerById(itemInfo.customer).name : "Kunde auswählen"}}
|
{{dataStore.getCustomerById(itemInfo.customer) ? dataStore.getCustomerById(itemInfo.customer).name : "Kunde auswählen"}}
|
||||||
@@ -549,6 +578,21 @@ const loadPhases = async () => {
|
|||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
|
<UFormGroup
|
||||||
|
label="Typ:"
|
||||||
|
>
|
||||||
|
<USelectMenu
|
||||||
|
v-model="itemInfo.projecttype"
|
||||||
|
:options="projecttypes"
|
||||||
|
option-attribute="name"
|
||||||
|
value-attribute="id"
|
||||||
|
searchable
|
||||||
|
:search-attributes="['label']"
|
||||||
|
:disabled="oldItemInfo.projecttype"
|
||||||
|
>
|
||||||
|
</USelectMenu>
|
||||||
|
</UFormGroup>
|
||||||
|
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="Gewerk:"
|
label="Gewerk:"
|
||||||
>
|
>
|
||||||
@@ -564,38 +608,7 @@ const loadPhases = async () => {
|
|||||||
</USelectMenu>
|
</USelectMenu>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
<UFormGroup
|
|
||||||
label="Objekt:"
|
|
||||||
>
|
|
||||||
<USelectMenu
|
|
||||||
v-model="itemInfo.plant"
|
|
||||||
:options="plants"
|
|
||||||
option-attribute="name"
|
|
||||||
value-attribute="id"
|
|
||||||
searchable
|
|
||||||
:search-attributes="['name']"
|
|
||||||
>
|
|
||||||
<template #label>
|
|
||||||
{{plants.find(i => i.id === itemInfo.plant) ? plants.find(i => i.id === itemInfo.plant).name : "Objekt auswählen"}}
|
|
||||||
</template>
|
|
||||||
</USelectMenu>
|
|
||||||
</UFormGroup>
|
|
||||||
<UFormGroup
|
|
||||||
label="Vertrag:"
|
|
||||||
>
|
|
||||||
<USelectMenu
|
|
||||||
v-model="itemInfo.contract"
|
|
||||||
:options="contracts"
|
|
||||||
option-attribute="name"
|
|
||||||
value-attribute="id"
|
|
||||||
searchable
|
|
||||||
:search-attributes="['name']"
|
|
||||||
>
|
|
||||||
<template #label>
|
|
||||||
{{contracts.find(i => i.id === itemInfo.contract) ? contracts.find(i => i.id === itemInfo.contract).name : "Vertrag auswählen"}}
|
|
||||||
</template>
|
|
||||||
</USelectMenu>
|
|
||||||
</UFormGroup>
|
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="Beteiligte Benutzer:"
|
label="Beteiligte Benutzer:"
|
||||||
>
|
>
|
||||||
@@ -615,13 +628,14 @@ const loadPhases = async () => {
|
|||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
|
|
||||||
<UFormGroup
|
<UFormGroup
|
||||||
label="Notizen:"
|
label="Notizen:"
|
||||||
>
|
>
|
||||||
<UTextarea
|
<UTextarea
|
||||||
v-model="itemInfo.notes"
|
v-model="itemInfo.notes"
|
||||||
/>
|
/>
|
||||||
</UFormGroup>
|
</UFormGroup>
|
||||||
</UForm>
|
</UForm>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -26,7 +26,20 @@
|
|||||||
<UCheckbox
|
<UCheckbox
|
||||||
label="Abgeschlossene anzeigen"
|
label="Abgeschlossene anzeigen"
|
||||||
v-model="showFinished"
|
v-model="showFinished"
|
||||||
|
class="mt-1"
|
||||||
/>
|
/>
|
||||||
|
<USelectMenu
|
||||||
|
class="ml-3 w-36"
|
||||||
|
v-model="selectedTypes"
|
||||||
|
:options="projecttypes"
|
||||||
|
value-attribute="id"
|
||||||
|
option-attribute="name"
|
||||||
|
multiple
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
Typen
|
||||||
|
</template>
|
||||||
|
</USelectMenu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #right>
|
<template #right>
|
||||||
@@ -60,6 +73,9 @@
|
|||||||
<span class="text-primary-500 font-bold" v-if="row === filteredRows[selectedItem]">{{row.name}}</span>
|
<span class="text-primary-500 font-bold" v-if="row === filteredRows[selectedItem]">{{row.name}}</span>
|
||||||
<span v-else>{{row.name}}</span>
|
<span v-else>{{row.name}}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template #projecttype-data="{row}">
|
||||||
|
{{row.projecttype.name}}
|
||||||
|
</template>
|
||||||
<template #phase-data="{row}">
|
<template #phase-data="{row}">
|
||||||
{{getActivePhaseLabel(row)}}
|
{{getActivePhaseLabel(row)}}
|
||||||
</template>
|
</template>
|
||||||
@@ -117,9 +133,13 @@ const router = useRouter()
|
|||||||
|
|
||||||
const items = ref([])
|
const items = ref([])
|
||||||
const selectedItem = ref(0)
|
const selectedItem = ref(0)
|
||||||
|
const projecttypes = ref([])
|
||||||
|
const selectedTypes = ref([])
|
||||||
|
|
||||||
const setupPage = async () => {
|
const setupPage = async () => {
|
||||||
items.value = await useSupabaseSelect("projects","*, customer (name), plant(name)","projectNumber")
|
items.value = await useSupabaseSelect("projects","*, customer (name), plant(name), projecttype(name, id)","projectNumber")
|
||||||
|
projecttypes.value = await useSupabaseSelect("projecttypes","*")
|
||||||
|
selectedTypes.value = projecttypes.value.map(i => i.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupPage()
|
setupPage()
|
||||||
@@ -129,6 +149,10 @@ const templateColumns = [
|
|||||||
key: "projectNumber",
|
key: "projectNumber",
|
||||||
label: "Projektnummer"
|
label: "Projektnummer"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "projecttype",
|
||||||
|
label: "Typ"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "phase",
|
key: "phase",
|
||||||
label: "Phase"
|
label: "Phase"
|
||||||
@@ -198,10 +222,11 @@ const filteredRows = computed(() => {
|
|||||||
temp = temp.filter(i => i.phaseLabel !== "Abgeschlossen")
|
temp = temp.filter(i => i.phaseLabel !== "Abgeschlossen")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
temp = temp.filter(i => selectedTypes.value.includes(i.projecttype.id))
|
||||||
|
|
||||||
if(!searchString.value) {
|
if(!searchString.value) {
|
||||||
return temp
|
return temp
|
||||||
}
|
}
|
||||||
|
|
||||||
return useSearch(searchString.value, temp)
|
return useSearch(searchString.value, temp)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
292
pages/projecttypes/[mode]/[[id]].vue
Normal file
292
pages/projecttypes/[mode]/[[id]].vue
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
<script setup>
|
||||||
|
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
definePageMeta({
|
||||||
|
middleware: "auth"
|
||||||
|
})
|
||||||
|
|
||||||
|
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 dataStore = useDataStore()
|
||||||
|
const supabase = useSupabaseClient()
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
|
const mode = ref(route.params.mode || "show")
|
||||||
|
const itemInfo = ref({
|
||||||
|
name: "",
|
||||||
|
initialPhases: []
|
||||||
|
})
|
||||||
|
const oldItemInfo = ref({})
|
||||||
|
|
||||||
|
const openQuickActionModal = ref(false)
|
||||||
|
const selectedKeyForQuickAction = ref("")
|
||||||
|
|
||||||
|
const setupPage = async() => {
|
||||||
|
|
||||||
|
if(mode.value === "show" ){
|
||||||
|
itemInfo.value = await useSupabaseSelectSingle("projecttypes",route.params.id,"*")
|
||||||
|
} else if (mode.value === "edit") {
|
||||||
|
itemInfo.value = await useSupabaseSelectSingle("projecttypes",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 setKeys = () => {
|
||||||
|
itemInfo.value.initialPhases = itemInfo.value.initialPhases.map(i => {
|
||||||
|
return {
|
||||||
|
...i,
|
||||||
|
key: uuidv4(),
|
||||||
|
quickactions: i.quickactions || []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
</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="dataStore.updateItem('projecttypes',itemInfo,oldItemInfo)"
|
||||||
|
>
|
||||||
|
Speichern
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-else-if="mode === 'create'"
|
||||||
|
@click="dataStore.createNewItem('projecttyes', 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"
|
||||||
|
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="itemInfo.initialPhases.push({label: '', icon: ''}),
|
||||||
|
setKeys"
|
||||||
|
>
|
||||||
|
+ Phase
|
||||||
|
</UButton>
|
||||||
|
|
||||||
|
<table class="mt-3">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Icon</th>
|
||||||
|
<th>Optional</th>
|
||||||
|
<th>Beschreibung</th>
|
||||||
|
<th>Schnellaktionen</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"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<UInput
|
||||||
|
class="my-2 ml-2"
|
||||||
|
v-model="phase.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"
|
||||||
|
/>
|
||||||
|
</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:'+ 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>
|
||||||
108
pages/projecttypes/index.vue
Normal file
108
pages/projecttypes/index.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<script setup>
|
||||||
|
definePageMeta({
|
||||||
|
middleware: "auth"
|
||||||
|
})
|
||||||
|
|
||||||
|
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 items = ref([])
|
||||||
|
const selectedItem = ref(0)
|
||||||
|
|
||||||
|
|
||||||
|
const setup = async () => {
|
||||||
|
items.value = await useSupabaseSelect("projecttypes","*")
|
||||||
|
}
|
||||||
|
|
||||||
|
setup()
|
||||||
|
|
||||||
|
const templateColumns = [
|
||||||
|
{
|
||||||
|
key: "name",
|
||||||
|
label: "Name"
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
const selectedColumns = ref(templateColumns)
|
||||||
|
const columns = computed(() => templateColumns.filter((column) => selectedColumns.value.includes(column)))
|
||||||
|
|
||||||
|
const searchString = ref("")
|
||||||
|
|
||||||
|
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()"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
@@ -155,6 +155,12 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
labelSingle: "Fahrt",
|
labelSingle: "Fahrt",
|
||||||
redirect: true,
|
redirect: true,
|
||||||
historyItemHolder: "trackingtrip",
|
historyItemHolder: "trackingtrip",
|
||||||
|
},
|
||||||
|
projecttypes: {
|
||||||
|
label: "Projekttypen",
|
||||||
|
labelSingle: "Projekttyp",
|
||||||
|
redirect: true,
|
||||||
|
historyItemHolder: "projecttype"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,6 +693,12 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
name = "Wöchentliche Arbeitszeit"
|
name = "Wöchentliche Arbeitszeit"
|
||||||
} else if(key === "licensePlate") {
|
} else if(key === "licensePlate") {
|
||||||
name = "Kennzeichen"
|
name = "Kennzeichen"
|
||||||
|
}else if(key === "towingCapacity") {
|
||||||
|
name = "Anhängelast"
|
||||||
|
}else if(key === "color") {
|
||||||
|
name = "Farbe"
|
||||||
|
}else if(key === "powerInKW") {
|
||||||
|
name = "Leistung"
|
||||||
} else if(key === "driver") {
|
} else if(key === "driver") {
|
||||||
name = "Fahrer"
|
name = "Fahrer"
|
||||||
if(prop.data.o) oldVal = profiles.value.find(i => i.id === prop.data.o).fullName
|
if(prop.data.o) oldVal = profiles.value.find(i => i.id === prop.data.o).fullName
|
||||||
@@ -1193,6 +1205,10 @@ export const useDataStore = defineStore('data', () => {
|
|||||||
return documents.value.filter(item => item.project === projectId && !item.tags.includes("Archiviert"))
|
return documents.value.filter(item => item.project === projectId && !item.tags.includes("Archiviert"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const getDocumentsByProfileId = computed(() => (profileId) => {
|
||||||
|
return documents.value.filter(item => item.profile === profileId && !item.tags.includes("Archiviert"))
|
||||||
|
})
|
||||||
|
|
||||||
const getDocumentsByPlantId = computed(() => (itemId) => {
|
const getDocumentsByPlantId = computed(() => (itemId) => {
|
||||||
return documents.value.filter(item => item.plant === itemId && !item.tags.includes("Archiviert"))
|
return documents.value.filter(item => item.plant === itemId && !item.tags.includes("Archiviert"))
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user