feat(time): add span-based attendance tracking under 2.0
This commit is contained in:
@@ -478,6 +478,12 @@ const links = computed(() => {
|
||||
icon: "i-heroicons-user-group",
|
||||
children: visibleContactsChildren
|
||||
}] : []),
|
||||
...(featureEnabled("staffTime") ? [{
|
||||
label: "2.0",
|
||||
icon: "i-heroicons-sparkles",
|
||||
defaultOpen: false,
|
||||
children: [{ label: "Zeiterfassung", to: "/v2/time", icon: "i-heroicons-clock" }]
|
||||
}] : []),
|
||||
...(visibleStaffChildren.length > 0 ? [{
|
||||
label: "Mitarbeiter",
|
||||
defaultOpen: false,
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
import { useNow } from "@vueuse/core";
|
||||
import { workingMinutes } from "~/utils/staffTimeSpans";
|
||||
|
||||
const profileStore = useProfileStore();
|
||||
const toast = useToast()
|
||||
const staffTime = useStaffTime()
|
||||
|
||||
const runningTimeInfo = ref({})
|
||||
const clock = useNow({ interval: 1000 })
|
||||
const workingDuration = computed(() => {
|
||||
const minutes = workingMinutes(runningTimeInfo.value, clock.value.getTime())
|
||||
return `${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, '0')} h`
|
||||
})
|
||||
|
||||
const projects = ref([])
|
||||
const platform = ref("default")
|
||||
@@ -51,9 +58,12 @@ const stopStartedTime = async () => {
|
||||
<template>
|
||||
<div v-if="runningTimeInfo.started_at">
|
||||
<p>Start: {{dayjs(runningTimeInfo.started_at).format("HH:mm")}}</p>
|
||||
<p>Dauer: {{dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') > 59 ? `${Math.floor(dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') / 60)}:${dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') % 60} h` : dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') + ' min' }}</p>
|
||||
<p>Arbeitszeit: {{ workingDuration }}</p>
|
||||
<p v-if="runningTimeInfo.paused">In Pause</p>
|
||||
<UButton v-if="runningTimeInfo.model === 'spans-v2'" class="mt-2" variant="soft" :to="{ path: '/v2/time', query: { user_id: runningTimeInfo.user_id } }">Anwesenheit bearbeiten</UButton>
|
||||
|
||||
<UFormField
|
||||
v-if="runningTimeInfo.model !== 'spans-v2'"
|
||||
class="mt-2"
|
||||
label="Notizen:"
|
||||
>
|
||||
@@ -62,6 +72,7 @@ const stopStartedTime = async () => {
|
||||
/>
|
||||
</UFormField>
|
||||
<UFormField
|
||||
v-if="runningTimeInfo.model !== 'spans-v2'"
|
||||
class="mt-2"
|
||||
label="Projekt:"
|
||||
>
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
<script setup>
|
||||
import dayjs from "dayjs";
|
||||
import { useNow } from "@vueuse/core";
|
||||
import { workingMinutes } from "~/utils/staffTimeSpans";
|
||||
|
||||
const profileStore = useProfileStore();
|
||||
const toast = useToast()
|
||||
const staffTime = useStaffTime()
|
||||
|
||||
const runningTimeInfo = ref({})
|
||||
const clock = useNow({ interval: 1000 })
|
||||
const workingDuration = computed(() => {
|
||||
const minutes = workingMinutes(runningTimeInfo.value, clock.value.getTime())
|
||||
return `${Math.floor(minutes / 60)}:${String(minutes % 60).padStart(2, '0')} h`
|
||||
})
|
||||
|
||||
const setupPage = async () => {
|
||||
const rows = await staffTime.list({ user_id: profileStore.activeProfile?.user_id || profileStore.activeProfile?.id })
|
||||
@@ -47,9 +54,12 @@ const stopStartedTime = async () => {
|
||||
<template>
|
||||
<div v-if="runningTimeInfo.started_at">
|
||||
<p>Start: {{dayjs(runningTimeInfo.started_at).format("HH:mm")}}</p>
|
||||
<p>Dauer: {{dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') > 59 ? `${Math.floor(dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') / 60)}:${dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') % 60} h` : dayjs().diff(dayjs(runningTimeInfo.started_at),'minutes') + ' min' }}</p>
|
||||
<p>Arbeitszeit: {{ workingDuration }}</p>
|
||||
<p v-if="runningTimeInfo.paused">In Pause</p>
|
||||
<UButton v-if="runningTimeInfo.model === 'spans-v2'" class="mt-2" variant="soft" :to="{ path: '/v2/time', query: { user_id: runningTimeInfo.user_id } }">Anwesenheit bearbeiten</UButton>
|
||||
|
||||
<UFormField
|
||||
v-if="runningTimeInfo.model !== 'spans-v2'"
|
||||
class="mt-2"
|
||||
label="Notizen:"
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ const setupPage = async () => {
|
||||
const checks = await Promise.all(profiles.map(async (profile) => {
|
||||
try {
|
||||
const spans = await useNuxtApp().$api(`/api/staff/time/spans?targetUserId=${profile.user_id || profile.id}`)
|
||||
const openSpan = (spans || []).find((s) => !s.endedAt && s.type === "work")
|
||||
const openSpan = (spans || []).find((s) => !s.endedAt && ["work", "pause"].includes(s.type))
|
||||
if (openSpan) return { profile: profile.id }
|
||||
} catch (e) {
|
||||
return null
|
||||
|
||||
Reference in New Issue
Block a user