Files

159 lines
8.5 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'
import Pagination from '@/Components/Pagination.vue'
import { Head, Link, router } from '@inertiajs/vue3'
import { ref, reactive } from 'vue'
const props = defineProps({
assets: Object,
communes: Array,
types: Array,
filters: Object,
})
const filters = reactive({
search: props.filters.search || '',
type: props.filters.type || '',
commune_id: props.filters.commune_id || '',
})
function applyFilters() {
router.get(route('assets.index'), filters, { preserveState: true, replace: true })
}
function formatDate(d) {
if (!d) return '—'
return new Intl.DateTimeFormat('fr-FR').format(new Date(d))
}
const statutLabels = {
en_service: 'En service',
hors_service: 'Hors service',
en_reparation: 'En réparation',
stock: 'En stock',
}
const statutColors = {
en_service: 'bg-green-100 text-green-800',
hors_service: 'bg-red-100 text-red-800',
en_reparation: 'bg-orange-100 text-orange-800',
stock: 'bg-blue-100 text-blue-800',
}
function checkWarranty(date) {
if (!date) return 'text-gray-400'
const today = new Date()
const exp = new Date(date)
if (exp < today) return 'text-red-600 font-bold'
const diff = (exp - today) / (1000 * 60 * 60 * 24)
if (diff <= 30) return 'text-orange-600 font-bold'
return 'text-gray-600'
}
</script>
<template>
<Head title="Inventaire Infrastructure (Assets)" />
<AuthenticatedLayout>
<template #header>
<div class="flex items-center justify-between">
<h1 class="text-xl font-semibold text-gray-900">Assets (Hardware & Infra)</h1>
<Link :href="route('assets.create')"
class="rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 transition-colors">
+ Nouvel Asset
</Link>
</div>
</template>
<div class="space-y-4">
<!-- Filtres -->
<div class="rounded-xl bg-white p-4 shadow-sm border border-gray-100">
<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
<input v-model="filters.search" @input="applyFilters" type="text" placeholder="Recherche (SN, Nom, Modèle)..."
class="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-indigo-500 focus:outline-none placeholder-gray-400" />
<select v-model="filters.type" @change="applyFilters"
class="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-indigo-500 focus:outline-none">
<option value="">Tous les types</option>
<option v-for="t in types" :key="t" :value="t">{{ t }}</option>
<option value="Serveur">Serveur</option>
<option value="Switch">Switch</option>
<option value="NAS">NAS</option>
<option value="Baie de stockage">Baie de stockage</option>
<option value="Onduleur">Onduleur</option>
</select>
<select v-model="filters.commune_id" @change="applyFilters"
class="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:border-indigo-500 focus:outline-none">
<option value="">Partout (Agglo)</option>
<option v-for="c in communes" :key="c.id" :value="c.id">{{ c.nom }}</option>
</select>
</div>
</div>
<!-- Table -->
<div class="rounded-xl bg-white shadow-sm border border-gray-100 overflow-hidden">
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-100 text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Matériel</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Type</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">S/N</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Ville / Site</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Fin Garantie</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Statut</th>
<th class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-50">
<tr v-for="asset in assets.data" :key="asset.id" class="hover:bg-gray-50 transition-colors">
<td class="px-4 py-3">
<div class="font-medium text-gray-900">{{ asset.nom }}</div>
<div class="text-xs text-gray-500">{{ asset.marque }} {{ asset.modele }}</div>
</td>
<td class="px-4 py-3 whitespace-nowrap text-gray-600">
<span class="px-2 py-0.5 rounded border border-gray-200 bg-gray-50 text-[10px] uppercase font-bold text-gray-500">
{{ asset.type }}
</span>
</td>
<td class="px-4 py-3 whitespace-nowrap font-mono text-xs text-gray-600">{{ asset.numero_serie ?? '—' }}</td>
<td class="px-4 py-3">
<div class="text-gray-900">{{ asset.commune?.nom ?? 'Agglo' }}</div>
<div class="text-xs text-gray-500">{{ asset.emplacement ?? '—' }}</div>
</td>
<td class="px-4 py-3 whitespace-nowrap" :class="checkWarranty(asset.date_fin_garantie)">
{{ formatDate(asset.date_fin_garantie) }}
<span v-if="checkWarranty(asset.date_fin_garantie).includes('red')" class="ml-1" title="Expirée"></span>
<span v-else-if="checkWarranty(asset.date_fin_garantie).includes('orange')" class="ml-1" title="Proche échéance"></span>
</td>
<td class="px-4 py-3 whitespace-nowrap">
<span :class="['px-2 py-0.5 rounded-full text-xs font-medium', statutColors[asset.statut]]">
{{ statutLabels[asset.statut] }}
</span>
</td>
<td class="px-4 py-3 text-center">
<div class="flex items-center justify-center gap-2">
<Link :href="route('assets.show', asset.id)"
class="text-gray-400 hover:text-blue-600 transition-colors" title="Afficher les détails">
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
</svg>
</Link>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div v-if="!assets.data.length" class="py-12 text-center text-gray-400">
Aucun matériel trouvé.
</div>
<div class="px-4 py-3 border-t border-gray-100">
<Pagination :links="assets.links" />
</div>
</div>
</div>
</AuthenticatedLayout>
</template>