Merge branch 'devCorrected' into 'beta'

Dev corrected

See merge request fedeo/software!33
This commit is contained in:
2025-11-10 11:14:31 +00:00
6 changed files with 107 additions and 34 deletions

View File

@@ -38,6 +38,20 @@ export function useStaffTime() {
}) })
} }
async function submit(id: string) {
return await $api<StaffTimeEntry>(`/api/staff/time/${id}`, {
method: 'PUT',
body: { state: 'submitted' },
})
}
async function approve(id: string) {
return await $api<StaffTimeEntry>(`/api/staff/time/${id}`, {
method: 'PUT',
body: { state: 'approved' },
})
}
async function get(id: string) { async function get(id: string) {
return await $api<StaffTimeEntry>(`/api/staff/time/${id}`, { method: 'GET' }) return await $api<StaffTimeEntry>(`/api/staff/time/${id}`, { method: 'GET' })
} }
@@ -50,5 +64,5 @@ export function useStaffTime() {
return await $api(`/api/staff/time/${id}`, { method: 'PUT', body: data }) return await $api(`/api/staff/time/${id}`, { method: 'PUT', body: data })
} }
return { list, start, stop, get, create, update } return { list, start, stop,submit,approve, get, create, update }
} }

View File

@@ -2,7 +2,7 @@
import { useStaffTime } from '~/composables/useStaffTime' import { useStaffTime } from '~/composables/useStaffTime'
import { useAuthStore } from '~/stores/auth' import { useAuthStore } from '~/stores/auth'
const { list, start, stop } = useStaffTime() const { list, start, stop, submit,approve } = useStaffTime()
const auth = useAuthStore() const auth = useAuthStore()
const router = useRouter() const router = useRouter()
@@ -51,6 +51,16 @@ function handleEdit(entry: any) {
showModal.value = true showModal.value = true
} }
async function handleSubmit(entry: any) {
await submit(entry.id)
await load()
}
async function handleApprove(entry: any) {
await approve(entry.id)
await load()
}
onMounted(async () => { onMounted(async () => {
await loadUsers() await loadUsers()
await load() await load()
@@ -115,14 +125,19 @@ onMounted(async () => {
/> />
<!-- 🔹 Button zur Auswertung --> <!-- 🔹 Button zur Auswertung -->
<UTooltip
:text="selectedUser ? 'Anwesenheiten des Mitarbeiters auswerten' : 'Mitarbeiter für die Auswertung auswählen'"
>
<UButton <UButton
v-if="selectedUser" :disabled="!selectedUser"
color="gray" color="gray"
icon="i-heroicons-chart-bar" icon="i-heroicons-chart-bar"
label="Auswertung" label="Auswertung"
variant="soft" variant="soft"
@click="router.push(`/staff/time/${selectedUser}/evaluate`)" @click="router.push(`/staff/time/${selectedUser}/evaluate`)"
/> />
</UTooltip>
</div> </div>
</template> </template>
</UDashboardToolbar> </UDashboardToolbar>
@@ -131,15 +146,15 @@ onMounted(async () => {
<UDashboardPanelContent> <UDashboardPanelContent>
<UTable <UTable
:rows="entries" :rows="entries"
@select="(row) => handleEdit(row)"
:columns="[ :columns="[
{ key: 'actions', label: '' },
{ key: 'state', label: 'Status' }, { key: 'state', label: 'Status' },
{ key: 'started_at', label: 'Start' }, { key: 'started_at', label: 'Start' },
{ key: 'stopped_at', label: 'Ende' }, { key: 'stopped_at', label: 'Ende' },
{ key: 'duration_minutes', label: 'Dauer' }, { key: 'duration_minutes', label: 'Dauer' },
{ key: 'description', label: 'Beschreibung' }, { key: 'description', label: 'Beschreibung' },
...(canViewAll ? [{ key: 'user_name', label: 'Benutzer' }] : []), ...(canViewAll ? [{ key: 'user_name', label: 'Benutzer' }] : []),
{ key: 'actions', label: '' },
]" ]"
> >
<template #state-data="{row}"> <template #state-data="{row}">
@@ -163,7 +178,40 @@ onMounted(async () => {
{{ row.user_id ? users.find(i => i.user_id === row.user_id).full_name : '-' }} {{ row.user_id ? users.find(i => i.user_id === row.user_id).full_name : '-' }}
</template> </template>
<template #actions-data="{ row }"> <template #actions-data="{ row }">
<UButton variant="ghost" icon="i-heroicons-pencil-square" @click="handleEdit(row)" /> <UTooltip
text="Zeit genehmigen"
v-if="row.state === 'submitted'"
>
<UButton
variant="ghost"
icon="i-heroicons-check-circle"
@click="handleApprove(row)"
/>
</UTooltip>
<UTooltip
text="Zeit einreichen"
v-if="row.state === 'draft'"
>
<UButton
variant="ghost"
icon="i-heroicons-arrow-right-end-on-rectangle"
@click="handleSubmit(row)"
/>
</UTooltip>
<UTooltip
text="Zeit bearbeiten"
v-if="row.state === 'draft'"
>
<UButton
variant="ghost"
icon="i-heroicons-pencil-square"
@click="handleEdit(row)"
/>
</UTooltip>
</template> </template>
</UTable> </UTable>
</UDashboardPanelContent> </UDashboardPanelContent>

View File

@@ -86,9 +86,7 @@ const changePage = (number) => {
setupPage() setupPage()
} }
const resetColum = (column) => {
columnsToFilter.value[column] = itemsMeta.value.distinctValues[column]
}
const changeSort = (column) => { const changeSort = (column) => {
if(sort.value.column === column) { if(sort.value.column === column) {
@@ -131,7 +129,11 @@ const setupPage = async () => {
items.value = data items.value = data
itemsMeta.value = meta itemsMeta.value = meta
if(!initialSetupDone.value){ if(!initialSetupDone.value){
Object.keys(itemsMeta.value.distinctValues).forEach(distinctValue => { Object.keys(tempStore.filters[type] || {}).forEach((column) => {
columnsToFilter.value[column] = tempStore.filters[type][column]
})
Object.keys(itemsMeta.value.distinctValues).filter(i => !Object.keys(tempStore.filters[type] || {}).includes(i)).forEach(distinctValue => {
columnsToFilter.value[distinctValue] = itemsMeta.value.distinctValues[distinctValue] columnsToFilter.value[distinctValue] = itemsMeta.value.distinctValues[distinctValue]
}) })
} }
@@ -144,8 +146,14 @@ const setupPage = async () => {
setupPage() setupPage()
const handleFilterChange = async (action,column) => {
if(action === 'reset') {
columnsToFilter.value[column] = itemsMeta.value.distinctValues[column]
} else if(action === 'change') {
tempStore.modifyFilter(type,column,columnsToFilter.value[column])
}
setupPage()
}
@@ -297,7 +305,7 @@ setupPage()
sort-mode="manual" sort-mode="manual"
v-model:sort="sort" v-model:sort="sort"
@update:sort="setupPage" @update:sort="setupPage"
v-if="dataType && columns && items.length > 0" v-if="dataType && columns && items.length > 0 && !loading"
:rows="items" :rows="items"
:columns="columns" :columns="columns"
class="w-full" class="w-full"
@@ -328,7 +336,7 @@ setupPage()
:options="itemsMeta?.distinctValues?.[column.key]" :options="itemsMeta?.distinctValues?.[column.key]"
v-model="columnsToFilter[column.key]" v-model="columnsToFilter[column.key]"
multiple multiple
@change="setupPage" @change="handleFilterChange('change', column.key)"
searchable searchable
searchable-placeholder="Suche..." searchable-placeholder="Suche..."
:search-attributes="[column.key]" :search-attributes="[column.key]"
@@ -367,7 +375,7 @@ setupPage()
v-if="columnsToFilter[column.key]?.length !== itemsMeta.distinctValues?.[column.key]?.length && column.distinct" v-if="columnsToFilter[column.key]?.length !== itemsMeta.distinctValues?.[column.key]?.length && column.distinct"
> >
<UButton <UButton
@click="resetColum(column.key)" @click="handleFilterChange('reset',column.key)"
variant="outline" variant="outline"
color="rose" color="rose"
> >
@@ -428,7 +436,7 @@ setupPage()
</UTable> </UTable>
<UCard <UCard
class="w-1/3 mx-auto mt-10" class="w-1/3 mx-auto mt-10"
v-else v-else-if="!loading"
> >
<div <div
class="flex flex-col text-center" class="flex flex-col text-center"
@@ -442,6 +450,7 @@ setupPage()
</UCard> </UCard>
<UProgress v-else animation="carousel" class="w-3/4 mx-auto mt-5"></UProgress>
</template> </template>
<style scoped> <style scoped>

View File

@@ -35,9 +35,6 @@ export const useAuthStore = defineStore("auth", {
console.log("Auth initStore") console.log("Auth initStore")
await this.fetchMe() await this.fetchMe()
const tempStore = useTempStore()
if(this.profile.temp_config) tempStore.setStoredTempConfig(this.profile.temp_config)
if(this.activeTenant > 0) { if(this.activeTenant > 0) {
this.loading = false this.loading = false
if(useCapacitor().getIsNative()) { if(useCapacitor().getIsNative()) {
@@ -99,6 +96,8 @@ export const useAuthStore = defineStore("auth", {
async fetchMe(jwt= null) { async fetchMe(jwt= null) {
console.log("Auth fetchMe") console.log("Auth fetchMe")
const tempStore = useTempStore()
try { try {
const me = await useNuxtApp().$api("/api/me", { const me = await useNuxtApp().$api("/api/me", {
headers: { Authorization: `Bearer ${jwt}`, headers: { Authorization: `Bearer ${jwt}`,
@@ -117,6 +116,8 @@ export const useAuthStore = defineStore("auth", {
this.profile = me.profile this.profile = me.profile
if(this.profile.temp_config) tempStore.setStoredTempConfig(this.profile.temp_config)
if(me.activeTenant > 0) { if(me.activeTenant > 0) {
this.activeTenant = me.activeTenant this.activeTenant = me.activeTenant
this.activeTenantData = me.tenants.find(i => i.id === me.activeTenant) this.activeTenantData = me.tenants.find(i => i.id === me.activeTenant)

View File

@@ -47,10 +47,7 @@ import sepaDate from "~/components/columnRenderings/sepaDate.vue";
// @ts-ignore // @ts-ignore
export const useDataStore = defineStore('data', () => { export const useDataStore = defineStore('data', () => {
const profileStore = useProfileStore()
const toast = useToast()
const router = useRouter()
const modal = useModal()
const dataTypes = { const dataTypes = {
tasks: { tasks: {
@@ -1088,9 +1085,9 @@ export const useDataStore = defineStore('data', () => {
}, },
sortable: true sortable: true
},{ },{
key: "phase", key: "active_phase",
label: "Phase", label: "Phase",
component: phase distinct:true
},{ },{
key: "name", key: "name",
label: "Name", label: "Name",

View File

@@ -17,6 +17,7 @@ export const useTempStore = defineStore('temp', () => {
columns: columns.value, columns: columns.value,
pages: pages.value, pages: pages.value,
settings: settings.value, settings: settings.value,
filters: filters.value
} }
await useNuxtApp().$api(`/api/profiles/${auth.profile.id}`,{ await useNuxtApp().$api(`/api/profiles/${auth.profile.id}`,{
@@ -30,6 +31,7 @@ export const useTempStore = defineStore('temp', () => {
columns.value = config.columns columns.value = config.columns
pages.value = config.pages pages.value = config.pages
settings.value = config.settings settings.value = config.settings
filters.value = config.filters || {}
} }
function modifySearchString(type,input) { function modifySearchString(type,input) {
@@ -42,8 +44,10 @@ export const useTempStore = defineStore('temp', () => {
storeTempConfig() storeTempConfig()
} }
function modifyFilter(type,input) { function modifyFilter(domain,type,input) {
filters.value[type] = input if(!filters.value[domain]) filters.value[domain] = {}
filters.value[domain][type] = input
storeTempConfig() storeTempConfig()
} }