137 lines
6.5 KiB
JavaScript
137 lines
6.5 KiB
JavaScript
import { createModuleApi } from '/mobile/shared/api.js';
|
|
|
|
const inventurApi = createModuleApi('Lager/Inventur');
|
|
|
|
export default {
|
|
name: 'StocktakeList',
|
|
emits: ['select'],
|
|
props: {
|
|
user: Object
|
|
},
|
|
|
|
setup(props, { emit }) {
|
|
const { ref, onMounted } = Vue;
|
|
|
|
const stocktakes = ref([]);
|
|
const isLoading = ref(true);
|
|
const error = ref('');
|
|
|
|
const fetchStocktakes = async () => {
|
|
isLoading.value = true;
|
|
error.value = '';
|
|
|
|
try {
|
|
const result = await inventurApi.get('getActiveStocktakes');
|
|
|
|
if (result.success) {
|
|
stocktakes.value = result.stocktakes;
|
|
} else {
|
|
error.value = result.error || 'Fehler beim Laden';
|
|
}
|
|
} catch (e) {
|
|
error.value = 'Netzwerkfehler';
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
};
|
|
|
|
const selectStocktake = (stocktake) => {
|
|
emit('select', stocktake);
|
|
};
|
|
|
|
onMounted(() => {
|
|
fetchStocktakes();
|
|
});
|
|
|
|
return {
|
|
stocktakes,
|
|
isLoading,
|
|
error,
|
|
fetchStocktakes,
|
|
selectStocktake
|
|
};
|
|
},
|
|
|
|
template: `
|
|
<div class="h-full flex flex-col">
|
|
<!-- Refresh bar -->
|
|
<div class="flex items-center justify-between px-3 py-2 bg-white dark:bg-slate-800 border-b border-slate-200 dark:border-slate-700">
|
|
<span class="text-sm font-medium text-slate-600 dark:text-slate-300">Aktive Inventuren</span>
|
|
<button
|
|
@click="fetchStocktakes"
|
|
class="p-2 rounded-full text-slate-500 hover:bg-slate-100 dark:hover:bg-slate-700 transition"
|
|
:disabled="isLoading"
|
|
>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" :class="{ 'animate-spin': isLoading }" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="flex-1 overflow-y-auto p-3">
|
|
<!-- Loading -->
|
|
<div v-if="isLoading" class="space-y-3">
|
|
<div v-for="i in 3" :key="i" class="bg-white dark:bg-slate-800 p-4 rounded-xl shadow-sm animate-pulse">
|
|
<div class="h-5 bg-slate-200 dark:bg-slate-700 rounded w-3/4 mb-2"></div>
|
|
<div class="h-4 bg-slate-200 dark:bg-slate-700 rounded w-1/2 mb-3"></div>
|
|
<div class="h-3 bg-slate-200 dark:bg-slate-700 rounded w-1/3"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Error -->
|
|
<div v-else-if="error" class="text-center py-8">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto text-red-400 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<p class="text-slate-500 dark:text-slate-400 mb-4">{{ error }}</p>
|
|
<button @click="fetchStocktakes" class="px-4 py-2 bg-primary text-white rounded-lg font-medium">
|
|
Erneut versuchen
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Empty -->
|
|
<div v-else-if="stocktakes.length === 0" class="text-center py-8">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mx-auto text-slate-300 dark:text-slate-600 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
|
</svg>
|
|
<p class="text-slate-500 dark:text-slate-400">Keine aktiven Inventuren</p>
|
|
</div>
|
|
|
|
<!-- Stocktake List -->
|
|
<div v-else class="bg-white dark:bg-slate-800 rounded-xl overflow-hidden shadow-sm">
|
|
<button
|
|
v-for="(stocktake, index) in stocktakes"
|
|
:key="stocktake.id"
|
|
@click="selectStocktake(stocktake)"
|
|
:class="[
|
|
'w-full text-left px-4 py-3 hover:bg-slate-50 dark:hover:bg-slate-700/50 active:bg-slate-100 dark:active:bg-slate-700 transition',
|
|
index !== stocktakes.length - 1 ? 'border-b border-slate-100 dark:border-slate-700' : ''
|
|
]"
|
|
>
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex-1 min-w-0">
|
|
<h3 class="font-medium text-slate-800 dark:text-white truncate">
|
|
{{ stocktake.title || 'Inventur #' + stocktake.stocktakeNumber }}
|
|
</h3>
|
|
<p class="text-sm text-slate-500 dark:text-slate-400 mt-0.5">
|
|
{{ stocktake.locationName }}
|
|
</p>
|
|
</div>
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-slate-400 flex-shrink-0 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
</svg>
|
|
</div>
|
|
<div class="flex items-center mt-2 text-xs text-slate-400 dark:text-slate-500">
|
|
<span class="font-medium text-slate-600 dark:text-slate-400">{{ stocktake.totalScannedItems || 0 }}</span>
|
|
<span class="ml-1">Artikel</span>
|
|
<span class="mx-2">·</span>
|
|
<span>{{ stocktake.startedAt || 'Nicht gestartet' }}</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
};
|