This commit is contained in:
2026-02-21 22:41:07 +01:00
parent 27be8241bf
commit 724f152d70

View File

@@ -142,13 +142,6 @@ function getAssigneeLabel(task) {
return assigneeOptions.value.find((option) => option.value === assigneeId)?.label || "-" return assigneeOptions.value.find((option) => option.value === assigneeId)?.label || "-"
} }
function getStatusBadgeColor(status) {
const normalized = normalizeStatus(status)
if (normalized === "Offen") return "gray"
if (normalized === "In Bearbeitung") return "amber"
return "green"
}
async function loadTasks() { async function loadTasks() {
loading.value = true loading.value = true
try { try {
@@ -368,7 +361,6 @@ onMounted(async () => {
/> />
<UButton <UButton
icon="i-heroicons-arrow-path" icon="i-heroicons-arrow-path"
color="gray"
variant="soft" variant="soft"
:loading="loading" :loading="loading"
@click="loadTasks" @click="loadTasks"
@@ -391,15 +383,15 @@ onMounted(async () => {
v-model="showOnlyMine" v-model="showOnlyMine"
label="Nur meine Aufgaben" label="Nur meine Aufgaben"
/> />
<span v-else class="text-sm text-gray-500">Ansicht: Nur eigene Aufgaben</span> <span v-else class="text-sm">Ansicht: Nur eigene Aufgaben</span>
</template> </template>
<template #right> <template #right>
<div class="flex items-center gap-1 rounded-lg border border-gray-200 p-1 dark:border-gray-700"> <div class="view-toggle">
<UButton <UButton
size="xs" size="xs"
variant="ghost" variant="ghost"
icon="i-heroicons-view-columns" icon="i-heroicons-view-columns"
:color="viewMode === 'kanban' ? 'primary' : 'gray'" :variant="viewMode === 'kanban' ? 'solid' : 'ghost'"
@click="viewMode = 'kanban'" @click="viewMode = 'kanban'"
> >
Kanban Kanban
@@ -408,7 +400,7 @@ onMounted(async () => {
size="xs" size="xs"
variant="ghost" variant="ghost"
icon="i-heroicons-list-bullet" icon="i-heroicons-list-bullet"
:color="viewMode === 'list' ? 'primary' : 'gray'" :variant="viewMode === 'list' ? 'solid' : 'ghost'"
@click="viewMode = 'list'" @click="viewMode = 'list'"
> >
Liste Liste
@@ -429,7 +421,7 @@ onMounted(async () => {
> >
<header class="kanban-column-header"> <header class="kanban-column-header">
<h3>{{ status }}</h3> <h3>{{ status }}</h3>
<UBadge color="gray" variant="subtle">{{ groupedTasks[status]?.length || 0 }}</UBadge> <UBadge variant="subtle">{{ groupedTasks[status]?.length || 0 }}</UBadge>
</header> </header>
<div :class="['kanban-dropzone', droppingOn === status ? 'kanban-dropzone-active' : '']"> <div :class="['kanban-dropzone', droppingOn === status ? 'kanban-dropzone-active' : '']">
@@ -445,13 +437,13 @@ onMounted(async () => {
<p v-if="task.description" class="kanban-card-description">{{ task.description }}</p> <p v-if="task.description" class="kanban-card-description">{{ task.description }}</p>
<div class="kanban-card-meta"> <div class="kanban-card-meta">
<UBadge v-if="getEntityLabel(projectOptions, task.project?.id || task.project)" color="primary" variant="soft"> <UBadge v-if="getEntityLabel(projectOptions, task.project?.id || task.project)" variant="soft">
{{ getEntityLabel(projectOptions, task.project?.id || task.project) }} {{ getEntityLabel(projectOptions, task.project?.id || task.project) }}
</UBadge> </UBadge>
<UBadge v-if="getEntityLabel(customerOptions, task.customer?.id || task.customer)" color="gray" variant="soft"> <UBadge v-if="getEntityLabel(customerOptions, task.customer?.id || task.customer)" variant="soft">
{{ getEntityLabel(customerOptions, task.customer?.id || task.customer) }} {{ getEntityLabel(customerOptions, task.customer?.id || task.customer) }}
</UBadge> </UBadge>
<UBadge v-if="getEntityLabel(plantOptions, task.plant?.id || task.plant)" color="gray" variant="soft"> <UBadge v-if="getEntityLabel(plantOptions, task.plant?.id || task.plant)" variant="soft">
{{ getEntityLabel(plantOptions, task.plant?.id || task.plant) }} {{ getEntityLabel(plantOptions, task.plant?.id || task.plant) }}
</UBadge> </UBadge>
</div> </div>
@@ -464,17 +456,15 @@ onMounted(async () => {
</section> </section>
</div> </div>
<UTable <UTable
v-else v-else-if="filteredTasks.length"
:rows="filteredTasks" :rows="filteredTasks"
:columns="listColumns" :columns="listColumns"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Aufgaben anzuzeigen' }"
@select="(task) => openTaskViaRoute(task)" @select="(task) => openTaskViaRoute(task)"
> >
<template #actions-data="{ row }"> <template #actions-data="{ row }">
<UButton <UButton
v-if="normalizeStatus(row.categorie) !== 'Abgeschlossen' && canCreate" v-if="normalizeStatus(row.categorie) !== 'Abgeschlossen' && canCreate"
size="xs" size="xs"
color="green"
variant="soft" variant="soft"
icon="i-heroicons-check" icon="i-heroicons-check"
:loading="quickCompleteLoadingId === row.id" :loading="quickCompleteLoadingId === row.id"
@@ -484,9 +474,7 @@ onMounted(async () => {
</UButton> </UButton>
</template> </template>
<template #categorie-data="{ row }"> <template #categorie-data="{ row }">
<UBadge :color="getStatusBadgeColor(row.categorie)" variant="soft"> <UBadge variant="soft">{{ normalizeStatus(row.categorie) }}</UBadge>
{{ normalizeStatus(row.categorie) }}
</UBadge>
</template> </template>
<template #assignee-data="{ row }"> <template #assignee-data="{ row }">
{{ getAssigneeLabel(row) }} {{ getAssigneeLabel(row) }}
@@ -501,6 +489,12 @@ onMounted(async () => {
{{ getEntityLabel(plantOptions, row.plant?.id || row.plant) || "-" }} {{ getEntityLabel(plantOptions, row.plant?.id || row.plant) || "-" }}
</template> </template>
</UTable> </UTable>
<UAlert
v-else
icon="i-heroicons-circle-stack-20-solid"
title="Keine Aufgaben anzuzeigen"
variant="subtle"
/>
</UDashboardPanelContent> </UDashboardPanelContent>
<UModal v-model="isModalOpen" :prevent-close="saving || deleting"> <UModal v-model="isModalOpen" :prevent-close="saving || deleting">
@@ -508,7 +502,7 @@ onMounted(async () => {
<template #header> <template #header>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h3 class="font-semibold">{{ modalTitle }}</h3> <h3 class="font-semibold">{{ modalTitle }}</h3>
<UBadge color="gray" variant="subtle">{{ taskForm.id ? `#${taskForm.id}` : "Neu" }}</UBadge> <UBadge variant="subtle">{{ taskForm.id ? `#${taskForm.id}` : "Neu" }}</UBadge>
</div> </div>
</template> </template>
@@ -595,7 +589,6 @@ onMounted(async () => {
<div class="flex gap-2"> <div class="flex gap-2">
<UButton <UButton
v-if="taskForm.id && canCreate" v-if="taskForm.id && canCreate"
color="red"
variant="soft" variant="soft"
:loading="deleting" :loading="deleting"
@click="archiveTask" @click="archiveTask"
@@ -605,10 +598,9 @@ onMounted(async () => {
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<UButton color="gray" variant="ghost" @click="closeModal">Schließen</UButton> <UButton variant="ghost" @click="closeModal">Schließen</UButton>
<UButton <UButton
v-if="modalMode === 'show' && canCreate" v-if="modalMode === 'show' && canCreate"
color="gray"
variant="soft" variant="soft"
@click="modalMode = 'edit'" @click="modalMode = 'edit'"
> >
@@ -632,7 +624,8 @@ onMounted(async () => {
.kanban-grid { .kanban-grid {
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 1rem; gap: 1.25rem;
align-items: start;
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
@@ -642,38 +635,56 @@ onMounted(async () => {
} }
.kanban-column { .kanban-column {
border: 1px solid rgb(229 231 235); border: 1px solid var(--ui-border);
border-radius: 0.75rem; border-radius: 0.75rem;
background: rgb(249 250 251); background: var(--ui-bg);
min-height: 500px; min-height: 500px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden;
position: relative;
box-shadow: 0 1px 2px color-mix(in oklab, var(--ui-text) 10%, transparent);
}
@media (min-width: 1024px) {
.kanban-column:not(:first-child)::before {
content: "";
position: absolute;
left: -0.7rem;
top: 0.75rem;
bottom: 0.75rem;
width: 1px;
background: var(--ui-border);
opacity: 0.9;
pointer-events: none;
}
} }
.kanban-column-header { .kanban-column-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 0.75rem 0.9rem; padding: 0.85rem 1rem;
border-bottom: 1px solid rgb(229 231 235); border-bottom: 1px solid var(--ui-border);
background: var(--ui-bg-muted);
} }
.kanban-dropzone { .kanban-dropzone {
padding: 0.75rem; padding: 0.9rem;
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.75rem; gap: 0.85rem;
transition: background-color 0.2s ease; transition: background-color 0.2s ease;
} }
.kanban-dropzone-active { .kanban-dropzone-active {
background: rgb(239 246 255); background: var(--ui-bg-muted);
} }
.kanban-card { .kanban-card {
border: 1px solid rgb(229 231 235); border: 1px solid var(--ui-border);
background: white; background: var(--ui-bg-elevated);
border-radius: 0.6rem; border-radius: 0.6rem;
padding: 0.7rem; padding: 0.7rem;
cursor: pointer; cursor: pointer;
@@ -686,7 +697,7 @@ onMounted(async () => {
.kanban-card-description { .kanban-card-description {
margin-top: 0.4rem; margin-top: 0.4rem;
color: rgb(107 114 128); color: var(--ui-text-dimmed);
font-size: 0.875rem; font-size: 0.875rem;
line-height: 1.15rem; line-height: 1.15rem;
} }
@@ -699,8 +710,8 @@ onMounted(async () => {
} }
.kanban-empty { .kanban-empty {
border: 1px dashed rgb(209 213 219); border: 1px dashed var(--ui-border);
color: rgb(156 163 175); color: var(--ui-text-dimmed);
border-radius: 0.6rem; border-radius: 0.6rem;
padding: 0.7rem; padding: 0.7rem;
font-size: 0.875rem; font-size: 0.875rem;
@@ -711,36 +722,15 @@ onMounted(async () => {
font-size: 0.875rem; font-size: 0.875rem;
font-weight: 600; font-weight: 600;
margin-bottom: 0.35rem; margin-bottom: 0.35rem;
color: var(--ui-text);
} }
:global(.dark) .kanban-column { .view-toggle {
border-color: rgb(55 65 81); display: flex;
background: rgb(17 24 39); align-items: center;
} gap: 0.25rem;
border: 1px solid var(--ui-border);
:global(.dark) .kanban-column-header { border-radius: 0.5rem;
border-bottom-color: rgb(55 65 81); padding: 0.25rem;
}
:global(.dark) .kanban-dropzone-active {
background: rgb(30 41 59);
}
:global(.dark) .kanban-card {
border-color: rgb(75 85 99);
background: rgb(31 41 55);
}
:global(.dark) .kanban-card-description {
color: rgb(209 213 219);
}
:global(.dark) .kanban-empty {
border-color: rgb(75 85 99);
color: rgb(156 163 175);
}
:global(.dark) .form-label {
color: rgb(229 231 235);
} }
</style> </style>