Files
siop2/docs/02-design/maquettes/maquette-mobile-tous-roles.html
pr-daaif ab0f260d0f feat(r6): mobile ouvert à tous les rôles — maquette + socle R6.1
R4 avait délibérément fermé le mobile au Technicien. Le référent demande
l'ouverture à tous les rôles avec les mêmes droits qu'au web — nouvelle
release R6 (R4 est close, R4.1/4.2/4.3 déjà pris par le socle mobile
technicien d'origine, pas de réouverture ni de collision de numérotation).

Maquette (docs/02-design/maquettes/maquette-mobile-tous-roles.html, 7
écrans) validée par le référent : D1 barre d'onglets adaptative par rôle
(Technicien/Technicien limité inchangés + onglet Menu ajouté) ; D2 le Menu
reprend à l'identique les 4 groupes du web, même matrice de permissions ;
D3 groupe sans lien visible masqué en entier ; D4 le mobile porte les
actions courantes par famille, pas les flux de gestion les plus denses ;
D5 aucune logique de permission propre au mobile.

R6.1 — socle : usePermissions() mobile calqué sur le web ; barre d'onglets
adaptative (ongletsVisibles par rôle, href:null masque sans retirer du
navigateur) ; Accueil (dashboard réel pour Administrateur/Gestionnaire/
Dispatcher/Vue seule, aucun chiffre inventé) ; OT (liste complète,
viewOther déjà géré serveur, réutilise la fiche OT R4 telle quelle) ; Menu
(groupes filtrés, vide masqué) ; Demandes (PanneauDemandes — un seul
composant pour tous les rôles : création/suivi Demandeur, approbation/
rejet Gestionnaire/Dispatcher/Administrateur, lecture Vue seule).
Familles pas encore portées : écran « à venir » plutôt qu'un lien mort.

Typecheck propre, 17 tests Jest, lint 5/5 paquets.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 11:19:44 +01:00

765 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SIOP V2 — Maquettes HD · Mobile ouvert à tous les rôles</title>
</head>
<body>
<!--
SIOP V2 — Maquette HD « Mobile ouvert à tous les rôles » (design-first).
À VALIDER PAR LE RÉFÉRENT AVANT TOUT CODE EXPO (principe n°1).
R4 avait délibérément fermé le mobile au Technicien (périmètre R4 D3). Ici :
ouvrir l'app à TOUS les rôles, avec les MÊMES droits qu'au web (aucune
nouvelle logique de permission — le mobile lit la même matrice, ADR-003).
Tokens et gabarit téléphone repris tels quels de maquette-r4.html.
Les 4 écrans terrain déjà livrés et recettés (Ma journée, Scanner, Préventif,
Synchro) restent INCHANGÉS pour le Technicien — cette maquette ajoute une
couche autour, elle ne les remplace pas.
Décisions proposées à validation (récapitulées aussi dans le journal) :
D1 — Barre d'onglets ADAPTATIVE selon le rôle connecté (pas un seul jeu
d'onglets pour tout le monde) ; Technicien/Technicien limité gardent
exactement leurs onglets terrain actuels + un nouvel onglet « Menu ».
D2 — Le Menu mobile reprend EXACTEMENT les 4 groupes du web (Exploitation /
Parc / Ressources / Pilotage), dans le même ordre, filtrés par la même
matrice de permissions déjà en base — aucune règle de droit nouvelle.
D3 — Contrairement au web (le groupe reste affiché même vide), un groupe
SANS AUCUN lien visible est masqué en entier sur mobile — l'écran est
petit, un intitulé de groupe vide n'aide personne.
D4 — Le mobile porte les actions COURANTES de chaque famille (consulter,
créer une pièce/BC simple, approuver/rejeter, inviter) mais pas les
flux de gestion les plus denses (BC multi-lignes détaillé, revue pixel
de document) qui restent réservés au grand écran pour l'instant.
D5 — Le mobile n'acquiert AUCUNE logique de permission propre : un hook
`usePermissions()` calqué sur celui du web, lisant `me.permissions`
(déjà renvoyé par `/users/me`, déjà mis en cache par l'app).
-->
<style>
/* ═══ Tokens (répliques de ../tokens.css) ═══ */
:root{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--st-annule:#68788f;--st-annule-fond:#edf0f4;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;--prio-haute:#d92626;
--prio-moyenne:#b96f07;--prio-basse:#178a50;--prio-aucune:#8494ab;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--graf-1:#3b69d6;--graf-2:#dd8a0b;--graf-3:#1f9e8e;--graf-4:#8a63d2;--graf-grille:#e6ebf2;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--police-ui:"Manrope","Avenir Next","Segoe UI Variable",system-ui,sans-serif;
--rayon:10px;--rayon-controle:8px;--ombre-menu:0 8px 24px rgb(16 30 54/.14);
--transition:140ms ease-out;
}
@media (prefers-color-scheme:dark){:root{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--st-annule:#93a3ba;--st-annule-fond:#222d3f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;--prio-haute:#f26d6d;
--prio-moyenne:#e0a33c;--prio-basse:#4bc084;--prio-aucune:#6d7d96;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--graf-1:#5580e4;--graf-2:#c7820a;--graf-3:#26a896;--graf-4:#9673de;--graf-grille:#24304a;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}}
:root[data-theme="light"]{
--primaire:#1f4fb8;--primaire-actif:#1a439c;--primaire-doux:#eaf0fb;
--safran:#dd8a0b;--safran-doux:#fdf3e3;
--fond:#f5f7fa;--surface:#ffffff;--surface-2:#eef2f7;
--bordure:#dce3ec;--bordure-forte:#b9c4d4;
--encre:#1b2534;--encre-2:#55647a;--encre-3:#8494ab;
--st-ouvert:#3d6fe0;--st-ouvert-fond:#e9effc;--st-encours:#6d5bd8;--st-encours-fond:#efecfa;
--st-attente:#b96f07;--st-attente-fond:#fbf1df;--st-termine:#178a50;--st-termine-fond:#e6f5ec;
--st-annule:#68788f;--st-annule-fond:#edf0f4;
--prio-bloque:#d92626;--prio-bloque-fond:#fdeaea;--prio-haute:#d92626;
--prio-moyenne:#b96f07;--prio-basse:#178a50;--prio-aucune:#8494ab;
--succes:#178a50;--alerte:#b96f07;--danger:#d92626;--info:#3d6fe0;
--graf-1:#3b69d6;--graf-2:#dd8a0b;--graf-3:#1f9e8e;--graf-4:#8a63d2;--graf-grille:#e6ebf2;
--nav-fond:#16233b;--nav-encre:#c6d2e4;--nav-encre-vif:#ffffff;--nav-bordure:#24344f;
--ombre-menu:0 8px 24px rgb(16 30 54/.14);
}
:root[data-theme="dark"]{
--primaire:#6e92e8;--primaire-actif:#8facf0;--primaire-doux:#1d2c4c;
--safran:#e89a1f;--safran-doux:#33270f;
--fond:#0f1622;--surface:#182234;--surface-2:#1e2a40;
--bordure:#2b3850;--bordure-forte:#3d4d6b;
--encre:#e8edf5;--encre-2:#a7b4c8;--encre-3:#6d7d96;
--st-ouvert:#7da2ee;--st-ouvert-fond:#1c2a47;--st-encours:#a394ec;--st-encours-fond:#262040;
--st-attente:#e0a33c;--st-attente-fond:#322510;--st-termine:#4bc084;--st-termine-fond:#12301f;
--st-annule:#93a3ba;--st-annule-fond:#222d3f;
--prio-bloque:#f26d6d;--prio-bloque-fond:#3a1414;--prio-haute:#f26d6d;
--prio-moyenne:#e0a33c;--prio-basse:#4bc084;--prio-aucune:#6d7d96;
--succes:#4bc084;--alerte:#e0a33c;--danger:#f26d6d;--info:#7da2ee;
--graf-1:#5580e4;--graf-2:#c7820a;--graf-3:#26a896;--graf-4:#9673de;--graf-grille:#24304a;
--nav-fond:#0c1524;--nav-encre:#a7b4c8;--nav-encre-vif:#f2f6fc;--nav-bordure:#1e2c44;
--ombre-menu:0 8px 24px rgb(0 0 0/.45);
}
/* ═══ Base ═══ */
*{box-sizing:border-box;margin:0}
html,body{background:var(--fond)}
body{font-family:var(--police-ui);color:var(--encre);font-size:14px;line-height:1.5}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
button:focus-visible,a:focus-visible{outline:2px solid var(--primaire);outline-offset:2px;border-radius:4px}
.num{font-variant-numeric:tabular-nums}
/* ═══ Barre de revue (outil maquette, pas l'app) ═══ */
.revue{position:sticky;top:0;z-index:50;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
padding:10px 16px;background:var(--nav-fond);color:var(--nav-encre);font-size:13px}
.revue b{color:var(--nav-encre-vif);letter-spacing:.02em}
.revue .onglets{display:flex;gap:4px;flex-wrap:wrap}
.revue .onglets button{padding:6px 10px;border-radius:6px;color:var(--nav-encre)}
.revue .onglets button:hover{background:rgb(255 255 255/.08);color:var(--nav-encre-vif)}
.revue .onglets button[aria-selected="true"]{background:rgb(255 255 255/.12);color:var(--nav-encre-vif);
box-shadow:inset 3px 0 0 var(--safran)}
.revue .droite{margin-left:auto;display:flex;align-items:center;gap:8px}
.revue .theme{padding:6px 10px;border:1px solid var(--nav-bordure);border-radius:6px}
.note-ecran{max-width:1120px;margin:14px auto 0;padding:0 20px;color:var(--encre-2);font-size:13px}
.note-ecran b{color:var(--encre)}
/* ═══ Écrans ═══ */
.ecran{display:none;max-width:1120px;margin:18px auto 44px;padding:0 20px}
.ecran.actif{display:block}
.tels{display:flex;gap:28px;justify-content:center;flex-wrap:wrap}
.tel{width:310px;border:1px solid var(--bordure-forte);border-radius:28px;overflow:hidden;background:var(--fond);
box-shadow:var(--ombre-menu);display:flex;flex-direction:column}
.tel .encoche{height:26px;background:var(--nav-fond);display:flex;justify-content:center;align-items:center;flex:none}
.tel .encoche i{width:70px;height:7px;border-radius:999px;background:rgb(255 255 255/.18)}
.tel .legende{flex:none;text-align:center;font-size:11.5px;font-weight:700;letter-spacing:.05em;
text-transform:uppercase;color:var(--encre-3);padding:8px;background:var(--surface-2)}
.ecran-tel{padding:14px;display:flex;flex-direction:column;gap:10px;min-height:560px}
/* Entête app */
.entete-tel{display:flex;align-items:center;gap:8px}
.entete-tel .flamme{color:var(--safran);font-size:16px}
.entete-tel b{font-size:16px;letter-spacing:.03em}
.entete-tel small{color:var(--encre-3);font-size:10.5px;margin-top:3px}
.entete-tel .fin{margin-left:auto;display:flex;align-items:center;gap:6px}
.avatar-tel{width:26px;height:26px;border-radius:50%;background:var(--st-encours);color:#fff;
display:flex;align-items:center;justify-content:center;font-size:10.5px;font-weight:700}
.sync{font-size:10.5px;font-weight:700;color:var(--st-termine);background:var(--st-termine-fond);
padding:2px 8px;border-radius:999px;white-space:nowrap}
.sync.off{color:var(--st-attente);background:var(--st-attente-fond)}
.titre-tel{font-size:17px;font-weight:800;display:flex;align-items:center;gap:8px}
.titre-tel .filet{margin-left:auto;font-size:11px;color:var(--encre-3);font-weight:600}
/* Bandeaux */
.bandeau-off{display:flex;align-items:center;gap:8px;background:var(--st-attente-fond);color:var(--st-attente);
border:1px solid currentColor;border-radius:10px;padding:8px 10px;font-size:12px;font-weight:700}
.bandeau-urgence{display:flex;align-items:center;gap:8px;background:var(--prio-bloque-fond);color:var(--prio-bloque);
border-radius:10px;padding:8px 10px;font-size:12px;font-weight:800}
.point-pulse{width:8px;height:8px;border-radius:50%;background:currentColor;flex:none}
/* Cartes OT */
.carte-ot-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:11px 12px;
border-left:4px solid transparent}
.carte-ot-tel.bloque{border-left-color:var(--prio-bloque)}
.carte-ot-tel.haute{border-left-color:var(--prio-haute)}
.carte-ot-tel.moyenne{border-left-color:var(--prio-moyenne)}
.carte-ot-tel.basse{border-left-color:var(--prio-basse)}
.carte-ot-tel .type-t{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--encre-2);
font-weight:700;display:flex;justify-content:space-between;align-items:center;gap:6px}
.carte-ot-tel b{display:block;margin:3px 0 2px;font-size:14px}
.carte-ot-tel .ou{color:var(--encre-2);font-size:12px}
.st{font-size:10.5px;font-weight:700;padding:2px 8px;border-radius:999px;white-space:nowrap}
.st.ouvert{color:var(--st-ouvert);background:var(--st-ouvert-fond)}
.st.encours{color:var(--st-encours);background:var(--st-encours-fond)}
.st.attente{color:var(--st-attente);background:var(--st-attente-fond)}
.st.termine{color:var(--st-termine);background:var(--st-termine-fond)}
.st.annule{color:var(--st-annule);background:var(--st-annule-fond)}
.pastille-file{font-size:10.5px;font-weight:700;color:var(--st-attente);background:var(--st-attente-fond);
padding:2px 8px;border-radius:999px}
/* Boutons */
.btn-tel{display:flex;justify-content:center;align-items:center;gap:8px;padding:12px;border-radius:10px;
font-weight:700;font-size:14.5px;background:var(--primaire);color:#fff;width:100%}
.btn-tel.vert{background:var(--succes)}
.btn-tel.rouge{background:var(--danger)}
.btn-tel.gris{background:var(--bordure-forte);color:var(--surface)}
.btn-tel.contour{background:var(--surface);color:var(--primaire);border:1.5px solid var(--primaire)}
.paire-boutons{display:flex;gap:8px}
.paire-boutons .btn-tel{padding:10px;font-size:13px}
/* Fiche : cartes d'info */
.carte-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:12px;padding:12px;
display:flex;flex-direction:column;gap:8px}
.carte-tel h4{font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;color:var(--encre-2)}
.ligne-info{display:flex;justify-content:space-between;gap:10px;font-size:12.5px}
.ligne-info span:first-child{color:var(--encre-2)}
.ligne-info b{text-align:right}
.garde{font-size:11.5px;color:var(--alerte);font-weight:600}
/* Tabbar */
.tabbar{margin-top:auto;display:flex;border-top:1px solid var(--bordure);background:var(--surface);
padding:6px 4px 8px}
.tabbar a{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;font-size:9.5px;
font-weight:700;color:var(--encre-3);text-decoration:none;position:relative}
.tabbar a.actif{color:var(--primaire)}
.tabbar a .pic{font-size:17px;line-height:1.2}
.tabbar .badge-tab{position:absolute;top:-3px;right:calc(50% - 16px);background:var(--st-attente);
color:#fff;font-size:9px;font-weight:800;padding:0 5px;border-radius:999px}
.tabbar .badge-tab.rouge{background:var(--prio-bloque)}
/* ═══ Nouveautés propres à cette maquette ═══ */
/* KPI mini-cartes (Accueil / Statistiques) */
.kpis-tel{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.kpi-tel{background:var(--surface);border:1px solid var(--bordure);border-radius:10px;padding:9px 10px}
.kpi-tel .val{font-size:19px;font-weight:800;color:var(--encre)}
.kpi-tel .lbl{font-size:10.5px;color:var(--encre-2);font-weight:600}
.kpi-tel.accent .val{color:var(--primaire)}
/* Raccourcis (Accueil) */
.raccourci-tel{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--bordure);
border-radius:10px;padding:10px 11px}
.raccourci-tel .ico{width:28px;height:28px;border-radius:8px;background:var(--primaire-doux);color:var(--primaire);
display:flex;align-items:center;justify-content:center;font-size:14px;flex:none}
.raccourci-tel .txt{flex:1;display:flex;flex-direction:column}
.raccourci-tel b{font-size:12.5px}
.raccourci-tel small{color:var(--encre-2);font-size:11px}
.raccourci-tel .chev{color:var(--encre-3)}
.raccourci-tel .num{font-size:10.5px;font-weight:800;color:var(--st-attente);background:var(--st-attente-fond);
padding:2px 7px;border-radius:999px}
/* Menu groupé (mirroir de la nav web) */
.menu-groupe{display:flex;flex-direction:column;gap:6px}
.menu-groupe .titre-groupe{font-size:10.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
color:var(--encre-3);padding:4px 2px 0}
.menu-item{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--bordure);
border-radius:10px;padding:10px 11px}
.menu-item .ico{width:24px;text-align:center;font-size:14px;color:var(--primaire);flex:none}
.menu-item b{flex:1;font-size:12.5px;font-weight:700}
.menu-item .chev{color:var(--encre-3);font-size:13px}
.menu-item .num{font-size:10.5px;font-weight:800;color:var(--st-attente);background:var(--st-attente-fond);
padding:2px 7px;border-radius:999px}
.menu-vide{color:var(--encre-3);font-size:12px;text-align:center;padding:20px 8px;font-weight:600}
/* Formulaire mobile */
.champ-tel{display:flex;flex-direction:column;gap:4px}
.champ-tel label{font-size:11px;font-weight:700;color:var(--encre-2)}
.champ-tel .valeur-champ{border:1.5px solid var(--bordure-forte);border-radius:9px;background:var(--surface);
padding:9px 10px;font-size:13px;font-weight:600;color:var(--encre)}
.champ-tel textarea.valeur-champ{min-height:56px}
/* Tableau de synthèse (hors gabarit téléphone) */
.table-roles{width:100%;border-collapse:collapse;background:var(--surface);border:1px solid var(--bordure);
border-radius:12px;overflow:hidden;font-size:12.5px}
.table-roles th,.table-roles td{padding:10px 12px;text-align:left;border-bottom:1px solid var(--bordure)}
.table-roles thead th{background:var(--surface-2);font-size:10.5px;letter-spacing:.05em;text-transform:uppercase;
color:var(--encre-2)}
.table-roles tbody tr:last-child td{border-bottom:0}
.table-roles td.role{font-weight:800}
.table-roles .oui{color:var(--st-termine);font-weight:800}
.table-roles .non{color:var(--encre-3)}
.chip-onglet{display:inline-block;background:var(--primaire-doux);color:var(--primaire);font-weight:700;
font-size:11px;padding:2px 8px;border-radius:999px;margin:2px 3px 2px 0}
.chip-onglet.terrain{background:var(--safran-doux);color:var(--safran)}
</style>
<header class="revue">
<b>SIOP · Maquette — Mobile ouvert à tous les rôles</b>
<nav class="onglets" role="tablist" aria-label="Écrans">
<button role="tab" aria-selected="true" data-cible="synthese">1 · Synthèse par rôle</button>
<button role="tab" aria-selected="false" data-cible="accueil">2 · Accueil adaptatif</button>
<button role="tab" aria-selected="false" data-cible="menu">3 · Menu groupé</button>
<button role="tab" aria-selected="false" data-cible="ot-dispatch">4 · OT — Dispatcher</button>
<button role="tab" aria-selected="false" data-cible="demandes">5 · Demandes</button>
<button role="tab" aria-selected="false" data-cible="stock">6 · Stock & achats</button>
<button role="tab" aria-selected="false" data-cible="pilotage">7 · Personnes & statistiques</button>
</nav>
<div class="droite"><button class="theme" id="btn-theme">Thème : auto</button></div>
</header>
<!-- ═══ 1 · SYNTHÈSE PAR RÔLE ═══ -->
<p class="note-ecran" data-note="synthese"><b>Intention :</b> avant le détail écran par écran,
le tableau ci-dessous résume la <b>décision D1/D2</b> pour les 7 rôles : quels onglets la barre
adaptative affiche, et quels groupes du Menu restent visibles (mêmes droits qu'au web, rien de
nouveau dans la matrice). Les 4 onglets terrain du Technicien (encadré safran) sont ceux déjà
livrés en R4 — inchangés.</p>
<section class="ecran actif" id="synthese">
<div style="overflow-x:auto">
<table class="table-roles">
<thead><tr><th>Rôle (compte démo)</th><th>Onglets de la barre</th><th>Groupes du Menu visibles</th></tr></thead>
<tbody>
<tr>
<td class="role">Administrateur<br><small style="font-weight:500;color:var(--encre-3)">Yasmine Alaoui</small></td>
<td><span class="chip-onglet">Accueil</span><span class="chip-onglet">OT</span><span class="chip-onglet">Menu</span></td>
<td>Exploitation · Parc · Ressources · Pilotage <span style="color:var(--encre-3)">(tout)</span></td>
</tr>
<tr>
<td class="role">Gestionnaire<br><small style="font-weight:500;color:var(--encre-3)">Nadia Berrada</small></td>
<td><span class="chip-onglet">Accueil</span><span class="chip-onglet">OT</span><span class="chip-onglet">Menu</span></td>
<td>Exploitation · Parc · Ressources · Pilotage <span style="color:var(--encre-3)">(stats en lecture)</span></td>
</tr>
<tr>
<td class="role">Dispatcher<br><small style="font-weight:500;color:var(--encre-3)">Salma Idrissi</small></td>
<td><span class="chip-onglet">Accueil</span><span class="chip-onglet">OT</span><span class="chip-onglet">Menu</span></td>
<td>Exploitation · Parc (lecture) <span style="color:var(--encre-3)">— Ressources/Pilotage restreints</span></td>
</tr>
<tr style="box-shadow:inset 3px 0 0 var(--safran)">
<td class="role">Technicien<br><small style="font-weight:500;color:var(--encre-3)">Ahmed Benali</small></td>
<td><span class="chip-onglet terrain">Ma journée</span><span class="chip-onglet terrain">Scanner</span><span class="chip-onglet terrain">Préventif</span><span class="chip-onglet terrain">Synchro</span><span class="chip-onglet">Menu</span></td>
<td>Menu quasi vide (ses OT + parc en lecture) — <b>inchangé depuis R4</b></td>
</tr>
<tr style="box-shadow:inset 3px 0 0 var(--safran)">
<td class="role">Technicien limité<br><small style="font-weight:500;color:var(--encre-3)">Youssef Tazi</small></td>
<td><span class="chip-onglet terrain">Ma journée</span><span class="chip-onglet terrain">Scanner</span><span class="chip-onglet terrain">Préventif</span><span class="chip-onglet terrain">Synchro</span><span class="chip-onglet">Menu</span></td>
<td>Menu quasi vide (ses OT uniquement) — <b>inchangé depuis R4</b></td>
</tr>
<tr>
<td class="role">Demandeur<br><small style="font-weight:500;color:var(--encre-3)">Karim Doukkali</small></td>
<td><span class="chip-onglet">Accueil</span><span class="chip-onglet">Nouvelle demande</span></td>
<td>Exploitation → Demandes uniquement <span style="color:var(--encre-3)">(Menu quasi vide, D3)</span></td>
</tr>
<tr>
<td class="role">Vue seule<br><small style="font-weight:500;color:var(--encre-3)">Rachid Bennis</small></td>
<td><span class="chip-onglet">Accueil</span><span class="chip-onglet">Menu</span></td>
<td>Exploitation · Parc · Ressources · Pilotage <span style="color:var(--encre-3)">(lecture seule, aucun bouton d'action)</span></td>
</tr>
</tbody>
</table>
</div>
</section>
<!-- ═══ 2 · ACCUEIL ADAPTATIF ═══ -->
<p class="note-ecran" data-note="accueil" hidden><b>Intention :</b> le Technicien garde « Ma
journée » telle quelle (rien à revalider). Les autres rôles reçoivent un <b>Accueil</b> propre à
leur travail : le Gestionnaire voit ses signaux de pilotage et des raccourcis vers ce qui demande
une action ; le Demandeur voit directement ses demandes et le geste qu'il fait le plus (en
créer une nouvelle) — jamais un écran vide générique.</p>
<section class="ecran" id="accueil">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Technicien — inchangé (R4)</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Technicien</small>
<span class="fin"><span class="sync">Synchro à jour</span><span class="avatar-tel">AB</span></span>
</div>
<div class="titre-tel">Ma journée <span class="filet">jeudi 1 août</span></div>
<div class="bandeau-urgence"><span class="point-pulse"></span>1 personne bloquée — B2 · Tour Atlas</div>
<div class="carte-ot-tel bloque">
<div class="type-t">OT-2026-0342 · Dépannage <span class="st ouvert">Ouvert</span></div>
<b>Personne bloquée en cabine</b>
<div class="ou">Asc. B2 — Tour Atlas · Aïn Diab</div>
</div>
<div class="carte-ot-tel haute">
<div class="type-t">OT-2026-0341 · Dépannage <span class="st encours">En cours</span></div>
<b>Bruit anormal en gaine</b>
<div class="ou">Asc. A1 — Résidence Al Manar</div>
</div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Ma journée</a>
<a href="#"><span class="pic"></span>Scanner</a>
<a href="#"><span class="pic"></span>Préventif</a>
<a href="#"><span class="pic"></span>Synchro</a>
<a href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Gestionnaire — nouveau</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Gestionnaire</small>
<span class="fin"><span class="sync">Synchro à jour</span><span class="avatar-tel">NB</span></span>
</div>
<div class="titre-tel">Accueil <span class="filet">jeudi 1 août</span></div>
<div class="kpis-tel">
<div class="kpi-tel accent"><div class="val">6</div><div class="lbl">OT en cours</div></div>
<div class="kpi-tel"><div class="val">3</div><div class="lbl">Stock sous seuil</div></div>
<div class="kpi-tel"><div class="val">78 %</div><div class="lbl">Préventif du mois</div></div>
<div class="kpi-tel"><div class="val">2</div><div class="lbl">Demandes reçues</div></div>
</div>
<div class="raccourci-tel"><span class="ico"></span>
<span class="txt"><b>Stock sous seuil</b><small>3 pièces à commander</small></span>
<span class="num">3</span><span class="chev"></span></div>
<div class="raccourci-tel"><span class="ico"></span>
<span class="txt"><b>Demandes reçues</b><small>en attente d'approbation</small></span>
<span class="num">2</span><span class="chev"></span></div>
<div class="raccourci-tel"><span class="ico"></span>
<span class="txt"><b>Invitations en attente</b><small>lien envoyé, pas encore activé</small></span>
<span class="chev"></span></div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic"></span>OT</a>
<a href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Demandeur — nouveau</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Demandeur</small>
<span class="fin"><span class="sync">Synchro à jour</span><span class="avatar-tel">KD</span></span>
</div>
<div class="titre-tel">Mes demandes</div>
<div class="carte-ot-tel">
<div class="type-t">DEM-2026-0089 <span class="st attente">Reçue</span></div>
<b>Éclairage cabine défaillant</b>
<div class="ou">Asc. A2 — Résidence Al Manar</div>
</div>
<div class="carte-ot-tel">
<div class="type-t">DEM-2026-0081 <span class="st termine">Traitée</span></div>
<b>Bruit au démarrage</b>
<div class="ou">Asc. A2 — Résidence Al Manar → OT-2026-0336</div>
</div>
<div style="margin-top:auto">
<button class="btn-tel">+ Nouvelle demande</button>
</div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic">+</span>Nouvelle demande</a>
</nav>
</div>
</div>
</div>
</section>
<!-- ═══ 3 · MENU GROUPÉ ═══ -->
<p class="note-ecran" data-note="menu" hidden><b>Intention :</b> le Menu reprend, à l'identique,
les 4 groupes et l'ordre du sidebar web — <b>Exploitation / Parc / Ressources / Pilotage</b> — et
les mêmes permissions (`can(catégorie, 'view')`). Un rôle qui n'a droit à rien dans un groupe ne
voit pas le groupe du tout (D3) : comparez Administrateur (tout) et Demandeur (presque rien) sur
le MÊME écran, sans aucune règle de plus dans le code.</p>
<section class="ecran" id="menu">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Administrateur — tout visible</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Administrateur</small>
<span class="fin"><span class="avatar-tel">YA</span></span>
</div>
<div class="titre-tel">Menu</div>
<div class="menu-groupe">
<div class="titre-groupe">Exploitation</div>
<div class="menu-item"><span class="ico"></span><b>Tableau de bord</b><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Ordres de travail</b><span class="num">1</span><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Demandes</b><span class="num">2</span><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Préventif</b><span class="chev"></span></div>
</div>
<div class="menu-groupe">
<div class="titre-groupe">Parc</div>
<div class="menu-item"><span class="ico"></span><b>Ascenseurs</b><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Sites</b><span class="chev"></span></div>
</div>
<div class="menu-groupe">
<div class="titre-groupe">Ressources</div>
<div class="menu-item"><span class="ico"></span><b>Stock & achats</b><span class="num">3</span><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Tiers</b><span class="chev"></span></div>
</div>
<div class="menu-groupe">
<div class="titre-groupe">Pilotage</div>
<div class="menu-item"><span class="ico"></span><b>Statistiques</b><span class="chev"></span></div>
<div class="menu-item"><span class="ico"></span><b>Personnes & équipes</b><span class="chev"></span></div>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic"></span>OT</a>
<a class="actif" href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Demandeur — presque vide (D3)</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Demandeur</small>
<span class="fin"><span class="avatar-tel">KD</span></span>
</div>
<div class="titre-tel">Menu</div>
<div class="menu-groupe">
<div class="titre-groupe">Exploitation</div>
<div class="menu-item"><span class="ico"></span><b>Mes demandes</b><span class="chev"></span></div>
</div>
<div class="menu-vide">Parc, Ressources et Pilotage ne sont pas accessibles à ce rôle —<br>groupes masqués, pas de section vide affichée.</div>
<nav class="tabbar">
<a class="actif" href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic">+</span>Nouvelle demande</a>
</nav>
</div>
</div>
</div>
</section>
<!-- ═══ 4 · OT — DISPATCHER ═══ -->
<p class="note-ecran" data-note="ot-dispatch" hidden><b>Intention :</b> contrairement au
Technicien (qui ne voit que SES OT), le Dispatcher a `viewOther` — il voit tous les OT et peut en
créer/assigner. Le mobile porte cette différence : liste complète, bouton « + » et une action
rapide « Assigner » par carte (bottom-sheet, même pattern que le sélecteur de bilan codé de R4).</p>
<section class="ecran" id="ot-dispatch">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Dispatcher — tous les OT</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Dispatcher</small>
<span class="fin"><span class="sync">Synchro à jour</span><span class="avatar-tel">SI</span></span>
</div>
<div class="titre-tel">Ordres de travail <span class="filet">14 en cours</span></div>
<div class="carte-ot-tel bloque">
<div class="type-t">OT-2026-0342 · Dépannage <span class="st ouvert">Ouvert</span></div>
<b>Personne bloquée en cabine</b>
<div class="ou">Asc. B2 — Tour Atlas · non assigné</div>
</div>
<div class="carte-ot-tel haute">
<div class="type-t">OT-2026-0341 · Dépannage <span class="st encours">En cours</span></div>
<b>Bruit anormal en gaine</b>
<div class="ou">Asc. A1 — Résidence Al Manar · Ahmed Benali</div>
</div>
<div class="carte-ot-tel moyenne">
<div class="type-t">OT-2026-0336 · Préventif <span class="st ouvert">Ouvert</span></div>
<b>Contrôle mensuel — juillet</b>
<div class="ou">Asc. A2 — Résidence Al Manar · non assigné</div>
</div>
<div style="margin-top:auto">
<button class="btn-tel">+ Nouvel OT</button>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a class="actif" href="#"><span class="pic"></span>OT</a>
<a href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Assigner — feuille au pouce</div>
<div class="ecran-tel" style="justify-content:flex-end;padding:0">
<div style="flex:1;background:rgb(9 14 22/.45)"></div>
<div style="background:var(--surface);border-radius:16px 16px 0 0;padding:14px;display:flex;flex-direction:column;gap:10px">
<div style="font-weight:800;font-size:15px">Assigner OT-2026-0342</div>
<div class="champ-tel">
<label>Technicien</label>
<div class="valeur-champ">Ahmed Benali ▾</div>
</div>
<button class="btn-tel">Assigner</button>
<button class="btn-tel contour">Annuler</button>
</div>
</div>
</div>
</div>
</section>
<!-- ═══ 5 · DEMANDES ═══ -->
<p class="note-ecran" data-note="demandes" hidden><b>Intention :</b> le Demandeur crée sa demande
en mobilité (site, ascenseur si connu, description, urgence) exactement comme au web mais sur un
formulaire au pouce ; le Gestionnaire/Dispatcher approuve ou rejette (motif obligatoire au rejet,
comme au web) directement depuis la carte.</p>
<section class="ecran" id="demandes">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Demandeur — nouvelle demande</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Demandeur</small>
<span class="fin"><span class="avatar-tel">KD</span></span>
</div>
<div class="titre-tel">Nouvelle demande</div>
<div class="champ-tel"><label>Site</label><div class="valeur-champ">Résidence Al Manar ▾</div></div>
<div class="champ-tel"><label>Ascenseur (si connu)</label><div class="valeur-champ">Asc. A2 ▾</div></div>
<div class="champ-tel"><label>Description</label>
<div class="valeur-champ" style="min-height:56px">Odeur de brûlé au démarrage, depuis ce matin.</div>
</div>
<div class="champ-tel"><label>Urgence</label><div class="valeur-champ">Personne bloquée — Non</div></div>
<div style="margin-top:auto">
<button class="btn-tel">Envoyer la demande</button>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a class="actif" href="#"><span class="pic">+</span>Nouvelle demande</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Gestionnaire — approbation</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Gestionnaire</small>
<span class="fin"><span class="avatar-tel">NB</span></span>
</div>
<div class="titre-tel">Demandes reçues <span class="filet">2</span></div>
<div class="carte-ot-tel">
<div class="type-t">DEM-2026-0089 <span class="st attente">Reçue</span></div>
<b>Éclairage cabine défaillant</b>
<div class="ou">Asc. A2 — Résidence Al Manar · Karim Doukkali</div>
<div class="paire-boutons" style="margin-top:8px">
<button class="btn-tel vert">Approuver</button>
<button class="btn-tel rouge">Rejeter</button>
</div>
</div>
<div class="carte-ot-tel">
<div class="type-t">DEM-2026-0090 <span class="st attente">Reçue</span></div>
<b>Porte palière qui force</b>
<div class="ou">Asc. C1 — Anfa Place · Karim Doukkali</div>
<div class="paire-boutons" style="margin-top:8px">
<button class="btn-tel vert">Approuver</button>
<button class="btn-tel rouge">Rejeter</button>
</div>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a class="actif" href="#"><span class="pic"></span>OT</a>
<a href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
</div>
</section>
<!-- ═══ 6 · STOCK & ACHATS ═══ -->
<p class="note-ecran" data-note="stock" hidden><b>Intention :</b> le Gestionnaire consulte le
stock en mobilité et déclenche l'action courante — commander une pièce sous seuil — sans passer
par le grand écran. La fiche pièce reprend les lignes déjà connues (quantité, seuil, dernier
prix, fournisseur). Le bon de commande détaillé multi-lignes reste au web (D4).</p>
<section class="ecran" id="stock">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Gestionnaire — stock</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Gestionnaire</small>
<span class="fin"><span class="avatar-tel">NB</span></span>
</div>
<div class="titre-tel">Stock & achats <span class="filet">3 sous seuil</span></div>
<div class="carte-tel">
<h4>Câble de traction 8 mm</h4>
<div class="ligne-info"><span>Quantité</span><b style="color:var(--danger)">2</b></div>
<div class="ligne-info"><span>Seuil</span><b>5</b></div>
<div class="ligne-info"><span>Fournisseur</span><b>Ascentech Maroc</b></div>
<button class="btn-tel" style="margin-top:4px">Commander</button>
</div>
<div class="carte-tel">
<h4>Galet de guidage</h4>
<div class="ligne-info"><span>Quantité</span><b style="color:var(--danger)">1</b></div>
<div class="ligne-info"><span>Seuil</span><b>4</b></div>
<div class="ligne-info"><span>Fournisseur</span><b>SchindlerParts</b></div>
<button class="btn-tel" style="margin-top:4px">Commander</button>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic"></span>OT</a>
<a class="actif" href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">BC pré-rempli depuis l'alerte</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Gestionnaire</small>
<span class="fin"><span class="avatar-tel">NB</span></span>
</div>
<div class="titre-tel">Nouveau BC</div>
<div class="champ-tel"><label>Fournisseur</label><div class="valeur-champ">Ascentech Maroc</div></div>
<div class="champ-tel"><label>Pièce</label><div class="valeur-champ">Câble de traction 8 mm</div></div>
<div class="champ-tel"><label>Quantité</label><div class="valeur-champ">10</div></div>
<div class="garde">Le détail multi-lignes se termine sur le grand écran (D4).</div>
<div style="margin-top:auto">
<button class="btn-tel">Créer le BC</button>
</div>
</div>
</div>
</div>
</section>
<!-- ═══ 7 · PERSONNES & STATISTIQUES ═══ -->
<p class="note-ecran" data-note="pilotage" hidden><b>Intention :</b> deux écrans « Pilotage » côte
à côte — les Statistiques en lecture (mêmes chiffres que `/analytics/summary`, en cartes plutôt
qu'en graphes denses) et Personnes & équipes, avec l'action d'invitation déjà connue du web
(lien 7 jours) portée sur mobile.</p>
<section class="ecran" id="pilotage">
<div class="tels">
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Administrateur — statistiques</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Administrateur</small>
<span class="fin"><span class="avatar-tel">YA</span></span>
</div>
<div class="titre-tel">Statistiques <span class="filet">12 derniers mois</span></div>
<div class="kpis-tel">
<div class="kpi-tel accent"><div class="val">505 MAD</div><div class="lbl">Coût du mois</div></div>
<div class="kpi-tel"><div class="val">78 %</div><div class="lbl">Taux préventif</div></div>
</div>
<div class="carte-tel">
<h4>Pannes par organe — top 3</h4>
<div class="ligne-info"><span>Portes palières</span><b>9</b></div>
<div class="ligne-info"><span>Câblage</span><b>6</b></div>
<div class="ligne-info"><span>Éclairage cabine</span><b>4</b></div>
</div>
<nav class="tabbar">
<a href="#"><span class="pic"></span>Accueil</a>
<a href="#"><span class="pic"></span>OT</a>
<a class="actif" href="#"><span class="pic"></span>Menu</a>
</nav>
</div>
</div>
<div class="tel">
<div class="encoche"><i></i></div>
<div class="legende">Gestionnaire — personnes & équipes</div>
<div class="ecran-tel">
<div class="entete-tel">
<span class="flamme"></span><b>SIOP</b><small>Gestionnaire</small>
<span class="fin"><span class="avatar-tel">NB</span></span>
</div>
<div class="titre-tel">Personnes <span class="filet">12</span></div>
<div class="menu-item"><span class="ico"></span><b>Ahmed Benali</b><span style="color:var(--encre-3);font-size:11px">Technicien</span></div>
<div class="menu-item"><span class="ico"></span><b>Youssef Tazi</b><span style="color:var(--encre-3);font-size:11px">Technicien limité</span></div>
<div class="menu-item"><span class="ico"></span><b>Salma Idrissi</b><span style="color:var(--encre-3);font-size:11px">Dispatcher</span></div>
<div style="margin-top:auto">
<button class="btn-tel">+ Inviter</button>
</div>
</div>
</div>
</div>
</section>
<script>
(function(){
var onglets=document.querySelectorAll('.revue .onglets button');
var ecrans=document.querySelectorAll('.ecran');
var notes=document.querySelectorAll('.note-ecran');
onglets.forEach(function(b){b.addEventListener('click',function(){
onglets.forEach(function(x){x.setAttribute('aria-selected','false')});
b.setAttribute('aria-selected','true');
var cible=b.dataset.cible;
ecrans.forEach(function(e){e.classList.toggle('actif',e.id===cible)});
notes.forEach(function(n){n.hidden=(n.dataset.note!==cible)});
window.scrollTo({top:0});
})});
var ordre=['auto','light','dark'];var i=0;
var bt=document.getElementById('btn-theme');
bt.addEventListener('click',function(){
i=(i+1)%3;var m=ordre[i];
if(m==='auto'){document.documentElement.removeAttribute('data-theme')}
else{document.documentElement.setAttribute('data-theme',m)}
bt.textContent='Thème : '+(m==='auto'?'auto':(m==='light'?'clair':'sombre'));
});
})();
</script>
</body>
</html>