feat: infrastructure assets management with warranty tracking and EAN lookup integration
This commit is contained in:
@@ -6,6 +6,7 @@ import { Head, Link, useForm } from '@inertiajs/vue3'
|
||||
const props = defineProps({
|
||||
services: Array,
|
||||
fournisseurs: Array,
|
||||
communes: Array,
|
||||
categories: Array,
|
||||
articles: Array,
|
||||
})
|
||||
@@ -13,6 +14,7 @@ const props = defineProps({
|
||||
const form = useForm({
|
||||
service_id: '',
|
||||
fournisseur_id: '',
|
||||
commune_id: '',
|
||||
objet: '',
|
||||
description: '',
|
||||
justification: '',
|
||||
@@ -77,6 +79,15 @@ function submit() {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Ville / Commune</label>
|
||||
<select v-model="form.commune_id"
|
||||
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-blue-500 focus:outline-none">
|
||||
<option value="">— Non défini —</option>
|
||||
<option v-for="c in communes" :key="c.id" :value="c.id">{{ c.nom }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Priorité</label>
|
||||
<select v-model="form.priorite"
|
||||
|
||||
@@ -8,6 +8,7 @@ const props = defineProps({
|
||||
commande: Object,
|
||||
services: Array,
|
||||
fournisseurs: Array,
|
||||
communes: Array,
|
||||
categories: Array,
|
||||
articles: Array,
|
||||
})
|
||||
@@ -15,6 +16,7 @@ const props = defineProps({
|
||||
const form = useForm({
|
||||
service_id: props.commande.service_id,
|
||||
fournisseur_id: props.commande.fournisseur_id ?? '',
|
||||
commune_id: props.commande.commune_id ?? '',
|
||||
objet: props.commande.objet,
|
||||
description: props.commande.description ?? '',
|
||||
justification: props.commande.justification ?? '',
|
||||
@@ -76,6 +78,14 @@ const showReceived = ['commandee','partiellement_recue','recue_complete'].includ
|
||||
<option v-for="f in fournisseurs" :key="f.id" :value="f.id">{{ f.nom }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Ville / Commune</label>
|
||||
<select v-model="form.commune_id"
|
||||
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2 text-sm shadow-sm focus:border-blue-500 focus:outline-none">
|
||||
<option value="">— Non défini —</option>
|
||||
<option v-for="c in communes" :key="c.id" :value="c.id">{{ c.nom }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700">Priorité</label>
|
||||
<select v-model="form.priorite"
|
||||
|
||||
@@ -11,13 +11,24 @@ const props = defineProps({
|
||||
commandes: Object,
|
||||
services: Array,
|
||||
fournisseurs: Array,
|
||||
communes: Array,
|
||||
filters: Object,
|
||||
})
|
||||
|
||||
const page = usePage()
|
||||
const statuts = page.props.config?.statuts ?? {}
|
||||
|
||||
const filters = reactive({ ...props.filters })
|
||||
const filters = reactive({
|
||||
search: '',
|
||||
service_id: '',
|
||||
fournisseur_id: '',
|
||||
commune_id: '',
|
||||
statut: '',
|
||||
priorite: '',
|
||||
date_from: '',
|
||||
date_to: '',
|
||||
...props.filters
|
||||
})
|
||||
const deleteTarget = ref(null)
|
||||
|
||||
function applyFilters() {
|
||||
@@ -97,6 +108,12 @@ function formatCurrency(v) {
|
||||
<option value="haute">Haute</option>
|
||||
<option value="normale">Normale</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-blue-500 focus:outline-none">
|
||||
<option value="">Toutes communes</option>
|
||||
<option v-for="c in communes" :key="c.id" :value="c.id">{{ c.nom }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 grid gap-3 sm:grid-cols-3">
|
||||
@@ -120,6 +137,7 @@ function formatCurrency(v) {
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">N°</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Objet</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Service</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Ville</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Fournisseur</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-left text-xs font-medium text-gray-500 uppercase">Priorité</th>
|
||||
@@ -141,6 +159,7 @@ function formatCurrency(v) {
|
||||
<p class="truncate text-gray-800">{{ cmd.objet }}</p>
|
||||
</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-gray-600">{{ cmd.service?.nom }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-gray-600">{{ cmd.commune?.nom ?? '—' }}</td>
|
||||
<td class="px-4 py-3 whitespace-nowrap text-gray-600">{{ cmd.fournisseur?.nom ?? '—' }}</td>
|
||||
<td class="px-4 py-3"><StatutBadge :statut="cmd.statut" /></td>
|
||||
<td class="px-4 py-3"><PrioriteBadge :priorite="cmd.priorite" /></td>
|
||||
|
||||
@@ -96,6 +96,10 @@ const transitionColors = {
|
||||
<p class="text-xs text-gray-500">Service demandeur</p>
|
||||
<p class="mt-0.5 font-medium text-gray-900">{{ commande.service?.nom ?? '—' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">Ville / Commune</p>
|
||||
<p class="mt-0.5 font-medium text-gray-900">{{ commande.commune?.nom ?? '—' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">Fournisseur</p>
|
||||
<p class="mt-0.5 font-medium text-gray-900">{{ commande.fournisseur?.nom ?? '—' }}</p>
|
||||
@@ -160,6 +164,35 @@ const transitionColors = {
|
||||
:show-received="['commandee','partiellement_recue','recue_complete','cloturee'].includes(commande.statut)" />
|
||||
</div>
|
||||
|
||||
<!-- Matériels associés (Assets) -->
|
||||
<div v-if="commande.assets?.length" class="rounded-xl bg-white p-5 shadow-sm border border-gray-100">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-sm font-semibold uppercase tracking-wide text-gray-500">Matériels livrés (Assets)</h2>
|
||||
<span class="px-2 py-0.5 rounded-full bg-blue-100 text-blue-700 text-[10px] font-bold uppercase">{{ commande.assets.length }} équipements</span>
|
||||
</div>
|
||||
<div class="divide-y divide-gray-100">
|
||||
<div v-for="asset in commande.assets" :key="asset.id" class="flex items-center justify-between py-3 first:pt-0 last:pb-0">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="mt-1 rounded bg-gray-100 p-2 text-gray-400">
|
||||
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<Link :href="route('assets.show', asset.id)" class="font-medium text-gray-900 hover:text-blue-600 transition-colors">
|
||||
{{ asset.nom }}
|
||||
</Link>
|
||||
<div class="text-xs text-gray-500 font-mono">{{ asset.numero_serie ?? 'Sans S/N' }} • {{ asset.marque }} {{ asset.modele }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="block text-xs font-medium text-gray-900">{{ asset.type }}</span>
|
||||
<span v-if="asset.date_fin_garantie" class="text-[10px] text-gray-500">Garantie jusqu'au {{ formatDate(asset.date_fin_garantie) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notes -->
|
||||
<div v-if="commande.description || commande.justification || commande.notes || commande.notes_fournisseur"
|
||||
class="rounded-xl bg-white p-5 shadow-sm border border-gray-100">
|
||||
|
||||
Reference in New Issue
Block a user