Zwischenstand
This commit is contained in:
@@ -254,7 +254,7 @@ onMounted(loadData)
|
||||
|
||||
<UTable
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
:rows="periods"
|
||||
:data="periods"
|
||||
:loading="loading"
|
||||
:empty-state="{ icon: 'i-heroicons-calculator', label: 'Keine Daten für die USt-Auswertung vorhanden' }"
|
||||
>
|
||||
|
||||
@@ -158,7 +158,7 @@ setupPage()
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
v-if="searchString.length > 0"
|
||||
/>
|
||||
@@ -194,7 +194,7 @@ setupPage()
|
||||
</template>
|
||||
</UDashboardToolbar>
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -137,7 +137,7 @@ const saldo = computed(() => {
|
||||
<UCard class="mt-5" v-if="item.label === 'Buchungen'">
|
||||
<UTable
|
||||
v-if="statementallocations"
|
||||
:rows="renderedAllocations"
|
||||
:data="renderedAllocations"
|
||||
:columns="normalizeTableColumns([{key:'amount', label:'Betrag'},{key:'date', label:'Datum'},{key:'partner', label:'Partner'},{key:'description', label:'Beschreibung'}])"
|
||||
@select="(i) => selectAllocation(i)"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Buchungen anzuzeigen' }"
|
||||
|
||||
@@ -504,7 +504,7 @@ onMounted(() => {
|
||||
placeholder="Konten"
|
||||
class="w-48"
|
||||
/>
|
||||
<UDivider orientation="vertical" class="h-6"/>
|
||||
<USeparator orientation="vertical" class="h-6"/>
|
||||
<div class="flex items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="selectedPeriod"
|
||||
@@ -633,7 +633,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="mt-2 flex flex-wrap gap-1">
|
||||
<UBadge v-if="entry.suggestions?.topDocument" size="xs" color="emerald" variant="subtle">Rechnung</UBadge>
|
||||
<UBadge v-if="entry.suggestions?.topIncomingInvoice" size="xs" color="rose" variant="subtle">Eingangsbeleg</UBadge>
|
||||
<UBadge v-if="entry.suggestions?.topIncomingInvoice" size="xs" color="error" variant="subtle">Eingangsbeleg</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -690,7 +690,7 @@ onMounted(() => {
|
||||
</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
<UButton size="sm" color="rose" @click="handleAssignIncomingInvoice(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice, $event)">
|
||||
<UButton size="sm" color="error" @click="handleAssignIncomingInvoice(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice, $event)">
|
||||
Zuweisen
|
||||
</UButton>
|
||||
<UButton size="sm" color="gray" variant="ghost" @click="dismissSuggestion(selectedSuggestionRow.row, selectedSuggestionRow.suggestions.topIncomingInvoice.suggestionKey, $event)">
|
||||
|
||||
@@ -438,7 +438,7 @@ setup()
|
||||
<UBadge v-else color="amber" variant="subtle">Offen</UBadge>
|
||||
</template>
|
||||
<template #right>
|
||||
<ArchiveButton color="rose" variant="outline" type="bankstatements" @confirmed="archiveStatement"/>
|
||||
<ArchiveButton color="error" variant="outline" type="bankstatements" @confirmed="archiveStatement"/>
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
@@ -552,7 +552,7 @@ setup()
|
||||
<div class="font-mono text-sm font-semibold">{{ displayCurrency(item.amount) }}</div>
|
||||
<UButton
|
||||
icon="i-heroicons-trash"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
class="opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
@@ -747,7 +747,7 @@ setup()
|
||||
</div>
|
||||
<UButton
|
||||
size="xs"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="saveAllocation({incominginvoice: invoice.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(invoice,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(invoice,true)), description: allocationDescription || 'Automatischer Vorschlag'})"
|
||||
>
|
||||
Beleg zuweisen
|
||||
@@ -867,7 +867,7 @@ setup()
|
||||
v-if="!itemInfo.statementallocations.find(i => i.incominginvoice === item.id)"
|
||||
icon="i-heroicons-check"
|
||||
size="sm"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
@click="saveAllocation({incominginvoice: item.id, bankstatement: itemInfo.id, amount: Number(Math.abs(getInvoiceSum(item,true)) > Math.abs(manualAllocationSum) ? manualAllocationSum : getInvoiceSum(item,true)), description: allocationDescription})"
|
||||
/>
|
||||
|
||||
@@ -1609,7 +1609,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</template>
|
||||
<template #right>
|
||||
<ArchiveButton
|
||||
color="rose"
|
||||
color="error"
|
||||
type="createddocuments"
|
||||
v-if="itemInfo.state === 'Entwurf' || itemInfo.type === 'serialInvoices'"
|
||||
variant="outline"
|
||||
@@ -1646,7 +1646,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UAlert
|
||||
class="my-5"
|
||||
title="Vorhandene Probleme und Informationen:"
|
||||
:color="findDocumentErrors.filter(i => i.type === 'breaking').length > 0 ? 'rose' : 'white'"
|
||||
:color="findDocumentErrors.filter(i => i.type === 'breaking').length > 0 ? 'error' : 'white'"
|
||||
variant="outline"
|
||||
v-if="findDocumentErrors.length > 0"
|
||||
>
|
||||
@@ -1761,7 +1761,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
searchable-placeholder="Suche..."
|
||||
:search-attributes="['name']"
|
||||
class="w-full"
|
||||
:color="itemInfo.letterhead ? 'primary' : 'rose'"
|
||||
:color="itemInfo.letterhead ? 'primary' : 'error'"
|
||||
>
|
||||
<template #label>
|
||||
{{ itemInfo.letterhead ? letterheads.find(i => i.id === itemInfo.letterhead).name : "Kein Briefpapier gewählt" }}
|
||||
@@ -1788,7 +1788,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
{{ option.name }}{{ option.nameAddition }}
|
||||
</template>
|
||||
<UButton
|
||||
:color="itemInfo.customer ? 'primary' : 'rose'"
|
||||
:color="itemInfo.customer ? 'primary' : 'error'"
|
||||
variant="outline"
|
||||
class="w-full"
|
||||
>
|
||||
@@ -1902,7 +1902,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
>Kontakt</UButton>-->
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.contact"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.contact = null"
|
||||
@@ -1923,7 +1923,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UInput
|
||||
v-model="itemInfo.address.street"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.street : 'Straße + Hausnummer'"
|
||||
:color="itemInfo.address.street ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.street ? 'primary' : 'error'"
|
||||
/>
|
||||
<UInput
|
||||
v-model="itemInfo.address.special"
|
||||
@@ -1940,13 +1940,13 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
@input="sanitizeAddressZipInput"
|
||||
@change="checkAddressZip"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.zip : 'PLZ'"
|
||||
:color="itemInfo.address.zip ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.zip ? 'primary' : 'error'"
|
||||
/>
|
||||
<UInput
|
||||
class="flex-auto"
|
||||
v-model="itemInfo.address.city"
|
||||
:placeholder="itemInfo.customer ? customers.find(i => i.id === itemInfo.customer).infoData.city : 'Ort'"
|
||||
:color="itemInfo.address.city ? 'primary' : 'rose'"
|
||||
:color="itemInfo.address.city ? 'primary' : 'error'"
|
||||
/>
|
||||
</InputGroup>
|
||||
</UFormGroup>
|
||||
@@ -2132,7 +2132,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.plant"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.plant = null"
|
||||
@@ -2171,7 +2171,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.project"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.project = null"
|
||||
@@ -2210,7 +2210,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</USelectMenu>
|
||||
<UButton
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
v-if="itemInfo.contract"
|
||||
icon="i-heroicons-x-mark"
|
||||
@click="itemInfo.contract = null"
|
||||
@@ -2229,9 +2229,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</InputGroup>
|
||||
|
||||
<div v-if="itemInfo.type === 'serialInvoices'" class="mb-5">
|
||||
<UDivider class="mt-5 mb-3">
|
||||
<USeparator class="mt-5 mb-3">
|
||||
Einstellungen für die Serienrechnung
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
|
||||
<div class="flex flex-row">
|
||||
<div class="w-1/3">
|
||||
@@ -2301,7 +2301,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
|
||||
</div>
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2317,7 +2317,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UInput v-model="itemInfo.description"/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2350,7 +2350,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</UFormGroup>
|
||||
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
@@ -2389,7 +2389,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
v-if="row.mode === 'pagebreak'"
|
||||
colspan="7"
|
||||
>
|
||||
<UDivider/>
|
||||
<USeparator/>
|
||||
</td>
|
||||
<td
|
||||
v-if="row.mode === 'text'"
|
||||
@@ -2429,7 +2429,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
class="w-60"
|
||||
:options="products"
|
||||
:color="row.product ? 'primary' : 'rose'"
|
||||
:color="row.product ? 'primary' : 'error'"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
@@ -2501,7 +2501,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
class="w-60"
|
||||
:options="services"
|
||||
:color="row.service ? 'primary' : 'rose'"
|
||||
:color="row.service ? 'primary' : 'error'"
|
||||
option-attribute="name"
|
||||
value-attribute="id"
|
||||
searchable
|
||||
@@ -2942,7 +2942,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UButton
|
||||
:disabled="itemInfo.type === 'cancellationInvoices'"
|
||||
variant="ghost"
|
||||
color="rose"
|
||||
color="error"
|
||||
icon="i-heroicons-x-mark-16-solid"
|
||||
@click="removePosition(row.id)"
|
||||
/>
|
||||
@@ -2954,7 +2954,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UAlert
|
||||
v-else
|
||||
title="Keine Positionen hinzugefügt"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
icon="i-heroicons-light-bulb"
|
||||
></UAlert>
|
||||
@@ -3004,12 +3004,12 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</UButton>
|
||||
</InputGroup>
|
||||
|
||||
<!-- <UDivider
|
||||
<!-- <USeparator
|
||||
class="mt-5 mb-3"
|
||||
v-if="openAdvanceInvoices.length > 0 || itemInfo.usedAdvanceInvoices.length > 0"
|
||||
>
|
||||
Noch nicht abgerechnete Abschlagsrechnungen
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
|
||||
<div
|
||||
v-for="advanceInvoice in openAdvanceInvoices"
|
||||
@@ -3029,7 +3029,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
<UButton
|
||||
@click="itemInfo.usedAdvanceInvoices = itemInfo.usedAdvanceInvoices.filter(i => i !== advanceInvoice.id)"
|
||||
:disabled="!itemInfo.usedAdvanceInvoices.includes(advanceInvoice.id)"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
>
|
||||
X
|
||||
@@ -3037,7 +3037,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</InputGroup>
|
||||
</div>-->
|
||||
|
||||
<UDivider class="my-3" v-if="Object.keys(documentTotal.titleSums).length > 0">Überschriften</UDivider>
|
||||
<USeparator class="my-3" v-if="Object.keys(documentTotal.titleSums).length > 0" label="Überschriften"/>
|
||||
|
||||
<table>
|
||||
<tr v-for="sumKey in Object.keys(documentTotal.titleSums) ">
|
||||
@@ -3046,7 +3046,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<UDivider class="my-3" v-if="itemInfo.rows.length > 0">Auswertung & Gesamt</UDivider>
|
||||
<USeparator class="my-3" v-if="itemInfo.rows.length > 0" label="Auswertung & Gesamt"/>
|
||||
|
||||
|
||||
<div class="w-full flex justify-between" v-if="itemInfo.type !== 'deliveryNotes'">
|
||||
@@ -3112,9 +3112,9 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- <UDivider
|
||||
<!-- <USeparator
|
||||
class="my-3"
|
||||
>Auswertung</UDivider>
|
||||
>Auswertung</USeparator>
|
||||
|
||||
<div class="w-full flex justify-end">
|
||||
<table class="w-1/3">
|
||||
@@ -3151,7 +3151,7 @@ const setRowData = async (row, service = {sellingPriceComposed: {}}, product = {
|
||||
|
||||
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
/>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</UInput>
|
||||
<UButton
|
||||
v-if="searchString.length > 0"
|
||||
color="rose"
|
||||
color="error"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
@click="clearSearchString()"
|
||||
@@ -60,7 +60,7 @@
|
||||
<UTable
|
||||
:columns="normalizeTableColumns(getColumnsForTab(item.key))"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Belege anzuzeigen' }"
|
||||
:rows="getRowsForTab(item.key)"
|
||||
:data="getRowsForTab(item.key)"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
class="w-full"
|
||||
@select="selectItem"
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
</div>
|
||||
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
@@ -158,7 +158,7 @@
|
||||
</div>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider label="Vorlagen auswählen" />
|
||||
<USeparator label="Vorlagen auswählen" />
|
||||
|
||||
<div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
|
||||
<div class="flex flex-col sm:flex-row gap-2 w-full sm:w-auto">
|
||||
@@ -204,7 +204,7 @@
|
||||
<div class="max-h-96 overflow-y-auto border border-gray-200 dark:border-gray-800 rounded-md">
|
||||
<UTable
|
||||
v-model="selectedExecutionRows"
|
||||
:rows="filteredExecutionList"
|
||||
:data="filteredExecutionList"
|
||||
:columns="normalizeTableColumns(executionColumns)"
|
||||
:ui="{ th: { base: 'whitespace-nowrap' } }"
|
||||
>
|
||||
|
||||
@@ -94,7 +94,7 @@ const openBankstatements = () => {
|
||||
<UButton
|
||||
@click="router.push(`/createDocument/edit/?createddocument=${itemInfo.id}&loadMode=storno`)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
:disabled="links.find(i => i.type === 'cancellationInvoices')"
|
||||
>
|
||||
Stornieren
|
||||
|
||||
@@ -162,7 +162,7 @@ const sendEmail = async () => {
|
||||
|
||||
|
||||
if(!res.success) {
|
||||
toast.add({title: "Fehler beim Absenden der E-Mail", color: "rose"})
|
||||
toast.add({title: "Fehler beim Absenden der E-Mail", color: "error"})
|
||||
|
||||
} else {
|
||||
navigateTo("/")
|
||||
@@ -220,7 +220,7 @@ const sendEmail = async () => {
|
||||
v-model="emailData.account"
|
||||
/>
|
||||
</UFormGroup>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
<UFormGroup
|
||||
label="Empfänger"
|
||||
>
|
||||
@@ -255,7 +255,7 @@ const sendEmail = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
<UDivider class="my-3"/>
|
||||
<USeparator class="my-3"/>
|
||||
<div id="parentAttachments" class="flex flex-col justify-center mt-3">
|
||||
<span class="font-medium mb-2 text-xl">Anhänge</span>
|
||||
<!-- <UIcon
|
||||
|
||||
@@ -39,7 +39,7 @@ const createExport = async () => {
|
||||
:loading="true"
|
||||
v-model="selected"
|
||||
:loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
|
||||
:rows="createddocuments" />
|
||||
:data="createddocuments" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -89,7 +89,7 @@ const createExport = async () => {
|
||||
if(res.success) {
|
||||
toast.add({title: "Export wird erstellt. Sie erhalten eine Benachrichtigung sobald es soweit ist."})
|
||||
} else {
|
||||
toast.add({title: "Es gab einen Fehler beim erstellen", color: "rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim erstellen", color: "error"})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -110,7 +110,7 @@ const createExport = async () => {
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UTable
|
||||
:rows="filteredExports"
|
||||
:data="filteredExports"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'created_at', label: 'Erstellt am' },
|
||||
{ key: 'start_date', label: 'Start' },
|
||||
|
||||
@@ -157,7 +157,7 @@ const updateIncomingInvoice = async (setBooked = false) => {
|
||||
toast.add({
|
||||
title: "Buchen nicht möglich",
|
||||
description: "Bitte beheben Sie zuerst die rot markierten Pflichtfehler.",
|
||||
color: "rose"
|
||||
color: "error"
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -220,7 +220,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<template #right>
|
||||
<ArchiveButton
|
||||
v-if="mode !== 'show'"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
type="incominginvoices"
|
||||
@confirmed="useEntities('incominginvoices').archive(route.params.id)"
|
||||
@@ -286,7 +286,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<UAlert
|
||||
v-if="findIncomingInvoiceErrors.length > 0"
|
||||
title="Prüfung erforderlich"
|
||||
:color="hasBlockingIncomingInvoiceErrors ? 'rose' : 'orange'"
|
||||
:color="hasBlockingIncomingInvoiceErrors ? 'error' : 'orange'"
|
||||
variant="soft"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
>
|
||||
@@ -323,7 +323,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="font-semibold">Stammdaten</h3>
|
||||
<div class="flex bg-gray-100 dark:bg-gray-800 p-1 rounded-lg">
|
||||
<UButton size="xs" :variant="itemInfo.expense ? 'solid' : 'ghost'" color="rose" @click="itemInfo.expense = true" :disabled="mode === 'show'">Ausgabe</UButton>
|
||||
<UButton size="xs" :variant="itemInfo.expense ? 'solid' : 'ghost'" color="error" @click="itemInfo.expense = true" :disabled="mode === 'show'">Ausgabe</UButton>
|
||||
<UButton size="xs" :variant="!itemInfo.expense ? 'solid' : 'ghost'" color="emerald" @click="itemInfo.expense = false" :disabled="mode === 'show'">Einnahme</UButton>
|
||||
</div>
|
||||
</div>
|
||||
@@ -354,7 +354,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
v-if="mode !== 'show'"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
:disabled="!itemInfo.vendor"
|
||||
@click="itemInfo.vendor = null"
|
||||
/>
|
||||
@@ -419,7 +419,7 @@ const hasBlockingIncomingInvoiceErrors = computed(() => blockingIncomingInvoiceE
|
||||
<UButton
|
||||
v-if="itemInfo.accounts.length > 1 && mode !== 'show'"
|
||||
icon="i-heroicons-trash"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
class="absolute top-2 right-2"
|
||||
|
||||
@@ -191,7 +191,7 @@ const selectIncomingInvoice = (invoice) => {
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
v-if="searchString.length > 0"
|
||||
/>
|
||||
@@ -250,7 +250,7 @@ const selectIncomingInvoice = (invoice) => {
|
||||
v-model:sort="sort"
|
||||
sort-mode="manual"
|
||||
@update:sort="setupPage"
|
||||
:rows="filteredRows.filter(i => item.label === 'Gebucht' ? i.state === 'Gebucht' : i.state !== 'Gebucht' )"
|
||||
:data="filteredRows.filter(i => item.label === 'Gebucht' ? i.state === 'Gebucht' : i.state !== 'Gebucht' )"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -16,7 +16,7 @@ const doLogin = async (data:any) => {
|
||||
await router.push("/")
|
||||
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Zugangsdaten falsch. Bitte überprüfen Sie Ihre Eingaben",color:"rose"})
|
||||
toast.add({title:"Zugangsdaten falsch. Bitte überprüfen Sie Ihre Eingaben",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -423,7 +423,7 @@ onMounted(() => {
|
||||
Urlaub
|
||||
</UButton>
|
||||
<UButton
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
icon="i-heroicons-heart"
|
||||
@click="openAbsenceModal('sick')"
|
||||
|
||||
@@ -24,7 +24,7 @@ const doChange = async (data:any) => {
|
||||
await auth.logout()
|
||||
return navigateTo("/login")
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Es gab ein Problem beim ändern",color:"rose"})
|
||||
toast.add({title:"Es gab ein Problem beim ändern",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -22,7 +22,7 @@ const doReset = async (data:any) => {
|
||||
toast.add({title:"Zurücksetzen erfolgreich"})
|
||||
return navigateTo("/login")
|
||||
} catch (err: any) {
|
||||
toast.add({title:"Problem beim zurücksetzen",color:"rose"})
|
||||
toast.add({title:"Problem beim zurücksetzen",color:"error"})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -152,7 +152,7 @@ const addPhase = () => {
|
||||
|
||||
<UForm v-else-if="mode === 'edit' || mode === 'create'">
|
||||
<UAlert
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mb-5"
|
||||
v-if="mode === 'edit'"
|
||||
@@ -167,9 +167,9 @@ const addPhase = () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider class="mt-5">
|
||||
<USeparator class="mt-5">
|
||||
Initiale Phasen
|
||||
</UDivider>
|
||||
</USeparator>
|
||||
<UButton
|
||||
class="mt-3"
|
||||
@click="addPhase"
|
||||
@@ -284,7 +284,7 @@ const addPhase = () => {
|
||||
<UButton
|
||||
class="my-2 ml-2"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="itemInfo.initialPhases = itemInfo.initialPhases.filter(i => i !== phase)"
|
||||
>X</UButton>
|
||||
</td>
|
||||
|
||||
@@ -87,7 +87,7 @@ const filteredRows = computed(() => {
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
|
||||
@@ -492,7 +492,7 @@ onMounted(async () => {
|
||||
<div class="admin-scroll">
|
||||
<UTable
|
||||
v-if="!loading"
|
||||
:rows="userTableRows"
|
||||
:data="userTableRows"
|
||||
:columns="normalizedUserTableColumns"
|
||||
@select="selectUser"
|
||||
/>
|
||||
@@ -565,7 +565,7 @@ onMounted(async () => {
|
||||
</UForm>
|
||||
|
||||
<div>
|
||||
<UDivider label="Rollen pro Tenant" class="mb-4" />
|
||||
<USeparator label="Rollen pro Tenant" class="mb-4" />
|
||||
|
||||
<div
|
||||
v-if="userForm.tenant_ids.length"
|
||||
@@ -627,7 +627,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<UDivider label="Profile im System" class="mb-4" />
|
||||
<USeparator label="Profile im System" class="mb-4" />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<UBadge
|
||||
v-for="profile in userForm.profiles"
|
||||
@@ -674,7 +674,7 @@ onMounted(async () => {
|
||||
<div class="admin-scroll">
|
||||
<UTable
|
||||
v-if="!loading"
|
||||
:rows="tenantTableRows"
|
||||
:data="tenantTableRows"
|
||||
:columns="normalizedTenantTableColumns"
|
||||
@select="selectTenant"
|
||||
/>
|
||||
@@ -711,7 +711,7 @@ onMounted(async () => {
|
||||
</UForm>
|
||||
|
||||
<div>
|
||||
<UDivider label="Zugeordnete Benutzer" class="mb-4" />
|
||||
<USeparator label="Zugeordnete Benutzer" class="mb-4" />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<UBadge
|
||||
v-for="user in getUsersForTenant(tenantForm.id)"
|
||||
|
||||
@@ -68,7 +68,7 @@ const addAccount = async (account) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
toast.add({title: "Es gab einen Fehler beim Hinzufügen des Accounts", color:"rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim Hinzufügen des Accounts", color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ const updateAccount = async (account) => {
|
||||
setupPage()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
toast.add({title: "Es gab einen Fehler beim Aktualisieren des Accounts", color:"rose"})
|
||||
toast.add({title: "Es gab einen Fehler beim Aktualisieren des Accounts", color:"error"})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ setupPage()
|
||||
v-else-if="showAlert && !bankData.id"
|
||||
title="Bank nicht gefunden"
|
||||
icon="i-heroicons-x-circle"
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mt-3"
|
||||
/>
|
||||
@@ -180,7 +180,7 @@ setupPage()
|
||||
</UModal>
|
||||
|
||||
<UTable
|
||||
:rows="bankaccounts"
|
||||
:data="bankaccounts"
|
||||
:columns="normalizeTableColumns([
|
||||
{
|
||||
key: 'expired',
|
||||
|
||||
@@ -75,7 +75,7 @@ const saveAccount = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider> IMAP </UDivider>
|
||||
<USeparator label="IMAP"/>
|
||||
|
||||
<UFormGroup
|
||||
label="IMAP Host"
|
||||
@@ -102,7 +102,7 @@ const saveAccount = async () => {
|
||||
/>
|
||||
</UFormGroup>
|
||||
|
||||
<UDivider> SMTP </UDivider>
|
||||
<USeparator label="SMTP"/>
|
||||
|
||||
<UFormGroup
|
||||
label="SMTP Host"
|
||||
|
||||
@@ -82,7 +82,7 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UTable
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
@select="(i) => navigateTo(`/settings/emailaccounts/edit/${i.id}`)"
|
||||
|
||||
@@ -41,7 +41,7 @@ const isLight = computed({
|
||||
<UCard class="mt-5">
|
||||
<div v-if="item.label === 'Profil'">
|
||||
|
||||
<UDivider
|
||||
<USeparator
|
||||
class="my-3"
|
||||
label="Profil"
|
||||
/>
|
||||
@@ -58,12 +58,12 @@ const isLight = computed({
|
||||
|
||||
</div>
|
||||
<div v-else-if="item.label === 'Projekte'">
|
||||
<UDivider
|
||||
<USeparator
|
||||
label="Phasenvorlagen"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="item.label === 'Dokumente'">
|
||||
<UDivider
|
||||
<USeparator
|
||||
label="Tags"
|
||||
class="mb-3"
|
||||
/>
|
||||
|
||||
@@ -80,7 +80,7 @@ const updateNumberRanges = async (range) => {
|
||||
<UDashboardToolbar>
|
||||
<UAlert
|
||||
title="Änderungen an diesen Werten betreffen nur neu Erstellte Einträge."
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
icon="i-heroicons-exclamation-triangle"
|
||||
/>
|
||||
|
||||
@@ -258,7 +258,7 @@ setupPage()
|
||||
<UAlert
|
||||
title="Funktionen ausblenden"
|
||||
description="Nur Funktionen mit gesetztem Haken sind im Unternehmen verfügbar. Diese Einstellungen gelten für alle Mitarbeiter und sind unabhängig von Berechtigungen."
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="mb-5"
|
||||
/>
|
||||
|
||||
@@ -49,7 +49,7 @@ const refreshData = async () => {
|
||||
// select() filtert bereits archivierte Einträge, wenn dataType.isArchivable true ist
|
||||
texttemplates.value = await select()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler beim Laden', description: e.message, color: 'rose' })
|
||||
toast.add({ title: 'Fehler beim Laden', description: e.message, color: 'error' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -93,7 +93,7 @@ const handleCreate = async () => {
|
||||
editTemplateModalOpen.value = false
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler', description: 'Konnte nicht erstellt werden.', color: 'rose' })
|
||||
toast.add({ title: 'Fehler', description: 'Konnte nicht erstellt werden.', color: 'error' })
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
@@ -109,7 +109,7 @@ const handleUpdate = async () => {
|
||||
editTemplateModalOpen.value = false
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht gespeichert werden.', color: 'rose'})
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht gespeichert werden.', color: 'error'})
|
||||
} finally {
|
||||
isSaving.value = false
|
||||
}
|
||||
@@ -122,7 +122,7 @@ const handleArchive = async (row) => {
|
||||
|
||||
await refreshData()
|
||||
} catch (e) {
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht archiviert werden.', color: 'rose'})
|
||||
toast.add({title: 'Fehler', description: 'Konnte nicht archiviert werden.', color: 'error'})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ const getDocLabel = (type) => {
|
||||
|
||||
<UTable
|
||||
class="mt-3"
|
||||
:rows="texttemplates"
|
||||
:data="texttemplates"
|
||||
:loading="loading"
|
||||
v-model:expand="expand"
|
||||
:empty-state="{ icon: 'i-heroicons-document-text', label: 'Keine Textvorlagen gefunden' }"
|
||||
@@ -212,7 +212,7 @@ const getDocLabel = (type) => {
|
||||
|
||||
<div class="flex justify-end gap-3">
|
||||
<ButtonWithConfirm
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="soft"
|
||||
icon="i-heroicons-archive-box"
|
||||
@confirmed="handleArchive(row)"
|
||||
|
||||
@@ -179,7 +179,7 @@ onMounted(fetchProfile)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<UDivider label="Persönliche Daten" />
|
||||
<USeparator label="Persönliche Daten" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Vorname">
|
||||
@@ -211,7 +211,7 @@ onMounted(fetchProfile)
|
||||
</UForm>
|
||||
</UCard>
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Vertragsinformationen" />
|
||||
<USeparator label="Vertragsinformationen" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Vertragsart">
|
||||
@@ -256,7 +256,7 @@ onMounted(fetchProfile)
|
||||
</UCard>
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Adresse & Standort" />
|
||||
<USeparator label="Adresse & Standort" />
|
||||
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Straße und Hausnummer">
|
||||
@@ -285,7 +285,7 @@ onMounted(fetchProfile)
|
||||
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Wöchentliche Arbeitsstunden" />
|
||||
<USeparator label="Wöchentliche Arbeitsstunden" />
|
||||
|
||||
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
<div
|
||||
@@ -313,7 +313,7 @@ onMounted(fetchProfile)
|
||||
</UCard>
|
||||
|
||||
<UCard v-if="!pending && profile" class="mt-3">
|
||||
<UDivider label="Sonstiges" />
|
||||
<USeparator label="Sonstiges" />
|
||||
<UForm :state="profile" @submit.prevent="saveProfile" class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-4">
|
||||
<UFormGroup label="Kleidergröße (Oberteil)">
|
||||
<UInput v-model="profile.clothing_size_top" />
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
<UTable
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
@select="(i) => navigateTo(`/staff/profiles/${i.id}`)"
|
||||
>
|
||||
|
||||
@@ -29,7 +29,16 @@ const platformIsNative = ref(false)
|
||||
const selectedPresetRange = ref("Dieser Monat bis heute")
|
||||
const selectedStartDay = ref("")
|
||||
const selectedEndDay = ref("")
|
||||
const openTab = ref(0)
|
||||
const openTab = ref("0")
|
||||
const presetRangeItems = [
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]
|
||||
|
||||
const showDocument = ref(false)
|
||||
const uri = ref("")
|
||||
@@ -131,7 +140,7 @@ async function loadWorkingTimeInfo() {
|
||||
|
||||
workingTimeInfo.value = data;
|
||||
|
||||
openTab.value = 0
|
||||
openTab.value = "0"
|
||||
}
|
||||
|
||||
// 📄 PDF generieren
|
||||
@@ -172,12 +181,12 @@ async function saveFile() {
|
||||
toast.add({title:"Auswertung erfolgreich gespeichert"})
|
||||
fileSaved.value = true
|
||||
} catch (error) {
|
||||
toast.add({title:"Fehler beim Speichern der Auswertung", color: "rose"})
|
||||
toast.add({title:"Fehler beim Speichern der Auswertung", color: "error"})
|
||||
}
|
||||
}
|
||||
|
||||
async function onTabChange(index: number) {
|
||||
if (index === 1) await generateDocument()
|
||||
async function onTabChange(index: string | number) {
|
||||
if (String(index) === "1") await generateDocument()
|
||||
}
|
||||
|
||||
// Initialisierung
|
||||
@@ -204,52 +213,44 @@ await setupPage()
|
||||
</template>
|
||||
</UDashboardNavbar>
|
||||
|
||||
<UDashboardToolbar>
|
||||
<UDashboardToolbar class="py-3">
|
||||
<template #left>
|
||||
<UFormGroup label="Zeitraum:">
|
||||
<UFormField label="Zeitraum:">
|
||||
<USelectMenu
|
||||
:options="[
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]"
|
||||
:items="presetRangeItems"
|
||||
v-model="selectedPresetRange"
|
||||
@change="changeRange"
|
||||
/>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
|
||||
<UFormGroup label="Start:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UFormField label="Start:">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="selectedStartDay ? $dayjs(selectedStartDay).format('DD.MM.YYYY') : 'Datum wählen'"
|
||||
/>
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedStartDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
|
||||
<UFormGroup label="Ende:">
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UFormField label="Ende:">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar-days-20-solid"
|
||||
:label="selectedEndDay ? $dayjs(selectedEndDay).format('DD.MM.YYYY') : 'Datum wählen'"
|
||||
/>
|
||||
<template #panel="{ close }">
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedEndDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</UFormGroup>
|
||||
</UFormField>
|
||||
</template>
|
||||
<template #right>
|
||||
<UTooltip
|
||||
:text="fileSaved ? 'Bericht bereits gespeichert' : 'Bericht speichern'"
|
||||
v-if="openTab === 1 && uri"
|
||||
v-if="openTab === '1' && uri"
|
||||
>
|
||||
<UButton
|
||||
icon="i-mdi-content-save"
|
||||
@@ -265,9 +266,9 @@ await setupPage()
|
||||
<UTabs
|
||||
:items="[{ label: 'Information' }, { label: 'Bericht' }]"
|
||||
v-model="openTab"
|
||||
@change="onTabChange"
|
||||
@update:model-value="onTabChange"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<template #content="{ item }">
|
||||
<div v-if="item.label === 'Information'">
|
||||
|
||||
<UCard v-if="workingTimeInfo && workingTimeInfo.summary" class="my-5">
|
||||
@@ -294,8 +295,8 @@ await setupPage()
|
||||
<UDashboardPanel>
|
||||
<UTable
|
||||
v-if="workingTimeInfo"
|
||||
:rows="workingTimeInfo.spans"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Anwesenheiten' }"
|
||||
:data="workingTimeInfo.spans"
|
||||
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Anwesenheiten' }"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'status', label: 'Status' },
|
||||
{ key: 'startedAt', label: 'Start' },
|
||||
@@ -303,30 +304,30 @@ await setupPage()
|
||||
{ key: 'duration', label: 'Dauer' },
|
||||
{ key: 'type', label: 'Typ' }
|
||||
])"
|
||||
@select="(row) => router.push(`/workingtimes/edit/${row.sourceEventIds[0]}`)"
|
||||
:on-select="(row) => router.push(`/workingtimes/edit/${row.original.sourceEventIds[0]}`)"
|
||||
>
|
||||
<template #status-data="{row}">
|
||||
<span v-if="row.status === 'approved'" class="text-primary-500">Genehmigt</span>
|
||||
<span v-else-if="row.status === 'submitted'" class="text-cyan-500">Eingereicht</span>
|
||||
<span v-else-if="row.status === 'factual'" class="text-gray-500">Faktisch</span>
|
||||
<span v-else-if="row.status === 'draft'" class="text-red-500">Entwurf</span>
|
||||
<span v-else>{{ row.status }}</span>
|
||||
<template #status-cell="{ row }">
|
||||
<span v-if="row.original.status === 'approved'" class="text-primary-500">Genehmigt</span>
|
||||
<span v-else-if="row.original.status === 'submitted'" class="text-cyan-500">Eingereicht</span>
|
||||
<span v-else-if="row.original.status === 'factual'" class="text-gray-500">Faktisch</span>
|
||||
<span v-else-if="row.original.status === 'draft'" class="text-error-500">Entwurf</span>
|
||||
<span v-else>{{ row.original.status }}</span>
|
||||
</template>
|
||||
|
||||
<template #startedAt-data="{ row }">
|
||||
{{ $dayjs(row.startedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
<template #startedAt-cell="{ row }">
|
||||
{{ $dayjs(row.original.startedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
</template>
|
||||
|
||||
<template #endedAt-data="{ row }">
|
||||
{{ $dayjs(row.endedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
<template #endedAt-cell="{ row }">
|
||||
{{ $dayjs(row.original.endedAt).format('HH:mm DD.MM.YY') }} Uhr
|
||||
</template>
|
||||
|
||||
<template #duration-data="{ row }">
|
||||
{{ formatSpanDuration(row.startedAt, row.endedAt) }}
|
||||
<template #duration-cell="{ row }">
|
||||
{{ formatSpanDuration(row.original.startedAt, row.original.endedAt) }}
|
||||
</template>
|
||||
|
||||
<template #type-data="{ row }">
|
||||
{{ row.type.charAt(0).toUpperCase() + row.type.slice(1).replace('_', ' ') }}
|
||||
<template #type-cell="{ row }">
|
||||
{{ row.original.type.charAt(0).toUpperCase() + row.original.type.slice(1).replace('_', ' ') }}
|
||||
</template>
|
||||
</UTable>
|
||||
</UDashboardPanel>
|
||||
@@ -360,15 +361,7 @@ await setupPage()
|
||||
<div class="p-4 space-y-4 border-b bg-white dark:bg-gray-900">
|
||||
<USelectMenu
|
||||
v-model="selectedPresetRange"
|
||||
:options="[
|
||||
'Dieser Monat bis heute',
|
||||
'Diese Woche',
|
||||
'Dieser Monat',
|
||||
'Dieses Jahr',
|
||||
'Letzte Woche',
|
||||
'Letzter Monat',
|
||||
'Letztes Jahr'
|
||||
]"
|
||||
:items="presetRangeItems"
|
||||
@change="changeRange"
|
||||
placeholder="Zeitraum wählen"
|
||||
class="w-full"
|
||||
@@ -377,13 +370,13 @@ await setupPage()
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 mb-1">Start</p>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar"
|
||||
class="w-full"
|
||||
:label="$dayjs(selectedStartDay).format('DD.MM.YYYY')"
|
||||
/>
|
||||
<template #panel>
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedStartDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
@@ -391,13 +384,13 @@ await setupPage()
|
||||
|
||||
<div>
|
||||
<p class="text-xs text-gray-500 mb-1">Ende</p>
|
||||
<UPopover :popper="{ placement: 'bottom-start' }">
|
||||
<UPopover :content="{ side: 'bottom', align: 'start' }">
|
||||
<UButton
|
||||
icon="i-heroicons-calendar"
|
||||
class="w-full"
|
||||
:label="$dayjs(selectedEndDay).format('DD.MM.YYYY')"
|
||||
/>
|
||||
<template #panel>
|
||||
<template #content>
|
||||
<LazyDatePicker v-model="selectedEndDay" @close="loadWorkingTimeInfo" />
|
||||
</template>
|
||||
</UPopover>
|
||||
@@ -408,12 +401,11 @@ await setupPage()
|
||||
<UTabs
|
||||
:items="[{ label: 'Information' }, { label: 'Bericht' }]"
|
||||
v-model="openTab"
|
||||
@change="onTabChange"
|
||||
@update:model-value="onTabChange"
|
||||
class="mt-3 mx-3"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
|
||||
<div v-if="item.label === 'Information'" class="space-y-4">
|
||||
<template #content="{ item }">
|
||||
<div v-if="item.label === 'Information'" class="space-y-4">
|
||||
|
||||
<UCard v-if="workingTimeInfo && workingTimeInfo.summary" class="mt-3">
|
||||
<template #header>
|
||||
@@ -459,7 +451,7 @@ await setupPage()
|
||||
|
||||
<div v-else-if="item.label === 'Bericht'">
|
||||
<UButton
|
||||
v-if="uri && !fileSaved"
|
||||
v-if="openTab === '1' && uri && !fileSaved"
|
||||
icon="i-mdi-content-save"
|
||||
color="primary"
|
||||
class="w-full mb-3"
|
||||
|
||||
@@ -32,6 +32,10 @@ const rejectReason = ref("")
|
||||
const users = ref([])
|
||||
const selectedUser = ref(auth.user.id)
|
||||
const canViewAll = computed(() => auth.permissions.includes('staff.time.read_all'))
|
||||
const userItems = computed(() => users.value.map(u => ({
|
||||
label: u.full_name || u.email,
|
||||
value: u.user_id
|
||||
})))
|
||||
|
||||
// DATA
|
||||
const entries = ref([])
|
||||
@@ -61,7 +65,7 @@ const typeLabel = {
|
||||
const typeColor = {
|
||||
work: "gray",
|
||||
vacation: "yellow",
|
||||
sick: "rose",
|
||||
sick: "error",
|
||||
holiday: "blue",
|
||||
other: "gray"
|
||||
}
|
||||
@@ -130,7 +134,7 @@ async function confirmReject() {
|
||||
showRejectModal.value = false
|
||||
await load()
|
||||
} catch (e) {
|
||||
toast.add({ title: 'Fehler beim Ablehnen', description: e.message, color: 'red' })
|
||||
toast.add({ title: 'Fehler beim Ablehnen', description: e.message, color: 'error' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
entryToReject.value = null
|
||||
@@ -167,10 +171,10 @@ onMounted(async () => {
|
||||
<div v-if="canViewAll" class="flex items-center gap-2">
|
||||
<USelectMenu
|
||||
v-model="selectedUser"
|
||||
:options="users.map(u => ({ label: u.full_name || u.email, value: u.user_id }))"
|
||||
:items="userItems"
|
||||
placeholder="Benutzer auswählen"
|
||||
value-attribute="value"
|
||||
option-attribute="label"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
class="min-w-[220px]"
|
||||
:clearable="false"
|
||||
/>
|
||||
@@ -211,11 +215,11 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<template v-if="isViewingSelf">
|
||||
<UButton v-if="active" color="red" icon="i-heroicons-stop" :loading="loading" label="Stoppen" @click="handleStop" />
|
||||
<UButton v-if="active" color="error" icon="i-heroicons-stop" :loading="loading" label="Stoppen" @click="handleStop" />
|
||||
<UButton v-else color="green" icon="i-heroicons-play" :loading="loading" label="Starten" @click="handleStart" />
|
||||
</template>
|
||||
<template v-else-if="active && canViewAll">
|
||||
<UButton color="red" variant="soft" icon="i-heroicons-stop" :loading="loading" label="Mitarbeiter stoppen" @click="handleStop" />
|
||||
<UButton color="error" variant="soft" icon="i-heroicons-stop" :loading="loading" label="Mitarbeiter stoppen" @click="handleStop" />
|
||||
</template>
|
||||
|
||||
<UButton color="gray" variant="solid" icon="i-heroicons-plus" label="Erfassen" @click="() => { entryToEdit = null; showEditModal = true }" />
|
||||
@@ -227,7 +231,7 @@ onMounted(async () => {
|
||||
|
||||
<UCard v-if="view === 'list'" :ui="{ body: { padding: 'p-0 sm:p-0' } }">
|
||||
<UTable
|
||||
:rows="entries"
|
||||
:data="entries"
|
||||
:columns="normalizeTableColumns([
|
||||
{ key: 'actions', label: 'Aktionen', class: 'w-32' },
|
||||
{ key: 'state', label: 'Status' },
|
||||
@@ -237,49 +241,49 @@ onMounted(async () => {
|
||||
{ key: 'type', label: 'Typ' },
|
||||
{ key: 'description', label: 'Beschreibung' },
|
||||
])"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Zeiten anzuzeigen' }"
|
||||
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine Zeiten anzuzeigen' }"
|
||||
>
|
||||
<template #state-data="{ row }">
|
||||
<UBadge v-if="row.state === 'approved'" color="green" variant="subtle">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'submitted'" color="cyan" variant="subtle">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="red" variant="subtle">Abgelehnt</UBadge>
|
||||
<template #state-cell="{ row }">
|
||||
<UBadge v-if="row.original.state === 'approved'" color="green" variant="subtle">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.original.state === 'submitted'" color="cyan" variant="subtle">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.original.state === 'rejected'" color="error" variant="subtle">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray" variant="subtle">Entwurf</UBadge>
|
||||
</template>
|
||||
<template #type-data="{ row }">
|
||||
<UBadge :color="typeColor[row.type] || 'gray'" variant="soft">{{ typeLabel[row.type] || row.type }}</UBadge>
|
||||
<template #type-cell="{ row }">
|
||||
<UBadge :color="typeColor[row.original.type] || 'gray'" variant="soft">{{ typeLabel[row.original.type] || row.original.type }}</UBadge>
|
||||
</template>
|
||||
<template #started_at-data="{ row }">
|
||||
<span v-if="['vacation','sick'].includes(row.type)">{{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.started_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
<template #started_at-cell="{ row }">
|
||||
<span v-if="['vacation','sick'].includes(row.original.type)">{{ useNuxtApp().$dayjs(row.original.started_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.original.started_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
</template>
|
||||
<template #stopped_at-data="{ row }">
|
||||
<span v-if="!row.stopped_at" class="text-primary-500 font-medium animate-pulse">läuft...</span>
|
||||
<span v-else-if="['vacation','sick'].includes(row.type)">{{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.stopped_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
<template #stopped_at-cell="{ row }">
|
||||
<span v-if="!row.original.stopped_at" class="text-primary-500 font-medium animate-pulse">läuft...</span>
|
||||
<span v-else-if="['vacation','sick'].includes(row.original.type)">{{ useNuxtApp().$dayjs(row.original.stopped_at).format("DD.MM.YY") }}</span>
|
||||
<span v-else>{{ useNuxtApp().$dayjs(row.original.stopped_at).format("DD.MM.YY HH:mm") }}</span>
|
||||
</template>
|
||||
<template #duration_minutes-data="{ row }">
|
||||
{{ row.duration_minutes ? useFormatDuration(row.duration_minutes) : "-" }}
|
||||
<template #duration_minutes-cell="{ row }">
|
||||
{{ row.original.duration_minutes ? useFormatDuration(row.original.duration_minutes) : "-" }}
|
||||
</template>
|
||||
<template #actions-data="{ row }">
|
||||
<template #actions-cell="{ row }">
|
||||
<div class="flex items-center gap-1">
|
||||
<UTooltip text="Einreichen" v-if="(row.state === 'draft' || row.state === 'factual') && row.stopped_at">
|
||||
<UButton size="xs" color="cyan" variant="ghost" icon="i-heroicons-paper-airplane" @click="handleSubmit(row)" :loading="loading" />
|
||||
<UTooltip text="Einreichen" v-if="(row.original.state === 'draft' || row.original.state === 'factual') && row.original.stopped_at">
|
||||
<UButton size="xs" color="cyan" variant="ghost" icon="i-heroicons-paper-airplane" @click="handleSubmit(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Genehmigen" v-if="row.state === 'submitted' && canViewAll">
|
||||
<UButton size="xs" color="green" variant="ghost" icon="i-heroicons-check" @click="handleApprove(row)" :loading="loading" />
|
||||
<UTooltip text="Genehmigen" v-if="row.original.state === 'submitted' && canViewAll">
|
||||
<UButton size="xs" color="green" variant="ghost" icon="i-heroicons-check" @click="handleApprove(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Ablehnen" v-if="(row.state === 'submitted' || row.state === 'approved') && canViewAll">
|
||||
<UButton size="xs" color="red" variant="ghost" icon="i-heroicons-x-mark" @click="openRejectModal(row)" :loading="loading" />
|
||||
<UTooltip text="Ablehnen" v-if="(row.original.state === 'submitted' || row.original.state === 'approved') && canViewAll">
|
||||
<UButton size="xs" color="error" variant="ghost" icon="i-heroicons-x-mark" @click="openRejectModal(row.original)" :loading="loading" />
|
||||
</UTooltip>
|
||||
<UTooltip text="Bearbeiten" v-if="['draft', 'factual', 'submitted'].includes(row.state)">
|
||||
<UButton size="xs" color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="handleEdit(row)" />
|
||||
<UTooltip text="Bearbeiten" v-if="['draft', 'factual', 'submitted'].includes(row.original.state)">
|
||||
<UButton size="xs" color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="handleEdit(row.original)" />
|
||||
</UTooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #description-data="{ row }">
|
||||
<span v-if="row.type === 'vacation'">{{row.vacation_reason}}</span>
|
||||
<span v-else-if="row.type === 'sick'">{{row.sick_reason}}</span>
|
||||
<span v-else>{{row.description}}</span>
|
||||
<template #description-cell="{ row }">
|
||||
<span v-if="row.original.type === 'vacation'">{{ row.original.vacation_reason }}</span>
|
||||
<span v-else-if="row.original.type === 'sick'">{{ row.original.sick_reason }}</span>
|
||||
<span v-else>{{ row.original.description }}</span>
|
||||
</template>
|
||||
</UTable>
|
||||
</UCard>
|
||||
@@ -334,7 +338,7 @@ onMounted(async () => {
|
||||
|
||||
<UBadge v-if="entry.state === 'approved'" color="green" size="xs" variant="solid">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'submitted'" color="cyan" size="xs" variant="solid">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'rejected'" color="red" size="xs" variant="solid">Abgelehnt</UBadge>
|
||||
<UBadge v-else-if="entry.state === 'rejected'" color="error" size="xs" variant="solid">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray" size="xs" variant="subtle">Entwurf</UBadge>
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,7 +367,7 @@ onMounted(async () => {
|
||||
|
||||
<UButton
|
||||
v-if="(entry.state === 'submitted' || entry.state === 'approved') && canViewAll"
|
||||
size="xs" color="red" variant="ghost" icon="i-heroicons-x-mark" label="Ablehnen"
|
||||
size="xs" color="error" variant="ghost" icon="i-heroicons-x-mark" label="Ablehnen"
|
||||
@click="openRejectModal(entry)" :loading="loading"
|
||||
/>
|
||||
|
||||
@@ -403,7 +407,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<template v-if="isViewingSelf">
|
||||
<UButton v-if="active" color="red" icon="i-heroicons-stop" :loading="loading" @click="handleStop" />
|
||||
<UButton v-if="active" color="error" icon="i-heroicons-stop" :loading="loading" @click="handleStop" />
|
||||
<UButton v-else color="green" icon="i-heroicons-play" :loading="loading" @click="handleStart" />
|
||||
</template>
|
||||
</div>
|
||||
@@ -422,7 +426,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<UBadge v-if="row.state === 'approved'" color="green">Genehmigt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'submitted'" color="cyan">Eingereicht</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="red">Abgelehnt</UBadge>
|
||||
<UBadge v-else-if="row.state === 'rejected'" color="error">Abgelehnt</UBadge>
|
||||
<UBadge v-else color="gray">Entwurf</UBadge>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-1">Start: {{ useNuxtApp().$dayjs(row.started_at).format('DD.MM.YY HH:mm') }}</p>
|
||||
@@ -445,29 +449,31 @@ onMounted(async () => {
|
||||
/>
|
||||
|
||||
<UModal v-model:open="showRejectModal">
|
||||
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Zeiteintrag ablehnen
|
||||
</h3>
|
||||
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showRejectModal = false" />
|
||||
<template #content>
|
||||
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
|
||||
Zeiteintrag ablehnen
|
||||
</h3>
|
||||
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="showRejectModal = false" />
|
||||
</div>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Der Eintrag wird als "Rejected" markiert und nicht mehr zur Arbeitszeit gezählt.
|
||||
</p>
|
||||
<UFormField label="Grund (optional)" name="reason">
|
||||
<UTextarea v-model="rejectReason" placeholder="Falsche Buchung, Doppelt, etc." autofocus />
|
||||
</UFormField>
|
||||
</div>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<p class="text-sm text-gray-500">
|
||||
Der Eintrag wird als "Rejected" markiert und nicht mehr zur Arbeitszeit gezählt.
|
||||
</p>
|
||||
<UFormGroup label="Grund (optional)" name="reason">
|
||||
<UTextarea v-model="rejectReason" placeholder="Falsche Buchung, Doppelt, etc." autofocus />
|
||||
</UFormGroup>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<UButton color="gray" variant="soft" @click="showRejectModal = false">Abbrechen</UButton>
|
||||
<UButton color="red" :loading="loading" @click="confirmReject">Bestätigen</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-2">
|
||||
<UButton color="gray" variant="soft" @click="showRejectModal = false">Abbrechen</UButton>
|
||||
<UButton color="error" :loading="loading" @click="confirmReject">Bestätigen</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
@@ -73,6 +73,24 @@ const sort = ref({
|
||||
column: dataType.sortColumn || "created_at",
|
||||
direction: 'desc'
|
||||
})
|
||||
const sorting = computed({
|
||||
get: () => [{
|
||||
id: sort.value.column,
|
||||
desc: sort.value.direction === 'desc'
|
||||
}],
|
||||
set: (value) => {
|
||||
const nextSort = Array.isArray(value) ? value[0] : undefined
|
||||
if (!nextSort?.id) {
|
||||
return
|
||||
}
|
||||
|
||||
sort.value = {
|
||||
column: nextSort.id,
|
||||
direction: nextSort.desc ? 'desc' : 'asc'
|
||||
}
|
||||
setupPage()
|
||||
}
|
||||
})
|
||||
|
||||
const columnsToFilter = ref({})
|
||||
|
||||
@@ -282,6 +300,19 @@ const handleFilterChange = async (action,column) => {
|
||||
setupPage()
|
||||
}
|
||||
|
||||
const truncateValue = (value, maxLength) => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '\u00A0'
|
||||
}
|
||||
|
||||
const stringValue = String(value)
|
||||
if (!maxLength || stringValue.length <= maxLength) {
|
||||
return stringValue
|
||||
}
|
||||
|
||||
return `${stringValue.substring(0, maxLength)}...`
|
||||
}
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
@@ -313,7 +344,7 @@ const handleFilterChange = async (action,column) => {
|
||||
<UButton
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
|
||||
/>
|
||||
@@ -336,10 +367,10 @@ const handleFilterChange = async (action,column) => {
|
||||
<template #left>
|
||||
<UTooltip :text="`${dataType.label} pro Seite`">
|
||||
<USelectMenu
|
||||
:options="[{value:10},{value:15, disabled: itemsMeta.total < 15},{value:25, disabled: itemsMeta.total < 25},{value:50, disabled: itemsMeta.total < 50},{value:100, disabled: itemsMeta.total < 100},{value:250, disabled: itemsMeta.total < 250}]"
|
||||
:items="[{value:10},{value:15, disabled: itemsMeta.total < 15},{value:25, disabled: itemsMeta.total < 25},{value:50, disabled: itemsMeta.total < 50},{value:100, disabled: itemsMeta.total < 100},{value:250, disabled: itemsMeta.total < 250}]"
|
||||
v-model="pageLimit"
|
||||
value-attribute="value"
|
||||
option-attribute="value"
|
||||
value-key="value"
|
||||
label-key="value"
|
||||
@change="setupPage"
|
||||
/>
|
||||
</UTooltip>
|
||||
@@ -363,15 +394,15 @@ const handleFilterChange = async (action,column) => {
|
||||
<USelectMenu
|
||||
v-model="selectedColumns"
|
||||
icon="i-heroicons-adjustments-horizontal-solid"
|
||||
:options="dataType.templateColumns.filter(i => !i.disabledInTable)"
|
||||
:items="dataType.templateColumns.filter(i => !i.disabledInTable)"
|
||||
multiple
|
||||
class="hidden lg:block"
|
||||
by="key"
|
||||
:color="selectedColumns.length !== dataType.templateColumns.filter(i => !i.disabledInTable).length ? 'primary' : 'white'"
|
||||
:ui-menu="{ width: 'min-w-max' }"
|
||||
:content="{ width: 'min-w-max' }"
|
||||
@change="tempStore.modifyColumns(type,selectedColumns)"
|
||||
>
|
||||
<template #label>
|
||||
<template #default>
|
||||
Spalten
|
||||
</template>
|
||||
</USelectMenu>
|
||||
@@ -382,18 +413,15 @@ const handleFilterChange = async (action,column) => {
|
||||
<div v-if="!platformIsNative">
|
||||
<UTable
|
||||
:loading="loading"
|
||||
:loading-state="{ icon: 'i-heroicons-arrow-path-20-solid', label: 'Loading...' }"
|
||||
sort-mode="manual"
|
||||
v-model:sort="sort"
|
||||
@update:sort="setupPage"
|
||||
v-model:sorting="sorting"
|
||||
v-if="dataType && columns && items.length > 0 && !loading"
|
||||
:rows="items"
|
||||
:data="items"
|
||||
:columns="normalizeTableColumns(columns)"
|
||||
class="w-full"
|
||||
style="height: 85dvh"
|
||||
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
|
||||
@select="(i) => router.push(`/standardEntity/${type}/show/${i.id}`) "
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: `Keine ${dataType.label} anzuzeigen` }"
|
||||
:on-select="(row) => router.push(`/standardEntity/${type}/show/${row.original.id}`)"
|
||||
:empty="`Keine ${dataType.label} anzuzeigen`"
|
||||
>
|
||||
<template
|
||||
v-for="column in dataType.templateColumns.filter(i => !i.disabledInTable)"
|
||||
@@ -414,15 +442,14 @@ const handleFilterChange = async (action,column) => {
|
||||
:text="!columnsToFilter[column.key]?.length > 0 ? `Keine Einträge für ${column.label} verfügbar` : `${column.label} Spalte nach Einträgen filtern`"
|
||||
>
|
||||
<USelectMenu
|
||||
:options="itemsMeta?.distinctValues?.[column.key]"
|
||||
:items="(itemsMeta?.distinctValues?.[column.key] || []).map(value => ({ label: value, value }))"
|
||||
v-model="columnsToFilter[column.key]"
|
||||
multiple
|
||||
@change="handleFilterChange('change', column.key)"
|
||||
searchable
|
||||
searchable-placeholder="Suche..."
|
||||
:search-attributes="[column.key]"
|
||||
:ui-menu="{ width: 'min-w-max' }"
|
||||
clear-search-on-close
|
||||
:search-input="{ placeholder: 'Suche...' }"
|
||||
value-key="value"
|
||||
label-key="label"
|
||||
:content="{ width: 'min-w-max' }"
|
||||
>
|
||||
|
||||
<template #empty>
|
||||
@@ -458,7 +485,7 @@ const handleFilterChange = async (action,column) => {
|
||||
<UButton
|
||||
@click="handleFilterChange('reset',column.key)"
|
||||
variant="outline"
|
||||
color="rose"
|
||||
color="error"
|
||||
>
|
||||
X
|
||||
</UButton>
|
||||
@@ -468,48 +495,54 @@ const handleFilterChange = async (action,column) => {
|
||||
</InputGroup>
|
||||
|
||||
</template>
|
||||
<template #name-data="{row}">
|
||||
<template #name-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
:text="row.original.name"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip> </span>
|
||||
<span v-else>
|
||||
<span v-else class="block truncate">
|
||||
<UTooltip
|
||||
:text="row.name"
|
||||
:text="row.original.name"
|
||||
>
|
||||
{{dataType.templateColumns.find(i => i.key === "name").maxLength ? (row.name.length > dataType.templateColumns.find(i => i.key === "name").maxLength ? `${row.name.substring(0,dataType.templateColumns.find(i => i.key === "name").maxLength)}...` : row.name ) : row.name}}
|
||||
<span class="block truncate">
|
||||
{{ truncateValue(row.original.name, dataType.templateColumns.find(i => i.key === "name")?.maxLength) }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
</template>
|
||||
<template #fullName-data="{row}">
|
||||
<template #fullName-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.fullName}}
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.fullName }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.fullName}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.fullName }}
|
||||
</span>
|
||||
</template>
|
||||
<template #licensePlate-data="{row}">
|
||||
<template #licensePlate-cell="{row}">
|
||||
<span
|
||||
v-if="row.id === items[selectedItem].id"
|
||||
class="text-primary-500 font-bold">{{row.licensePlate}}
|
||||
v-if="row.original.id === items[selectedItem]?.id"
|
||||
class="block truncate text-primary-500 font-bold">{{ row.original.licensePlate }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{row.licensePlate}}
|
||||
<span v-else class="block truncate">
|
||||
{{ row.original.licensePlate }}
|
||||
</span>
|
||||
</template>
|
||||
<template
|
||||
v-for="column in dataType.templateColumns.filter(i => i.key !== 'name' && i.key !== 'fullName' && i.key !== 'licensePlate' && !i.disabledInTable)"
|
||||
v-slot:[`${column.key}-data`]="{row}">
|
||||
<component v-if="column.component" :is="column.component" :row="row"></component>
|
||||
<span v-else-if="row[column.key]">
|
||||
<UTooltip :text="row[column.key]">
|
||||
{{row[column.key] ? `${column.maxLength ? (row[column.key].length > column.maxLength ? `${row[column.key].substring(0,column.maxLength)}...` : row[column.key]) : row[column.key]} ${column.unit ? column.unit : ''}`: ''}}
|
||||
v-slot:[`${column.key}-cell`]="{row}">
|
||||
<component v-if="column.component" :is="column.component" :row="row.original"></component>
|
||||
<span v-else-if="row.original[column.key]" class="block truncate">
|
||||
<UTooltip :text="String(row.original[column.key])">
|
||||
<span class="block truncate">
|
||||
{{ `${truncateValue(row.original[column.key], column.maxLength)}${column.unit ? ` ${column.unit}` : ''}` }}
|
||||
</span>
|
||||
</UTooltip>
|
||||
</span>
|
||||
|
||||
@@ -550,7 +583,7 @@ const handleFilterChange = async (action,column) => {
|
||||
v-if="searchString.length > 0"
|
||||
icon="i-heroicons-x-mark"
|
||||
variant="ghost"
|
||||
color="rose"
|
||||
color="error"
|
||||
@click="clearSearchString()"
|
||||
|
||||
/>
|
||||
@@ -687,7 +720,7 @@ const handleFilterChange = async (action,column) => {
|
||||
"
|
||||
>
|
||||
<UButton
|
||||
color="rose"
|
||||
color="error"
|
||||
variant="outline"
|
||||
class="flex-1"
|
||||
@click="resetMobileFilters"
|
||||
|
||||
@@ -72,7 +72,7 @@ const filteredRows = computed(() => {
|
||||
</template>
|
||||
</UDashboardToolbar>
|
||||
<UTable
|
||||
:rows="filteredRows"
|
||||
:data="filteredRows"
|
||||
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: `Keine Tickets anzuzeigen` }"
|
||||
@select="(i) => router.push(`/support/${i.id}`)"
|
||||
:columns="normalizeTableColumns([{key:'created_at',label:'Datum'}, ...profileStore.currentTenant === 5 ? [{key:'tenant',label:'Tenant'}] : [],{key:'status',label:'Status'},{key:'title',label:'Titel'},{key:'created_by',label:'Ersteller'},{key:'ticketmessages',label:'Nachrichten'}])"
|
||||
|
||||
@@ -458,7 +458,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
<UTable
|
||||
v-else-if="filteredTasks.length"
|
||||
:rows="filteredTasks"
|
||||
:data="filteredTasks"
|
||||
:columns="normalizedListColumns"
|
||||
@select="(task) => openTaskViaRoute(task)"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user