308 lines
17 KiB
Vue
308 lines
17 KiB
Vue
<script setup>
|
|
import { useForm, Head, Link } from '@inertiajs/vue3';
|
|
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
|
|
import InputError from '@/Components/InputError.vue';
|
|
import InputLabel from '@/Components/InputLabel.vue';
|
|
import TextInput from '@/Components/TextInput.vue';
|
|
import PrimaryButton from '@/Components/PrimaryButton.vue';
|
|
|
|
const props = defineProps({
|
|
hardware: {
|
|
type: Object,
|
|
default: () => null
|
|
},
|
|
orders: Array,
|
|
isEdit: Boolean,
|
|
});
|
|
|
|
// Initialisation du formulaire Inertia
|
|
const form = useForm({
|
|
name: props.hardware?.data?.name || '',
|
|
type: props.hardware?.data?.type || '',
|
|
brand: props.hardware?.data?.brand || '',
|
|
model: props.hardware?.data?.model || '',
|
|
serial_number: props.hardware?.data?.serial_number || '',
|
|
status: props.hardware?.data?.status || 'en_stock',
|
|
purchase_date: props.hardware?.data?.purchase_date || '',
|
|
commissioning_date: props.hardware?.data?.commissioning_date || '',
|
|
warranty_expiration_date: props.hardware?.data?.warranty_expiration_date || '',
|
|
location: props.hardware?.data?.location || '',
|
|
ip_address: props.hardware?.data?.ip_address || '',
|
|
order_id: props.hardware?.data?.order_id || '',
|
|
notes: props.hardware?.data?.notes || '',
|
|
});
|
|
|
|
// Raccourci pour définir une garantie standard (+3 ans)
|
|
const setStandardWarranty = () => {
|
|
if (form.purchase_date) {
|
|
const purchase = new Date(form.purchase_date);
|
|
purchase.setFullYear(purchase.getFullYear() + 3);
|
|
// Formater au format YYYY-MM-DD
|
|
const yyyy = purchase.getFullYear();
|
|
let mm = purchase.getMonth() + 1;
|
|
let dd = purchase.getDate();
|
|
if (mm < 10) mm = '0' + mm;
|
|
if (dd < 10) dd = '0' + dd;
|
|
form.warranty_expiration_date = `${yyyy}-${mm}-${dd}`;
|
|
} else {
|
|
alert("Veuillez d'abord saisir la date d'achat de l'équipement.");
|
|
}
|
|
};
|
|
|
|
const submit = () => {
|
|
if (props.isEdit) {
|
|
form.put(route('materiels.update', { materiel: props.hardware.data.id }));
|
|
} else {
|
|
form.post(route('materiels.store'));
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Head :title="isEdit ? 'Modifier équipement' : 'Ajouter un équipement'" />
|
|
|
|
<AuthenticatedLayout>
|
|
<template #header>
|
|
<div class="flex items-center justify-between">
|
|
<h2 class="text-xl font-bold leading-tight text-slate-800 dark:text-slate-200">
|
|
{{ isEdit ? `Modifier la fiche : ${hardware.data.name}` : 'Ajouter un équipement à l\'inventaire' }}
|
|
</h2>
|
|
|
|
<Link
|
|
:href="isEdit ? route('materiels.show', { materiel: hardware.data.id }) : route('materiels.index')"
|
|
class="inline-flex items-center px-4 py-2 text-sm font-semibold text-slate-700 bg-white border border-slate-300 rounded-lg hover:bg-slate-50 dark:bg-slate-900 dark:text-slate-300 dark:border-slate-850 dark:hover:bg-slate-800 transition-colors"
|
|
>
|
|
Annuler
|
|
</Link>
|
|
</div>
|
|
</template>
|
|
|
|
<div class="py-6">
|
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl shadow-sm overflow-hidden p-6">
|
|
<form @submit.prevent="submit" class="space-y-6">
|
|
|
|
<!-- Section : Identification -->
|
|
<div>
|
|
<h3 class="text-sm font-bold text-sky-600 dark:text-sky-400 uppercase tracking-wider border-b border-slate-100 dark:border-slate-850 pb-2 mb-4">
|
|
Identification du matériel
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<InputLabel for="name" value="Nom d'usage de l'équipement" />
|
|
<TextInput
|
|
id="name"
|
|
type="text"
|
|
class="mt-1 block w-full"
|
|
v-model="form.name"
|
|
required
|
|
placeholder="ex: Serveur Hyper-V 01"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.name" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="type" value="Type de matériel" />
|
|
<select
|
|
id="type"
|
|
v-model="form.type"
|
|
required
|
|
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm"
|
|
>
|
|
<option value="" disabled>Sélectionner un type</option>
|
|
<option value="serveur">Serveur</option>
|
|
<option value="switch">Switch</option>
|
|
<option value="routeur">Routeur</option>
|
|
<option value="onduleur">Onduleur</option>
|
|
<option value="stockage">Stockage (NAS/SAN)</option>
|
|
<option value="pare-feu">Pare-feu</option>
|
|
<option value="poste_travail">Poste de travail</option>
|
|
<option value="autre">Autre</option>
|
|
</select>
|
|
<InputError class="mt-2" :message="form.errors.type" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="brand" value="Marque / Constructeur" />
|
|
<TextInput
|
|
id="brand"
|
|
type="text"
|
|
class="mt-1 block w-full"
|
|
v-model="form.brand"
|
|
required
|
|
placeholder="ex: Dell"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.brand" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="model" value="Modèle" />
|
|
<TextInput
|
|
id="model"
|
|
type="text"
|
|
class="mt-1 block w-full"
|
|
v-model="form.model"
|
|
required
|
|
placeholder="ex: PowerEdge R750"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.model" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="serial_number" value="Numéro de série physique" />
|
|
<TextInput
|
|
id="serial_number"
|
|
type="text"
|
|
class="mt-1 block w-full font-mono uppercase"
|
|
v-model="form.serial_number"
|
|
required
|
|
placeholder="ex: CN-0ABC12-DEF34-..."
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.serial_number" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="status" value="Statut courant" />
|
|
<select
|
|
id="status"
|
|
v-model="form.status"
|
|
required
|
|
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm"
|
|
>
|
|
<option value="en_stock">En stock / Rechange</option>
|
|
<option value="en_service">En service / Actif</option>
|
|
<option value="en_panne">En panne / Maintenance</option>
|
|
<option value="au_rebut">Au rebut / Declassé</option>
|
|
</select>
|
|
<InputError class="mt-2" :message="form.errors.status" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section : Cycle de vie & Dates -->
|
|
<div>
|
|
<h3 class="text-sm font-bold text-sky-600 dark:text-sky-400 uppercase tracking-wider border-b border-slate-100 dark:border-slate-850 pb-2 mb-4">
|
|
Cycle de vie & Garantie
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div>
|
|
<InputLabel for="purchase_date" value="Date d'achat" />
|
|
<TextInput
|
|
id="purchase_date"
|
|
type="date"
|
|
class="mt-1 block w-full"
|
|
v-model="form.purchase_date"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.purchase_date" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="commissioning_date" value="Date de mise en service" />
|
|
<TextInput
|
|
id="commissioning_date"
|
|
type="date"
|
|
class="mt-1 block w-full"
|
|
v-model="form.commissioning_date"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.commissioning_date" />
|
|
</div>
|
|
|
|
<div>
|
|
<div class="flex justify-between items-center">
|
|
<InputLabel for="warranty_expiration_date" value="Fin de garantie" />
|
|
<button
|
|
type="button"
|
|
@click="setStandardWarranty"
|
|
class="text-xxs font-bold text-sky-600 hover:text-sky-500 dark:text-sky-450 underline"
|
|
>
|
|
+3 ans de garantie
|
|
</button>
|
|
</div>
|
|
<TextInput
|
|
id="warranty_expiration_date"
|
|
type="date"
|
|
class="mt-1 block w-full"
|
|
v-model="form.warranty_expiration_date"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.warranty_expiration_date" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Section : Technique & Traçabilité -->
|
|
<div>
|
|
<h3 class="text-sm font-bold text-sky-600 dark:text-sky-400 uppercase tracking-wider border-b border-slate-100 dark:border-slate-850 pb-2 mb-4">
|
|
Localisation & Réseau
|
|
</h3>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div>
|
|
<InputLabel for="location" value="Emplacement physique" />
|
|
<TextInput
|
|
id="location"
|
|
type="text"
|
|
class="mt-1 block w-full"
|
|
v-model="form.location"
|
|
required
|
|
placeholder="ex: Baie A, Salle Serveur 1"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.location" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="ip_address" value="Adresse IP de gestion" />
|
|
<TextInput
|
|
id="ip_address"
|
|
type="text"
|
|
class="mt-1 block w-full font-mono"
|
|
v-model="form.ip_address"
|
|
placeholder="ex: 192.168.10.25"
|
|
/>
|
|
<InputError class="mt-2" :message="form.errors.ip_address" />
|
|
</div>
|
|
|
|
<div>
|
|
<InputLabel for="order_id" value="Commande d'achat d'origine" />
|
|
<select
|
|
id="order_id"
|
|
v-model="form.order_id"
|
|
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm"
|
|
>
|
|
<option value="">Aucune commande liée</option>
|
|
<option v-for="order in orders" :key="order.id" :value="order.id">
|
|
{{ order.number }} - {{ order.label }}
|
|
</option>
|
|
</select>
|
|
<InputError class="mt-2" :message="form.errors.order_id" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes libres -->
|
|
<div>
|
|
<InputLabel for="notes" value="Notes libres & Historique des interventions" />
|
|
<textarea
|
|
id="notes"
|
|
v-model="form.notes"
|
|
rows="4"
|
|
placeholder="Historique des pannes, changements de pièces, interventions..."
|
|
class="mt-1 block w-full border-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 focus:border-indigo-500 dark:focus:border-indigo-600 focus:ring-indigo-500 dark:focus:ring-indigo-600 rounded-md shadow-sm"
|
|
></textarea>
|
|
<InputError class="mt-2" :message="form.errors.notes" />
|
|
</div>
|
|
|
|
<!-- Boutons d'action -->
|
|
<div class="flex items-center justify-end gap-3 pt-4 border-t border-slate-100 dark:border-slate-850">
|
|
<PrimaryButton :disabled="form.processing">
|
|
{{ isEdit ? 'Enregistrer les modifications' : 'Enregistrer le matériel' }}
|
|
</PrimaryButton>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AuthenticatedLayout>
|
|
</template>
|