Files
Inventory/frontend/app/pages/doc.vue
Matthieu 53d4d5768b refactor(doc) : utilise palier comme exemple plus parlant que pompe
Remplace l'exemple "pompe avec position sur la machine" par un palier
de tete vs palier de pied : exemple plus concret et plus universellement
compris pour illustrer la difference entre champs catalogue et champs
contextuels (custom field values).
2026-05-06 16:40:37 +02:00

1003 lines
60 KiB
Vue

<template>
<main class="min-h-screen bg-gradient-to-br from-base-200/50 via-base-100 to-base-200/30">
<div class="container mx-auto max-w-7xl px-4 py-10">
<!-- Mobile TOC toggle -->
<div class="lg:hidden mb-6">
<button
class="btn btn-outline btn-sm gap-2 w-full justify-between"
@click="mobileMenuOpen = !mobileMenuOpen"
>
<span class="flex items-center gap-2">
<IconLucideBookOpen class="w-4 h-4" />
Sommaire
</span>
<IconLucideChevronDown
class="w-4 h-4 transition-transform duration-300"
:class="{ 'rotate-180': mobileMenuOpen }"
/>
</button>
<Transition name="slide">
<nav
v-show="mobileMenuOpen"
class="mt-2 card bg-base-100 border border-base-300 shadow-lg"
>
<ul class="menu menu-sm p-3">
<li v-for="section in sections" :key="section.id">
<a
:href="`#${section.id}`"
class="flex items-center gap-2 rounded-lg"
:class="activeSection === section.id
? 'bg-primary text-primary-content font-semibold'
: 'text-base-content/70 hover:bg-base-200'"
@click.prevent="scrollTo(section.id)"
>
<component :is="section.icon" class="w-4 h-4 shrink-0" />
{{ section.label }}
</a>
</li>
</ul>
</nav>
</Transition>
</div>
<div class="flex gap-10">
<!-- Sidebar desktop -->
<aside class="hidden lg:block w-60 shrink-0">
<nav class="sticky top-20 max-h-[calc(100vh-6rem)] overflow-y-auto">
<p class="text-[10px] font-bold uppercase tracking-[0.2em] text-base-content/30 mb-4 px-3">
Guide
</p>
<ul class="space-y-0.5">
<li v-for="section in sections" :key="section.id">
<a
:href="`#${section.id}`"
class="flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm transition-all duration-200"
:class="activeSection === section.id
? 'bg-primary text-primary-content font-semibold shadow-sm'
: 'text-base-content/60 hover:text-base-content hover:bg-base-200/60'"
@click.prevent="scrollTo(section.id)"
>
<component :is="section.icon" class="w-4 h-4 shrink-0" />
{{ section.label }}
</a>
</li>
</ul>
</nav>
</aside>
<!-- Contenu principal -->
<div class="flex-1 min-w-0 space-y-20">
<!-- En-tete -->
<header>
<div class="flex items-center gap-4 mb-3">
<div class="w-14 h-14 rounded-2xl bg-primary/10 flex items-center justify-center">
<IconLucideBookOpen class="w-7 h-7 text-primary" />
</div>
<div>
<h1 class="text-3xl font-extrabold text-base-content tracking-tight">Guide d'utilisation</h1>
<p class="text-base-content/40 text-sm mt-1">Tout ce qu'il faut savoir pour utiliser Inventory</p>
</div>
</div>
</header>
<!-- ==================== 1. COMMENT C'EST ORGANISE ==================== -->
<section id="organisation" :ref="el => setSectionRef('organisation', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideNetwork" color="primary">
Comment c'est organise ?
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
L'application range vos equipements comme des poupees russes : chaque niveau contient le suivant.
Voici les 5 niveaux, du plus grand au plus petit :
</p>
<!-- Arbre visuel simplifie -->
<div class="card bg-base-100 border border-base-300 shadow-sm mb-8 overflow-hidden">
<div class="card-body p-6">
<div class="space-y-0">
<!-- Site -->
<div class="flex items-center gap-4">
<div class="w-11 h-11 rounded-xl bg-primary/15 flex items-center justify-center shrink-0">
<IconLucideFactory class="w-5 h-5 text-primary" />
</div>
<div>
<span class="font-bold text-base-content">Le site</span>
<span class="text-base-content/50"> &mdash; votre usine, votre atelier, votre entrepot</span>
</div>
</div>
<div class="ml-5 border-l-2 border-primary/20 h-4"></div>
<!-- Machine -->
<div class="flex items-center gap-4 ml-8">
<div class="w-11 h-11 rounded-xl bg-secondary/15 flex items-center justify-center shrink-0">
<IconLucideCog class="w-5 h-5 text-secondary" />
</div>
<div>
<span class="font-bold text-base-content">La machine</span>
<span class="text-base-content/50"> &mdash; la presse, le tour, la ligne de production</span>
</div>
</div>
<div class="ml-13 border-l-2 border-secondary/20 h-4"></div>
<!-- Composant -->
<div class="flex items-center gap-4 ml-16">
<div class="w-11 h-11 rounded-xl bg-accent/15 flex items-center justify-center shrink-0">
<IconLucideBoxes class="w-5 h-5 text-accent" />
</div>
<div>
<span class="font-bold text-base-content">Le composant</span>
<span class="text-base-content/50"> &mdash; le moteur, la pompe, le tableau electrique</span>
</div>
</div>
<div class="ml-21 border-l-2 border-accent/20 h-4"></div>
<!-- Piece & Produit -->
<div class="ml-24 grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="flex items-center gap-3">
<div class="w-11 h-11 rounded-xl bg-warning/15 flex items-center justify-center shrink-0">
<IconLucideWrench class="w-5 h-5 text-warning" />
</div>
<div>
<span class="font-bold text-base-content">La piece</span>
<p class="text-xs text-base-content/50">Joint, roulement, courroie...</p>
</div>
</div>
<div class="flex items-center gap-3">
<div class="w-11 h-11 rounded-xl bg-success/15 flex items-center justify-center shrink-0">
<IconLucideDroplets class="w-5 h-5 text-success" />
</div>
<div>
<span class="font-bold text-base-content">Le produit</span>
<p class="text-xs text-base-content/50">Huile, graisse, liquide...</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Piece vs Produit -->
<h3 class="font-bold text-base-content mb-4 text-lg">Quelle difference entre une piece et un produit ?</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
<div class="card bg-warning/5 border border-warning/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideWrench class="w-5 h-5 text-warning" />
<h4 class="font-bold text-base-content">Une piece</h4>
</div>
<p class="text-sm text-base-content/70">
C'est quelque chose qu'on <strong>monte</strong> physiquement sur la machine
et qu'on <strong>remplace</strong> quand c'est use. Un joint, un roulement, un capteur.
</p>
</div>
</div>
<div class="card bg-success/5 border border-success/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideDroplets class="w-5 h-5 text-success" />
<h4 class="font-bold text-base-content">Un produit</h4>
</div>
<p class="text-sm text-base-content/70">
C'est quelque chose qu'on <strong>consomme</strong> et qu'on
<strong>rachete regulierement</strong>. De l'huile, de la graisse, un degraissant.
</p>
</div>
</div>
</div>
<div class="alert shadow-sm mb-4">
<IconLucideInfo class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Bon a savoir :</strong> un composant peut contenir d'autres composants a l'interieur.
Par exemple, un moteur peut contenir un reducteur, qui lui-meme contient des roulements.
C'est comme des boites dans des boites.
</p>
</div>
</section>
<!-- ==================== 2. CREER UNE MACHINE ==================== -->
<section id="machines" :ref="el => setSectionRef('machines', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideCog" color="secondary">
Creer une machine
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
Pour ajouter une nouvelle machine dans l'application, suivez ces etapes :
</p>
<div class="space-y-4 mb-8">
<StepCard n="1" title="Choisissez le site">
Dans quel batiment ou atelier se trouve la machine ?
Selectionnez-le dans la liste.
</StepCard>
<StepCard n="2" title="Remplissez la fiche">
Donnez un nom a la machine, sa reference, son prix si vous le connaissez,
et le(s) fournisseur(s) qui l'ont fournie.
</StepCard>
<StepCard n="3" title="Ajoutez les composants">
Quels sont les gros elements de cette machine ? Un moteur, une pompe, un variateur ?
Ajoutez-les un par un. (Voir la section suivante.)
</StepCard>
<StepCard n="4" title="Ajoutez les pieces et produits">
Certaines pieces ou produits sont lies directement a la machine
(pas a un composant en particulier). Ajoutez-les ici.
</StepCard>
<StepCard n="5" title="Completez avec documents et infos supplementaires">
Joignez des photos, plans, factures, et remplissez les informations supplementaires
propres a cette machine (voir section Champs personnalises).
</StepCard>
</div>
<div class="alert shadow-sm mb-2">
<IconLucideCopy class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Astuce :</strong> si vous avez plusieurs machines identiques,
utilisez le bouton <strong>"Cloner"</strong> pour dupliquer une machine existante
avec tout son contenu. Il ne reste plus qu'a ajuster les details.
</p>
</div>
</section>
<!-- ==================== 3. LES COMPOSANTS ==================== -->
<section id="composants" :ref="el => setSectionRef('composants', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideBoxes" color="accent">
Les composants d'une machine
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
Un composant, c'est un <strong>gros morceau</strong> de votre machine : le moteur,
la pompe, le tableau electrique, le verin... Chaque composant a besoin de pieces
et de produits pour fonctionner.
</p>
<!-- Explication emplacements -->
<h3 class="font-bold text-base-content mb-4 text-lg">Le systeme d'emplacements</h3>
<p class="text-base-content/70 mb-4 text-sm leading-relaxed">
Quand vous ajoutez un composant a une machine, l'application cree automatiquement
des <strong>emplacements vides</strong> a remplir. C'est comme un formulaire pre-fait :
il vous indique tout ce qu'il faut pour que le composant soit complet.
</p>
<div class="card bg-base-100 border border-base-300 shadow-sm mb-6">
<div class="card-body p-5">
<p class="text-xs font-bold uppercase tracking-wider text-base-content/30 mb-4">Exemple : vous ajoutez une pompe hydraulique</p>
<div class="space-y-3">
<div class="flex items-center gap-3 bg-warning/5 rounded-lg px-4 py-3 border border-warning/10">
<IconLucideWrench class="w-5 h-5 text-warning shrink-0" />
<div>
<p class="font-semibold text-sm">Emplacement piece : "Joint principal"</p>
<p class="text-xs text-base-content/50">A remplir avec le joint que vous utilisez vraiment</p>
</div>
</div>
<div class="flex items-center gap-3 bg-warning/5 rounded-lg px-4 py-3 border border-warning/10">
<IconLucideWrench class="w-5 h-5 text-warning shrink-0" />
<div>
<p class="font-semibold text-sm">Emplacement piece : "Roulement"</p>
<p class="text-xs text-base-content/50">A remplir avec le roulement en place</p>
</div>
</div>
<div class="flex items-center gap-3 bg-success/5 rounded-lg px-4 py-3 border border-success/10">
<IconLucideDroplets class="w-5 h-5 text-success shrink-0" />
<div>
<p class="font-semibold text-sm">Emplacement produit : "Huile hydraulique"</p>
<p class="text-xs text-base-content/50">A remplir avec l'huile utilisee</p>
</div>
</div>
<div class="flex items-center gap-3 bg-accent/5 rounded-lg px-4 py-3 border border-accent/10">
<IconLucideBoxes class="w-5 h-5 text-accent shrink-0" />
<div>
<p class="font-semibold text-sm">Emplacement composant : "Moteur electrique"</p>
<p class="text-xs text-base-content/50">Un composant dans un composant (comme des poupees russes)</p>
</div>
</div>
</div>
</div>
</div>
<div class="alert shadow-sm mb-2">
<IconLucideInfo class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Pas de panique :</strong> un emplacement peut rester vide. Vous n'etes pas oblige
de tout remplir d'un coup. Completez au fur et a mesure, a votre rythme.
</p>
</div>
</section>
<!-- ==================== 4. PIECES ET PRODUITS ==================== -->
<section id="pieces-produits" :ref="el => setSectionRef('pieces-produits', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideWrench" color="warning">
Pieces et produits
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
Les pieces et les produits sont les elements les plus "petits" de l'application.
Ils peuvent etre rattaches a un composant (via un emplacement) ou directement a une machine.
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 mb-8">
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-5">
<h4 class="font-bold text-base-content flex items-center gap-2 mb-3">
<span class="badge badge-warning">Piece</span>
Creer une piece
</h4>
<p class="text-sm text-base-content/70">
Donnez-lui un nom, une reference, choisissez son modele type
(voir section suivante), indiquez la quantite et le fournisseur.
</p>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-5">
<h4 class="font-bold text-base-content flex items-center gap-2 mb-3">
<span class="badge badge-success">Produit</span>
Creer un produit
</h4>
<p class="text-sm text-base-content/70">
Meme chose : un nom, une reference, un modele type, et le fournisseur.
Les produits n'ont pas de quantite (c'est du consommable).
</p>
</div>
</div>
</div>
<div class="alert shadow-sm mb-2">
<IconLucideDroplets class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Bon a savoir :</strong> une piece peut elle-meme avoir besoin de produits.
Par exemple, un roulement a besoin de graisse. L'application gere ca automatiquement
si c'est prevu dans le modele type de la piece.
</p>
</div>
</section>
<!-- ==================== 5. MODELES TYPES ==================== -->
<section id="modeles-types" :ref="el => setSectionRef('modeles-types', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideLayoutTemplate" color="primary">
Les modeles types
</SectionTitle>
<!-- Analogie simple -->
<div class="card bg-primary/5 border border-primary/20 mb-8">
<div class="card-body p-6">
<h3 class="font-bold text-base-content text-lg mb-3 flex items-center gap-2">
<IconLucideLightbulb class="w-5 h-5 text-primary" />
C'est quoi ?
</h3>
<p class="text-base-content/70 leading-relaxed mb-4">
Imaginez un <strong>bon de commande type</strong> : il liste tout ce qu'il faut pour un
equipement donne. Un modele type, c'est exactement pareil. Vous le creez une seule fois,
et ensuite chaque fois que vous ajoutez un equipement de ce type, la liste est deja pre-remplie.
</p>
<p class="text-base-content/70 leading-relaxed">
<strong>Exemple :</strong> vous creez un modele type "Pompe hydraulique" qui dit :
"il faut 2 joints, 1 roulement, et de l'huile hydraulique". A chaque nouvelle pompe,
ces emplacements sont crees automatiquement. Plus besoin de tout refaire a la main.
</p>
</div>
</div>
<!-- 3 familles -->
<h3 class="font-bold text-base-content mb-4 text-lg">Il existe 3 familles de modeles</h3>
<p class="text-base-content/70 mb-4 text-sm">
Un modele type s'applique a une seule famille d'element :
</p>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<div class="card bg-accent/5 border border-accent/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideBoxes class="w-5 h-5 text-accent" />
<span class="font-bold text-base-content">Pour les composants</span>
</div>
<p class="text-sm text-base-content/60">
Peut prevoir des emplacements pour des pieces, des produits,
et meme d'autres composants a l'interieur.
</p>
</div>
</div>
<div class="card bg-warning/5 border border-warning/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideWrench class="w-5 h-5 text-warning" />
<span class="font-bold text-base-content">Pour les pieces</span>
</div>
<p class="text-sm text-base-content/60">
Peut prevoir des emplacements pour des produits.
Par exemple : un roulement qui a besoin de graisse.
</p>
</div>
</div>
<div class="card bg-success/5 border border-success/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideDroplets class="w-5 h-5 text-success" />
<span class="font-bold text-base-content">Pour les produits</span>
</div>
<p class="text-sm text-base-content/60">
Pas d'emplacements prevus. Un produit est un consommable simple,
il ne contient rien d'autre.
</p>
</div>
</div>
</div>
<!-- Reference automatique -->
<h3 class="font-bold text-base-content mb-4 text-lg">
<IconLucideHash class="w-5 h-5 inline text-base-content/50 mr-1" />
Reference automatique
</h3>
<p class="text-base-content/70 mb-4 text-sm leading-relaxed">
Pour les modeles de composants et de pieces, vous pouvez definir une
<strong>formule de reference</strong> qui genere automatiquement un code unique
pour chaque element, a partir de ses informations.
</p>
<div class="card bg-base-200/50 border border-base-300 shadow-sm mb-8">
<div class="card-body p-5">
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-4">
<div>
<p class="text-xs text-base-content/40 mb-1">Formule :</p>
<code class="bg-base-300/50 px-3 py-1.5 rounded-lg text-sm font-mono text-primary">
{site}-{type}-{numero}
</code>
</div>
<IconLucideArrowRight class="w-5 h-5 text-base-content/20 shrink-0 hidden sm:block" />
<div>
<p class="text-xs text-base-content/40 mb-1">Resultat :</p>
<code class="bg-primary/10 px-3 py-1.5 rounded-lg text-sm font-mono text-primary font-bold">
LYON-POMPE-001
</code>
</div>
</div>
<p class="text-xs text-base-content/40 mt-3">
La reference se met a jour automatiquement quand les informations changent.
</p>
</div>
</div>
<!-- Synchronisation -->
<h3 class="font-bold text-base-content mb-4 text-lg">
<IconLucideRefreshCw class="w-5 h-5 inline text-base-content/50 mr-1" />
Mettre a jour les elements existants
</h3>
<p class="text-base-content/70 mb-4 text-sm leading-relaxed">
Vous avez modifie un modele type (par exemple, ajoute un emplacement "filtre"
a votre modele de pompe) et vous voulez que <strong>toutes les pompes deja creees</strong>
recoivent aussi ce nouvel emplacement ? C'est possible grace a la synchronisation :
</p>
<div class="card bg-base-100 border border-base-300 shadow-sm mb-4">
<div class="card-body p-5">
<ul class="steps steps-horizontal w-full text-xs sm:text-sm">
<li class="step step-primary">Modifier le modele</li>
<li class="step step-primary">Voir l'apercu</li>
<li class="step step-primary">Confirmer</li>
<li class="step step-primary">C'est fait !</li>
</ul>
</div>
</div>
<div class="alert shadow-sm mb-2">
<IconLucideLightbulb class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Astuce :</strong> cette fonction est surtout utile au debut, quand vous etes
en train de configurer l'application et que les modeles evoluent souvent.
Un apercu est toujours affiche avant d'appliquer les changements.
</p>
</div>
</section>
<!-- ==================== 6. FOURNISSEURS ==================== -->
<section id="fournisseurs" :ref="el => setSectionRef('fournisseurs', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideTruck" color="primary">
Fournisseurs
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
Vous pouvez enregistrer vos fournisseurs dans l'application et les associer a
n'importe quel element : machine, composant, piece ou produit.
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-5 mb-6">
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-5">
<h4 class="font-bold text-base-content flex items-center gap-2 mb-2">
<IconLucidePlus class="w-4 h-4 text-primary" />
Creer un fournisseur
</h4>
<p class="text-sm text-base-content/70">
Allez dans Administration > Fournisseurs et ajoutez le nom
et les coordonnees de votre fournisseur.
</p>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-5">
<h4 class="font-bold text-base-content flex items-center gap-2 mb-2">
<IconLucideLink class="w-4 h-4 text-primary" />
Associer a un element
</h4>
<p class="text-sm text-base-content/70">
Sur la fiche de n'importe quel element, vous pouvez ajouter un ou
plusieurs fournisseurs avec leur reference propre.
</p>
</div>
</div>
</div>
<div class="alert shadow-sm mb-2">
<IconLucideInfo class="w-5 h-5 shrink-0 text-info" />
<p class="text-sm">
<strong>Reference fournisseur :</strong> chaque fournisseur peut avoir sa propre reference
pour le meme produit. Par exemple, un roulement SKF peut avoir la reference "6205-2Z"
chez un fournisseur et "SKF-6205-ZZ" chez un autre.
</p>
</div>
</section>
<!-- ==================== 7. DOCUMENTS ==================== -->
<section id="documents" :ref="el => setSectionRef('documents', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideFileText" color="primary">
Documents
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
Vous pouvez joindre des fichiers (PDF, images, etc.) a n'importe quel element de
l'application. Chaque document a un type pour faciliter le tri :
</p>
<div class="flex flex-wrap gap-2 mb-8">
<span class="badge badge-lg gap-2 py-3">
<IconLucideBook class="w-4 h-4" />
Documentation
</span>
<span class="badge badge-lg gap-2 py-3">
<IconLucideFileSpreadsheet class="w-4 h-4" />
Devis
</span>
<span class="badge badge-lg gap-2 py-3">
<IconLucideReceipt class="w-4 h-4" />
Facture
</span>
<span class="badge badge-lg gap-2 py-3">
<IconLucideRuler class="w-4 h-4" />
Plan
</span>
<span class="badge badge-lg gap-2 py-3">
<IconLucideCamera class="w-4 h-4" />
Photo
</span>
<span class="badge badge-lg gap-2 py-3">
<IconLucideFile class="w-4 h-4" />
Autre
</span>
</div>
<p class="text-sm text-base-content/60">
Les documents sont consultables et telechargeables directement depuis la fiche
de l'element auquel ils sont rattaches.
</p>
</section>
<!-- ==================== 8. CHAMPS PERSONNALISES ==================== -->
<section id="champs-personnalises" :ref="el => setSectionRef('champs-personnalises', el)" class="scroll-mt-24">
<SectionTitle icon="IconLucideSettings" color="primary">
Informations supplementaires (champs personnalises)
</SectionTitle>
<p class="text-base-content/70 mb-6 leading-relaxed">
En plus des informations de base (nom, reference, fournisseur...),
vous pouvez ajouter des <strong>informations supplementaires</strong> sur mesure
pour chaque element. Par exemple : un numero de serie, une date de garantie,
une puissance en kW, etc.
</p>
<!-- Chaque element a ses champs -->
<h3 class="font-bold text-base-content mb-4 text-lg">Qui peut avoir des informations supplementaires ?</h3>
<p class="text-base-content/70 mb-4 text-sm">
Tout le monde ! Mais la facon de les definir est differente :
</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
<div class="card bg-secondary/5 border border-secondary/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideCog class="w-5 h-5 text-secondary" />
<span class="font-bold text-base-content">Sur une machine</span>
</div>
<p class="text-sm text-base-content/70 mb-3">
Vous ajoutez les champs <strong>directement sur la machine</strong>,
un par un. Chaque machine peut avoir ses propres champs.
</p>
<div class="bg-base-200/50 rounded-lg p-3 text-xs space-y-1 text-base-content/60">
<p class="font-semibold text-base-content/40">Exemples :</p>
<p>Date de mise en service</p>
<p>Numero d'inventaire</p>
<p>Cout d'acquisition</p>
</div>
</div>
</div>
<div class="card bg-accent/5 border border-accent/20">
<div class="card-body p-5">
<div class="flex items-center gap-2 mb-3">
<IconLucideBoxes class="w-5 h-5 text-accent" />
<span class="font-bold text-base-content">Sur composant, piece, produit</span>
</div>
<p class="text-sm text-base-content/70 mb-3">
Les champs sont definis <strong>dans le modele type</strong>.
Tous les elements du meme modele partagent les memes champs.
</p>
<div class="bg-base-200/50 rounded-lg p-3 text-xs space-y-1 text-base-content/60">
<p class="font-semibold text-base-content/40">Exemple pour "Pompe hydraulique" :</p>
<p>Debit max (nombre)</p>
<p>Type de fluide (liste de choix)</p>
<p>Certifie ATEX (oui/non)</p>
</div>
</div>
</div>
</div>
<!-- Types de champs -->
<h3 class="font-bold text-base-content mb-4 text-lg">Les types d'informations possibles</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 mb-8">
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<div class="flex items-center gap-2 mb-2">
<IconLucideType class="w-4 h-4 text-primary" />
<span class="font-bold text-sm">Texte</span>
</div>
<p class="text-xs text-base-content/60">Saisie libre au clavier</p>
<div class="mt-2 bg-base-200/50 rounded px-2 py-1.5 text-xs text-base-content/40 italic">
Acier inoxydable 316L
</div>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<div class="flex items-center gap-2 mb-2">
<IconLucideHash class="w-4 h-4 text-primary" />
<span class="font-bold text-sm">Nombre</span>
</div>
<p class="text-xs text-base-content/60">Uniquement des chiffres</p>
<div class="mt-2 bg-base-200/50 rounded px-2 py-1.5 text-xs text-base-content/40 italic">
1500 tours/min
</div>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<div class="flex items-center gap-2 mb-2">
<IconLucideList class="w-4 h-4 text-primary" />
<span class="font-bold text-sm">Liste de choix</span>
</div>
<p class="text-xs text-base-content/60">Choisir parmi des options</p>
<div class="mt-2 bg-base-200/50 rounded px-2 py-1.5 text-xs text-base-content/40 italic">
Gauche / Droite / Centre
</div>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<div class="flex items-center gap-2 mb-2">
<IconLucideToggleLeft class="w-4 h-4 text-primary" />
<span class="font-bold text-sm">Oui / Non</span>
</div>
<p class="text-xs text-base-content/60">Juste cocher ou decocher</p>
<div class="mt-2 bg-base-200/50 rounded px-2 py-1.5 text-xs text-base-content/40 italic">
ATEX certifie : Oui
</div>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<div class="flex items-center gap-2 mb-2">
<IconLucideCalendar class="w-4 h-4 text-primary" />
<span class="font-bold text-sm">Date</span>
</div>
<p class="text-xs text-base-content/60">Choisir une date dans le calendrier</p>
<div class="mt-2 bg-base-200/50 rounded px-2 py-1.5 text-xs text-base-content/40 italic">
15/03/2026
</div>
</div>
</div>
</div>
<!-- Champs contextuels -->
<h3 class="font-bold text-base-content mb-4 text-lg">
<IconLucideAlertTriangle class="w-5 h-5 inline text-warning mr-1" />
Champs visibles uniquement dans une machine
</h3>
<div class="card bg-warning/5 border border-warning/20 mb-6">
<div class="card-body p-6">
<p class="text-base-content/70 leading-relaxed mb-4">
Quand vous creez un champ dans un modele type (pour un composant, une piece ou un produit),
vous pouvez choisir : <strong>est-ce que ce champ doit apparaitre partout,
ou seulement quand on regarde l'element depuis une machine ?</strong>
</p>
<p class="text-base-content/70 leading-relaxed mb-4">
<strong>Pourquoi ?</strong> Certaines informations n'ont de sens que quand
l'element est monte sur une machine. Prenons l'exemple d'un palier : sur une
machine, vous en avez souvent deux, un en haut (le palier de tete) et un en
bas (le palier de pied). Dans le catalogue, le palier n'est monte nulle part,
donc savoir s'il est "en haut" ou "en bas" ne veut rien dire. Mais des qu'on
regarde ce palier depuis la fiche d'une machine, on veut savoir lequel des
deux c'est.
</p>
</div>
</div>
<p class="text-sm font-semibold text-base-content mb-3">Voici la difference :</p>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
<div class="card bg-base-100 border-2 border-base-300">
<div class="card-body p-5">
<p class="font-bold text-sm text-base-content mb-1">Dans le catalogue</p>
<p class="text-xs text-base-content/40 mb-4">Quand on consulte l'element tout seul</p>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-base-content/70">Diametre interieur</span>
<span>50 mm</span>
</div>
<div class="flex justify-between">
<span class="text-base-content/70">Type</span>
<span>Roulement a billes</span>
</div>
<div class="border-t border-dashed border-base-300 pt-2 mt-2">
<div class="flex justify-between opacity-30">
<span class="line-through">Emplacement</span>
<span class="text-xs italic">pas affiche ici</span>
</div>
</div>
</div>
</div>
</div>
<div class="card bg-base-100 border-2 border-primary/30">
<div class="card-body p-5">
<p class="font-bold text-sm text-base-content mb-1">Depuis une machine</p>
<p class="text-xs text-base-content/40 mb-4">Quand on regarde l'element dans sa machine</p>
<div class="space-y-2 text-sm">
<div class="flex justify-between">
<span class="text-base-content/70">Diametre interieur</span>
<span>50 mm</span>
</div>
<div class="flex justify-between">
<span class="text-base-content/70">Type</span>
<span>Roulement a billes</span>
</div>
<div class="border-t border-primary/20 pt-2 mt-2">
<div class="flex justify-between bg-primary/10 rounded px-2 py-1.5">
<span class="text-base-content font-medium">Emplacement</span>
<span class="font-bold">Haut (palier de tete)</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Options -->
<h3 class="font-bold text-base-content mb-4 text-lg">Options des champs</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<h4 class="font-bold text-sm flex items-center gap-2">
<IconLucideAsterisk class="w-4 h-4 text-error" />
Obligatoire
</h4>
<p class="text-xs text-base-content/60 mt-1">
L'element ne peut pas etre sauvegarde tant que ce champ n'est pas rempli.
</p>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<h4 class="font-bold text-sm flex items-center gap-2">
<IconLucideClipboardCheck class="w-4 h-4 text-base-content/50" />
Valeur par defaut
</h4>
<p class="text-xs text-base-content/60 mt-1">
Le champ est pre-rempli automatiquement a la creation. Vous pouvez le modifier apres.
</p>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<h4 class="font-bold text-sm flex items-center gap-2">
<IconLucideList class="w-4 h-4 text-base-content/50" />
Options de la liste
</h4>
<p class="text-xs text-base-content/60 mt-1">
Pour les champs "liste de choix", vous definissez les options possibles.
</p>
</div>
</div>
<div class="card bg-base-100 border border-base-300 shadow-sm">
<div class="card-body p-4">
<h4 class="font-bold text-sm flex items-center gap-2">
<IconLucideArrowUpDown class="w-4 h-4 text-base-content/50" />
Ordre d'affichage
</h4>
<p class="text-xs text-base-content/60 mt-1">
Vous choisissez dans quel ordre les champs apparaissent sur la fiche.
</p>
</div>
</div>
</div>
</section>
<!-- Footer spacer -->
<div class="h-32" />
</div>
</div>
</div>
</main>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, type Component as VueComponent, defineComponent, h } from 'vue'
import { useHead } from '#imports'
// Icons
import IconLucideBookOpen from '~icons/lucide/book-open'
import IconLucideNetwork from '~icons/lucide/network'
import IconLucideFactory from '~icons/lucide/factory'
import IconLucideCog from '~icons/lucide/cog'
import IconLucideBoxes from '~icons/lucide/boxes'
import IconLucideWrench from '~icons/lucide/wrench'
import IconLucideDroplets from '~icons/lucide/droplets'
import IconLucideCheck from '~icons/lucide/check'
import IconLucideInfo from '~icons/lucide/info'
import IconLucideCopy from '~icons/lucide/copy'
import IconLucideLayoutTemplate from '~icons/lucide/layout-template'
import IconLucideLightbulb from '~icons/lucide/lightbulb'
import IconLucideHash from '~icons/lucide/hash'
import IconLucideArrowRight from '~icons/lucide/arrow-right'
import IconLucideRefreshCw from '~icons/lucide/refresh-cw'
import IconLucideTruck from '~icons/lucide/truck'
import IconLucidePlus from '~icons/lucide/plus'
import IconLucideLink from '~icons/lucide/link'
import IconLucideFileText from '~icons/lucide/file-text'
import IconLucideBook from '~icons/lucide/book'
import IconLucideFileSpreadsheet from '~icons/lucide/file-spreadsheet'
import IconLucideReceipt from '~icons/lucide/receipt'
import IconLucideRuler from '~icons/lucide/ruler'
import IconLucideCamera from '~icons/lucide/camera'
import IconLucideFile from '~icons/lucide/file'
import IconLucideSettings from '~icons/lucide/settings'
import IconLucideType from '~icons/lucide/type'
import IconLucideToggleLeft from '~icons/lucide/toggle-left'
import IconLucideCalendar from '~icons/lucide/calendar'
import IconLucideAlertTriangle from '~icons/lucide/alert-triangle'
import IconLucideClipboardCheck from '~icons/lucide/clipboard-check'
import IconLucideAsterisk from '~icons/lucide/asterisk'
import IconLucideArrowUpDown from '~icons/lucide/arrow-up-down'
import IconLucideList from '~icons/lucide/list'
import IconLucideChevronDown from '~icons/lucide/chevron-down'
useHead({ title: 'Documentation' })
// ─── Inline sub-components ───
const iconMap: Record<string, VueComponent> = {
IconLucideNetwork,
IconLucideCog,
IconLucideBoxes,
IconLucideWrench,
IconLucideLayoutTemplate,
IconLucideTruck,
IconLucideFileText,
IconLucideSettings,
}
const SectionTitle = defineComponent({
props: {
icon: { type: String, required: true },
color: { type: String, default: 'primary' },
},
setup(props, { slots }) {
return () => h('div', { class: 'flex items-center gap-3 mb-6' }, [
h(iconMap[props.icon] ?? 'span', { class: `w-6 h-6 text-${props.color}` }),
h('h2', { class: 'text-2xl font-bold text-base-content tracking-tight' }, slots.default?.()),
])
},
})
const StepCard = defineComponent({
props: {
n: { type: String, required: true },
title: { type: String, required: true },
},
setup(props, { slots }) {
return () => h('div', { class: 'flex gap-4 items-start' }, [
h('div', {
class: 'w-9 h-9 rounded-full bg-primary/10 text-primary font-bold text-sm flex items-center justify-center shrink-0 mt-0.5',
}, props.n),
h('div', {}, [
h('p', { class: 'font-bold text-base-content' }, props.title),
h('p', { class: 'text-sm text-base-content/60 mt-0.5' }, slots.default?.()),
]),
])
},
})
// ─── Sections ───
interface Section {
id: string
label: string
icon: VueComponent
}
const sections: Section[] = [
{ id: 'organisation', label: 'Organisation', icon: IconLucideNetwork },
{ id: 'machines', label: 'Machines', icon: IconLucideCog },
{ id: 'composants', label: 'Composants', icon: IconLucideBoxes },
{ id: 'pieces-produits', label: 'Pieces & Produits', icon: IconLucideWrench },
{ id: 'modeles-types', label: 'Modeles types', icon: IconLucideLayoutTemplate },
{ id: 'fournisseurs', label: 'Fournisseurs', icon: IconLucideTruck },
{ id: 'documents', label: 'Documents', icon: IconLucideFileText },
{ id: 'champs-personnalises', label: 'Champs perso', icon: IconLucideSettings },
]
const activeSection = ref('organisation')
const mobileMenuOpen = ref(false)
const sectionRefs = new Map<string, Element>()
function setSectionRef(id: string, el: unknown) {
if (el instanceof Element) {
sectionRefs.set(id, el)
}
}
function scrollTo(id: string) {
const el = document.getElementById(id)
if (el) {
el.scrollIntoView({ behavior: 'smooth' })
mobileMenuOpen.value = false
}
}
let observer: IntersectionObserver | null = null
onMounted(() => {
observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (entry.isIntersecting) {
activeSection.value = entry.target.id
}
}
},
{
rootMargin: '-20% 0px -60% 0px',
threshold: 0,
},
)
for (const el of sectionRefs.values()) {
observer.observe(el)
}
})
onUnmounted(() => {
observer?.disconnect()
})
</script>
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: max-height 0.25s ease, opacity 0.25s ease;
overflow: hidden;
}
.slide-enter-from,
.slide-leave-to {
max-height: 0;
opacity: 0;
}
.slide-enter-to,
.slide-leave-from {
max-height: 30rem;
opacity: 1;
}
</style>