BETA for new DB

This commit is contained in:
2025-12-08 14:40:21 +01:00
parent 9bfb880f7b
commit 888336dd04
8 changed files with 256 additions and 68 deletions

View File

@@ -155,7 +155,6 @@ const links = computed(() => {
label: "Anwesenheiten",
to: "/staff/time",
icon: "i-heroicons-clock",
disabled: true
}] : [],
/*... has("absencerequests") ? [{
label: "Abwesenheiten",
@@ -186,7 +185,6 @@ const links = computed(() => {
label: "Eingangsbelege",
to: "/incomingInvoices",
icon: "i-heroicons-document-text",
disabled: true
},{
label: "Kostenstellen",
to: "/standardEntity/costcentres",
@@ -195,7 +193,6 @@ const links = computed(() => {
label: "Buchungskonten",
to: "/accounts",
icon: "i-heroicons-document-text",
disabled: true
},{
label: "zusätzliche Buchungskonten",
to: "/standardEntity/ownaccounts",
@@ -205,7 +202,6 @@ const links = computed(() => {
label: "Bank",
to: "/banking",
icon: "i-heroicons-document-text",
disabled: true
},
]
}],
@@ -312,7 +308,6 @@ const links = computed(() => {
label: "Nummernkreise",
to: "/settings/numberRanges",
icon: "i-heroicons-clipboard-document-list",
disabled: true
},/*{
label: "Rollen",
to: "/roles",
@@ -321,17 +316,14 @@ const links = computed(() => {
label: "E-Mail Konten",
to: "/settings/emailaccounts",
icon: "i-heroicons-envelope",
disabled: true
},{
label: "Bankkonten",
to: "/settings/banking",
icon: "i-heroicons-currency-euro",
disabled: true
},{
label: "Textvorlagen",
to: "/settings/texttemplates",
icon: "i-heroicons-clipboard-document-list",
disabled: true
},/*{
label: "Eigene Felder",
to: "/settings/ownfields",
@@ -340,12 +332,10 @@ const links = computed(() => {
label: "Firmeneinstellungen",
to: "/settings/tenant",
icon: "i-heroicons-building-office",
disabled: true
},{
label: "Projekttypen",
to: "/projecttypes",
icon: "i-heroicons-clipboard-document-list",
disabled: true
},{
label: "Export",
to: "/export",

View File

@@ -3,55 +3,75 @@ import dayjs from "dayjs";
const props = defineProps<{
modelValue: boolean;
entry?: null;
entry?: any | null;
users: any[];
canSelectUser: boolean;
defaultUserId: string;
}>();
const emit = defineEmits(["update:modelValue", "saved"]);
const { create, update } = useStaffTime();
// v-model für das Modal
const show = computed({
get: () => props.modelValue,
set: (v: boolean) => emit("update:modelValue", v),
});
// 🧱 Lokale reactive Kopie, die beim Öffnen aus props.entry befüllt wird
const local = reactive<{
id?: string;
description: string;
started_at: string;
stopped_at: string | null;
type: string;
}>({
// 🌈 Typen
const typeOptions = [
{ label: "Arbeitszeit", value: "work" },
{ label: "Urlaub", value: "vacation" },
{ label: "Krankheit", value: "sick" },
{ label: "Feiertag", value: "holiday" },
];
// Lokaler State
const local = reactive({
id: "",
user_id: "", // 👈 Mitarbeiter
description: "",
started_at: dayjs().startOf("hour").format("YYYY-MM-DDTHH:mm"),
stopped_at: dayjs().add(1, "hour").format("YYYY-MM-DDTHH:mm"),
started_at: "",
stopped_at: "",
type: "work",
vacation_reason: "",
sick_reason: "",
});
// 📡 Wenn das Modal geöffnet wird, Entry-Daten übernehmen
// 📡 ENTRY —> LOCAL
watch(
() => props.entry,
(val) => {
if (val) {
Object.assign(local, {
id: val.id,
user_id: val.user_id, // 👈 Mitarbeiter vorbelegen
description: val.description || "",
started_at: dayjs(val.started_at).format("YYYY-MM-DDTHH:mm"),
stopped_at: val.stopped_at
? dayjs(val.stopped_at).format("YYYY-MM-DDTHH:mm")
: dayjs(val.started_at).add(1, "hour").format("YYYY-MM-DDTHH:mm"),
type: val.type || "work",
started_at:
val.type === "vacation"
? dayjs(val.started_at).format("YYYY-MM-DD")
: dayjs(val.started_at).format("YYYY-MM-DDTHH:mm"),
stopped_at:
val.type === "vacation"
? dayjs(val.stopped_at).format("YYYY-MM-DD")
: dayjs(val.stopped_at).format("YYYY-MM-DDTHH:mm"),
vacation_reason: val.vacation_reason || "",
sick_reason: val.sick_reason || "",
});
} else {
Object.assign(local, {
id: "",
user_id: props.defaultUserId, // 👈 Neuer Eintrag → aktueller Nutzer
description: "",
started_at: dayjs().startOf("hour").format("YYYY-MM-DDTHH:mm"),
stopped_at: dayjs().add(1, "hour").format("YYYY-MM-DDTHH:mm"),
type: "work",
started_at: dayjs().format("YYYY-MM-DDTHH:mm"),
stopped_at: dayjs().add(1, "hour").format("YYYY-MM-DDTHH:mm"),
vacation_reason: "",
sick_reason: "",
});
}
},
@@ -63,13 +83,27 @@ const loading = ref(false);
async function handleSubmit() {
loading.value = true;
try {
const payload = {
description: local.description,
started_at: dayjs(local.started_at).toISOString(),
stopped_at: local.stopped_at ? dayjs(local.stopped_at).toISOString() : null,
const payload: any = {
user_id: local.user_id, // 👈 immer senden
type: local.type,
};
if (local.type === "vacation") {
payload.started_at = dayjs(local.started_at).startOf("day").toISOString();
payload.stopped_at = dayjs(local.stopped_at).endOf("day").toISOString();
payload.vacation_reason = local.vacation_reason;
} else {
payload.started_at = dayjs(local.started_at).toISOString();
payload.stopped_at = local.stopped_at
? dayjs(local.stopped_at).toISOString()
: null;
payload.description = local.description;
if (local.type === "sick") {
payload.sick_reason = local.sick_reason;
}
}
if (local.id) {
await update(local.id, payload);
} else {
@@ -84,6 +118,7 @@ async function handleSubmit() {
}
</script>
<template>
<UModal v-model="show" :ui="{ width: 'w-full sm:max-w-md' }" :key="local.id || 'new'">
<UCard>
@@ -94,18 +129,72 @@ async function handleSubmit() {
</template>
<UForm @submit.prevent="handleSubmit" class="space-y-4">
<UFormGroup label="Beschreibung" name="description">
<UInput v-model="local.description" placeholder="Was wurde gemacht?" />
<!-- 👥 Mitarbeiter-Auswahl -->
<UFormGroup label="Mitarbeiter" v-if="props.canSelectUser">
<USelectMenu
v-model="local.user_id"
:options="props.users.map(u => ({
label: u.full_name || u.email,
value: u.user_id
}))"
placeholder="Mitarbeiter wählen"
option-attribute="label"
value-attribute="value"
/>
</UFormGroup>
<UFormGroup label="Startzeit" name="started_at">
<UInput v-model="local.started_at" type="datetime-local" />
<!-- TYPE -->
<UFormGroup label="Typ">
<USelect v-model="local.type" :options="typeOptions" />
</UFormGroup>
<UFormGroup label="Endzeit" name="stopped_at">
<UInput v-model="local.stopped_at" type="datetime-local" />
</UFormGroup>
<!-- VACATION -->
<template v-if="local.type === 'vacation'">
<UFormGroup label="Urlaubsgrund">
<UInput v-model="local.vacation_reason" />
</UFormGroup>
<UFormGroup label="Start (Tag)">
<UInput v-model="local.started_at" type="date" />
</UFormGroup>
<UFormGroup label="Ende (Tag)">
<UInput v-model="local.stopped_at" type="date" />
</UFormGroup>
</template>
<!-- SICK -->
<template v-else-if="local.type === 'sick'">
<UFormGroup label="Krankheitsgrund">
<UInput v-model="local.sick_reason" />
</UFormGroup>
<UFormGroup label="Start (Tag)">
<UInput v-model="local.started_at" type="date" />
</UFormGroup>
<UFormGroup label="Ende (Tag)">
<UInput v-model="local.stopped_at" type="date" />
</UFormGroup>
</template>
<!-- WORK / OTHER -->
<template v-else>
<UFormGroup label="Beschreibung">
<UInput v-model="local.description" placeholder="Was wurde gemacht?" />
</UFormGroup>
<UFormGroup label="Startzeit">
<UInput v-model="local.started_at" type="datetime-local" />
</UFormGroup>
<UFormGroup label="Endzeit">
<UInput v-model="local.stopped_at" type="datetime-local" />
</UFormGroup>
</template>
<!-- ACTIONS -->
<div class="flex justify-end gap-2 mt-4">
<UButton color="gray" label="Abbrechen" @click="show = false" />
<UButton color="primary" :loading="loading" type="submit" label="Speichern" />
@@ -114,3 +203,4 @@ async function handleSubmit() {
</UCard>
</UModal>
</template>